diff options
-rw-r--r-- | CHANGELOG.md | 4 | ||||
-rw-r--r-- | src/sys/socket/mod.rs | 16 | ||||
-rw-r--r-- | test/sys/test_socket.rs | 67 |
3 files changed, 82 insertions, 5 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index fa18a429..62953531 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<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)) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 9e8cefae..3ee02c3a 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<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; @@ -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 106428b9..13d7b6b0 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<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() { |