summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md4
-rw-r--r--src/sys/socket/mod.rs16
-rw-r--r--test/sys/test_socket.rs67
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() {