about summary refs log tree commit diff
diff options
context:
space:
mode:
authorReyk Floeter <contact@reykfloeter.com>2021-03-22 12:07:44 +0100
committerReyk Floeter <contact@reykfloeter.com>2021-03-26 21:12:22 +0100
commit3d6bd87b24a2fbccb6c1e81863874789eb046c17 (patch)
treece9973fad8cb080a769624d50e68186cb34c22cd
parentb8719c51e0e44483cff9b6975a830f6e51812a48 (diff)
downloadrust-3d6bd87b24a2fbccb6c1e81863874789eb046c17.tar.gz
rust-3d6bd87b24a2fbccb6c1e81863874789eb046c17.zip
unix: Fix feature(unix_socket_ancillary_data) on macos and other BSDs
This adds support for CMSG handling on macOS and fixes it on OpenBSD
and other BSDs.

When traversing the CMSG list, the previous code had an exception for
Android where the next element after the last pointer could point to
the first pointer instead of NULL.  This is actually not specific to
Android: the `libc::CMSG_NXTHDR` implementation for Linux and
emscripten have a special case to return NULL when the length of the
previous element is zero; most other implementations simply return the
previous element plus a zero offset in this case.

This MR additionally adds `SocketAncillary::is_empty` because clippy
is right that it should be added.
-rw-r--r--library/std/src/sys/unix/ext/net/ancillary.rs57
1 files changed, 34 insertions, 23 deletions
diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs
index 33d6a39af07..011ae643f87 100644
--- a/library/std/src/sys/unix/ext/net/ancillary.rs
+++ b/library/std/src/sys/unix/ext/net/ancillary.rs
@@ -5,9 +5,7 @@ use crate::marker::PhantomData;
 use crate::mem::{size_of, zeroed};
 use crate::os::unix::io::RawFd;
 use crate::path::Path;
-#[cfg(target_os = "android")]
-use crate::ptr::eq;
-use crate::ptr::read_unaligned;
+use crate::ptr::{eq, read_unaligned};
 use crate::slice::from_raw_parts;
 use crate::sys::net::Socket;
 
@@ -30,12 +28,10 @@ pub(super) fn recv_vectored_with_ancillary_from(
 ) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
     unsafe {
         let mut msg_name: libc::sockaddr_un = zeroed();
-
         let mut msg: libc::msghdr = zeroed();
         msg.msg_name = &mut msg_name as *mut _ as *mut _;
         msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
         msg.msg_iov = bufs.as_mut_ptr().cast();
-        msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
         cfg_if::cfg_if! {
             if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
                 msg.msg_iovlen = bufs.len() as libc::size_t;
@@ -45,6 +41,7 @@ pub(super) fn recv_vectored_with_ancillary_from(
                           target_os = "emscripten",
                           target_os = "freebsd",
                           all(target_os = "linux", target_env = "musl",),
+                          target_os = "macos",
                           target_os = "netbsd",
                           target_os = "openbsd",
                       ))] {
@@ -52,6 +49,10 @@ pub(super) fn recv_vectored_with_ancillary_from(
                 msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t;
             }
         }
+        // macos requires that the control pointer is NULL when the len is 0.
+        if msg.msg_controllen > 0 {
+            msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
+        }
 
         let count = socket.recv_msg(&mut msg)?;
 
@@ -79,7 +80,6 @@ pub(super) fn send_vectored_with_ancillary_to(
         msg.msg_name = &mut msg_name as *mut _ as *mut _;
         msg.msg_namelen = msg_namelen;
         msg.msg_iov = bufs.as_ptr() as *mut _;
-        msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
         cfg_if::cfg_if! {
             if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
                 msg.msg_iovlen = bufs.len() as libc::size_t;
@@ -89,6 +89,7 @@ pub(super) fn send_vectored_with_ancillary_to(
                           target_os = "emscripten",
                           target_os = "freebsd",
                           all(target_os = "linux", target_env = "musl",),
+                          target_os = "macos",
                           target_os = "netbsd",
                           target_os = "openbsd",
                       ))] {
@@ -96,6 +97,10 @@ pub(super) fn send_vectored_with_ancillary_to(
                 msg.msg_controllen = ancillary.length as libc::socklen_t;
             }
         }
+        // macos requires that the control pointer is NULL when the len is 0.
+        if msg.msg_controllen > 0 {
+            msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
+        }
 
         ancillary.truncated = false;
 
@@ -147,6 +152,7 @@ fn add_to_ancillary_data<T>(
                           target_os = "emscripten",
                           target_os = "freebsd",
                           all(target_os = "linux", target_env = "musl",),
+                          target_os = "macos",
                           target_os = "netbsd",
                           target_os = "openbsd",
                       ))] {
@@ -159,14 +165,12 @@ fn add_to_ancillary_data<T>(
         while !cmsg.is_null() {
             previous_cmsg = cmsg;
             cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
-            cfg_if::cfg_if! {
-                // Android return the same pointer if it is the last cmsg.
-                // Therefore, check it if the previous pointer is the same as the current one.
-                if #[cfg(target_os = "android")] {
-                    if cmsg == previous_cmsg {
-                        break;
-                    }
-                }
+
+            // Most operating systems, but not Linux or emscripten, return the previous pointer
+            // when its length is zero. Therefore, check if the previous pointer is the same as
+            // the current one.
+            if eq(cmsg, previous_cmsg) {
+                break;
             }
         }
 
@@ -184,6 +188,7 @@ fn add_to_ancillary_data<T>(
                           target_os = "emscripten",
                           target_os = "freebsd",
                           all(target_os = "linux", target_env = "musl",),
+                          target_os = "macos",
                           target_os = "netbsd",
                           target_os = "openbsd",
                       ))] {
@@ -371,6 +376,7 @@ impl<'a> AncillaryData<'a> {
                               target_os = "emscripten",
                               target_os = "freebsd",
                               all(target_os = "linux", target_env = "musl",),
+                              target_os = "macos",
                               target_os = "netbsd",
                               target_os = "openbsd",
                           ))] {
@@ -421,6 +427,7 @@ impl<'a> Iterator for Messages<'a> {
                               target_os = "emscripten",
                               target_os = "freebsd",
                               all(target_os = "linux", target_env = "musl",),
+                              target_os = "macos",
                               target_os = "netbsd",
                               target_os = "openbsd",
                           ))] {
@@ -435,15 +442,13 @@ impl<'a> Iterator for Messages<'a> {
             };
 
             let cmsg = cmsg.as_ref()?;
-            cfg_if::cfg_if! {
-                // Android return the same pointer if it is the last cmsg.
-                // Therefore, check it if the previous pointer is the same as the current one.
-                if #[cfg(target_os = "android")] {
-                    if let Some(current) = self.current {
-                        if eq(current, cmsg) {
-                            return None;
-                        }
-                    }
+
+            // Most operating systems, but not Linux or emscripten, return the previous pointer
+            // when its length is zero. Therefore, check if the previous pointer is the same as
+            // the current one.
+            if let Some(current) = self.current {
+                if eq(current, cmsg) {
+                    return None;
                 }
             }
 
@@ -514,6 +519,12 @@ impl<'a> SocketAncillary<'a> {
         self.buffer.len()
     }
 
+    /// Returns `true` if the ancillary data is empty.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn is_empty(&self) -> bool {
+        self.length == 0
+    }
+
     /// Returns the number of used bytes.
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn len(&self) -> usize {