Skip to content

Commit

Permalink
Merge #1145
Browse files Browse the repository at this point in the history
1145: Fix sys::socket::recvfrom for TCP sockets r=asomers a=asomers

recvfrom(2) only returns the sender's address for protocols that provide
it.  Usually, that means it returns the sender's address for datagram
sockets but not for stream sockets.

Fixes #1144

Co-authored-by: Alan Somers <asomers@gmail.com>
  • Loading branch information
bors[bot] and asomers committed Oct 29, 2019
2 parents a2bbbae + e10e537 commit 2e52ce8
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -19,6 +19,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#1133](https://github.com/nix-rust/nix/pull/1133))

### Changed
- `sys::socket::recvfrom` now returns
`Result<(usize, Option<SockAddr>)>` instead of `Result<(usize, SockAddr)>`.
([#1145](https://github.com/nix-rust/nix/pull/1145))

- `Signal::from_c_int` has been replaced by `Signal::try_from`
([#1113](https://github.com/nix-rust/nix/pull/1113))

Expand Down
16 changes: 11 additions & 5 deletions src/sys/socket/mod.rs
Expand Up @@ -1075,10 +1075,13 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
}

/// Receive data from a connectionless or connection-oriented socket. Returns
/// the number of bytes read and the socket address of the sender.
/// the number of bytes read and, for connectionless sockets, the socket
/// address of the sender.
///
/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html)
pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
pub fn recvfrom(sockfd: RawFd, buf: &mut [u8])
-> Result<(usize, Option<SockAddr>)>
{
unsafe {
let mut addr: sockaddr_storage = mem::zeroed();
let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
Expand All @@ -1089,10 +1092,13 @@ pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
buf.len() as size_t,
0,
&mut addr as *mut libc::sockaddr_storage as *mut libc::sockaddr,
&mut len as *mut socklen_t))?;
&mut len as *mut socklen_t))? as usize;

sockaddr_storage_to_addr(&addr, len as usize)
.map(|addr| (ret as usize, addr))
match sockaddr_storage_to_addr(&addr, len as usize) {
Err(Error::Sys(Errno::ENOTCONN)) => Ok((ret, None)),
Ok(addr) => Ok((ret, Some(addr))),
Err(e) => Err(e)
}
}
}

Expand Down
67 changes: 67 additions & 0 deletions test/sys/test_socket.rs
Expand Up @@ -161,6 +161,73 @@ pub fn test_socketpair() {
assert_eq!(&buf[..], b"hello");
}

mod recvfrom {
use nix::Result;
use nix::sys::socket::*;
use std::thread;
use super::*;

const MSG: &'static [u8] = b"Hello, World!";

fn sendrecv<F>(rsock: RawFd, ssock: RawFd, f: F) -> Option<SockAddr>
where F: Fn(RawFd, &[u8], MsgFlags) -> Result<usize> + Send + 'static
{
let mut buf: [u8; 13] = [0u8; 13];
let mut l = 0;
let mut from = None;

let send_thread = thread::spawn(move || {
let mut l = 0;
while l < std::mem::size_of_val(MSG) {
l += f(ssock, &MSG[l..], MsgFlags::empty()).unwrap();
}
});

while l < std::mem::size_of_val(MSG) {
let (len, from_) = recvfrom(rsock, &mut buf[l..]).unwrap();
from = from_;
l += len;
}
assert_eq!(&buf, MSG);
send_thread.join().unwrap();
from
}

#[test]
pub fn stream() {
let (fd2, fd1) = socketpair(AddressFamily::Unix, SockType::Stream,
None, SockFlag::empty()).unwrap();
// Ignore from for stream sockets
let _ = sendrecv(fd1, fd2, |s, m, flags| {
send(s, m, flags)
});
}

#[test]
pub fn udp() {
let std_sa = SocketAddr::from_str("127.0.0.1:6789").unwrap();
let inet_addr = InetAddr::from_std(&std_sa);
let sock_addr = SockAddr::new_inet(inet_addr);
let rsock = socket(AddressFamily::Inet,
SockType::Datagram,
SockFlag::empty(),
None
).unwrap();
bind(rsock, &sock_addr).unwrap();
let ssock = socket(
AddressFamily::Inet,
SockType::Datagram,
SockFlag::empty(),
None,
).expect("send socket failed");
let from = sendrecv(rsock, ssock, move |s, m, flags| {
sendto(s, m, &sock_addr, flags)
});
// UDP sockets should set the from address
assert_eq!(AddressFamily::Inet, from.unwrap().family());
}
}

// Test error handling of our recvmsg wrapper
#[test]
pub fn test_recvmsg_ebadf() {
Expand Down

0 comments on commit 2e52ce8

Please sign in to comment.