From e10e5373e887c96a1549e22e3dd05f448c040d1d Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 27 Oct 2019 13:33:40 -0600 Subject: [PATCH] Fix sys::socket::recvfrom for TCP sockets 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 --- CHANGELOG.md | 4 +++ src/sys/socket/mod.rs | 16 +++++++--- test/sys/test_socket.rs | 67 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa18a42960..62953531b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)>` 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)) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 9e8cefaee5..3ee02c3ae5 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1075,10 +1075,13 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result { } /// 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)> +{ unsafe { let mut addr: sockaddr_storage = mem::zeroed(); let mut len = mem::size_of::() as socklen_t; @@ -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) + } } } diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 106428b9d0..13d7b6b098 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -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(rsock: RawFd, ssock: RawFd, f: F) -> Option + where F: Fn(RawFd, &[u8], MsgFlags) -> Result + 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() {