about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/std/src/sys/unix/ext/net.rs867
-rw-r--r--library/std/src/sys/unix/ext/net/tests.rs152
-rw-r--r--library/std/src/sys/unix/net.rs92
3 files changed, 1111 insertions, 0 deletions
diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs
index 3d2366554b5..c72800b5d57 100644
--- a/library/std/src/sys/unix/ext/net.rs
+++ b/library/std/src/sys/unix/ext/net.rs
@@ -25,7 +25,10 @@ use crate::net::{self, Shutdown};
 use crate::os::unix::ffi::OsStrExt;
 use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
 use crate::path::Path;
+use crate::ptr::null_mut;
+use crate::slice::from_raw_parts;
 use crate::sys::net::Socket;
+use crate::sys::unix::net::{add_to_ancillary_data, AncillaryDataIter};
 use crate::sys::{self, cvt};
 use crate::sys_common::{self, AsInner, FromInner, IntoInner};
 use crate::time::Duration;
@@ -114,6 +117,62 @@ unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::sockl
     Ok((addr, len as libc::socklen_t))
 }
 
+fn recv_vectored_with_ancillary_from(
+    socket: &Socket,
+    bufs: &mut [IoSliceMut<'_>],
+    ancillary: &mut SocketAncillary<'_>,
+) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
+    unsafe {
+        let mut msg_name: libc::sockaddr_un = mem::zeroed();
+
+        let mut msg = libc::msghdr {
+            msg_name: &mut msg_name as *mut _ as *mut _,
+            msg_namelen: mem::size_of::<libc::sockaddr_un>() as libc::socklen_t,
+            msg_iov: bufs.as_mut_ptr().cast(),
+            msg_iovlen: bufs.len(),
+            msg_control: ancillary.buffer.as_mut_ptr().cast(),
+            msg_controllen: ancillary.buffer.len(),
+            msg_flags: 0,
+        };
+
+        let count = socket.recv_msg(&mut msg)?;
+
+        ancillary.length = msg.msg_controllen;
+        ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
+
+        let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
+        let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
+
+        Ok((count, truncated, addr))
+    }
+}
+
+fn send_vectored_with_ancillary_to(
+    socket: &Socket,
+    path: Option<&Path>,
+    bufs: &mut [IoSliceMut<'_>],
+    ancillary: &mut SocketAncillary<'_>,
+) -> io::Result<usize> {
+    unsafe {
+        let (mut msg_name, msg_namelen) =
+            if let Some(path) = path { sockaddr_un(path)? } else { (mem::zeroed(), 0) };
+
+        let mut msg = libc::msghdr {
+            msg_name: &mut msg_name as *mut _ as *mut _,
+            msg_namelen,
+            msg_iov: bufs.as_mut_ptr().cast(),
+            msg_iovlen: bufs.len(),
+            msg_control: ancillary.buffer.as_mut_ptr().cast(),
+            msg_controllen: ancillary.length,
+            msg_flags: 0,
+        };
+
+        ancillary.truncated = false;
+
+        socket.send_msg(&mut msg)
+    }
+}
+
 enum AddressKind<'a> {
     Unnamed,
     Pathname(&'a Path),
@@ -269,6 +328,556 @@ impl fmt::Debug for SocketAddr {
     }
 }
 
+#[cfg(any(
+    target_os = "haiku",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "macos",
+    target_os = "ios",
+    target_os = "freebsd",
+    target_os = "dragonfly",
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "linux",
+    target_os = "android",
+    target_os = "emscripten",
+    target_os = "fuchsia",
+    target_env = "uclibc",
+))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
+
+#[cfg(any(
+    target_os = "haiku",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "macos",
+    target_os = "ios",
+    target_os = "freebsd",
+    target_os = "dragonfly",
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "linux",
+    target_os = "android",
+    target_os = "emscripten",
+    target_os = "fuchsia",
+    target_env = "uclibc",
+))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+impl<'a> Iterator for ScmRights<'a> {
+    type Item = RawFd;
+
+    fn next(&mut self) -> Option<RawFd> {
+        self.0.next()
+    }
+}
+
+#[cfg(any(
+    target_os = "netbsd",
+    target_os = "openbsd",
+    target_os = "freebsd",
+    target_os = "dragonfly",
+    target_os = "macos",
+    target_os = "ios",
+    target_os = "linux",
+    target_os = "android",
+    target_os = "emscripten",
+    target_os = "fuchsia",
+    target_env = "uclibc",
+))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
+
+#[cfg(any(
+    target_os = "netbsd",
+    target_os = "openbsd",
+    target_os = "freebsd",
+    target_os = "dragonfly",
+    target_os = "macos",
+    target_os = "ios",
+    target_os = "linux",
+    target_os = "android",
+    target_os = "emscripten",
+    target_os = "fuchsia",
+    target_env = "uclibc",
+))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+impl<'a> Iterator for ScmCredentials<'a> {
+    type Item = libc::ucred;
+
+    fn next(&mut self) -> Option<libc::ucred> {
+        self.0.next()
+    }
+}
+
+#[cfg(any(
+    target_os = "haiku",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "macos",
+    target_os = "ios",
+    target_os = "freebsd",
+    target_os = "dragonfly",
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "linux",
+    target_os = "android",
+    target_os = "emscripten",
+    target_os = "fuchsia",
+    target_env = "uclibc",
+))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+pub enum AncillaryData<'a> {
+    ScmRights(ScmRights<'a>),
+    #[cfg(any(
+        target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "freebsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+        target_os = "ios",
+        target_os = "linux",
+        target_os = "android",
+        target_os = "emscripten",
+        target_os = "fuchsia",
+        target_env = "uclibc",
+    ))]
+    ScmCredentials(ScmCredentials<'a>),
+}
+
+impl<'a> AncillaryData<'a> {
+    #[cfg(any(
+        target_os = "haiku",
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "macos",
+        target_os = "ios",
+        target_os = "freebsd",
+        target_os = "dragonfly",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "linux",
+        target_os = "android",
+        target_os = "emscripten",
+        target_os = "fuchsia",
+        target_env = "uclibc",
+    ))]
+    fn as_rights(data: &'a [u8]) -> Self {
+        let ancillary_data_iter = AncillaryDataIter::new(data);
+        let scm_rights = ScmRights(ancillary_data_iter);
+        AncillaryData::ScmRights(scm_rights)
+    }
+
+    #[cfg(any(
+        target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "freebsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+        target_os = "ios",
+        target_os = "linux",
+        target_os = "android",
+        target_os = "emscripten",
+        target_os = "fuchsia",
+        target_env = "uclibc",
+    ))]
+    fn as_credentials(data: &'a [u8]) -> Self {
+        let ancillary_data_iter = AncillaryDataIter::new(data);
+        let scm_credentials = ScmCredentials(ancillary_data_iter);
+        AncillaryData::ScmCredentials(scm_credentials)
+    }
+}
+
+#[cfg(any(
+    target_os = "haiku",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "macos",
+    target_os = "ios",
+    target_os = "freebsd",
+    target_os = "dragonfly",
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "linux",
+    target_os = "android",
+    target_os = "emscripten",
+    target_os = "fuchsia",
+    target_env = "uclibc",
+))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+impl<'a> AncillaryData<'a> {
+    fn from(cmsg: &'a libc::cmsghdr) -> Self {
+        unsafe {
+            let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
+            let data_len = (*cmsg).cmsg_len - cmsg_len_zero;
+            let data = libc::CMSG_DATA(cmsg).cast();
+            let data = from_raw_parts(data, data_len);
+
+            if (*cmsg).cmsg_level == libc::SOL_SOCKET {
+                match (*cmsg).cmsg_type {
+                    libc::SCM_RIGHTS => AncillaryData::as_rights(data),
+                    #[cfg(any(
+                        target_os = "linux",
+                        target_os = "android",
+                        target_os = "emscripten",
+                        target_os = "fuchsia",
+                        target_env = "uclibc",
+                    ))]
+                    libc::SCM_CREDENTIALS => AncillaryData::as_credentials(data),
+                    #[cfg(any(
+                        target_os = "netbsd",
+                        target_os = "openbsd",
+                        target_os = "freebsd",
+                        target_os = "dragonfly",
+                        target_os = "macos",
+                        target_os = "ios",
+                    ))]
+                    libc::SCM_CREDS => AncillaryData::as_credentials(data),
+                    _ => panic!("Unknown cmsg type"),
+                }
+            } else {
+                panic!("Unknown cmsg level");
+            }
+        }
+    }
+}
+
+#[cfg(any(
+    target_os = "haiku",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "macos",
+    target_os = "ios",
+    target_os = "freebsd",
+    target_os = "dragonfly",
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "linux",
+    target_os = "android",
+    target_os = "emscripten",
+    target_os = "fuchsia",
+    target_env = "uclibc",
+))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+pub struct Messages<'a> {
+    buffer: &'a [u8],
+    current: Option<&'a libc::cmsghdr>,
+}
+
+#[cfg(any(
+    target_os = "haiku",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "macos",
+    target_os = "ios",
+    target_os = "freebsd",
+    target_os = "dragonfly",
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "linux",
+    target_os = "android",
+    target_os = "emscripten",
+    target_os = "fuchsia",
+    target_env = "uclibc",
+))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+impl<'a> Iterator for Messages<'a> {
+    type Item = AncillaryData<'a>;
+
+    fn next(&mut self) -> Option<AncillaryData<'a>> {
+        unsafe {
+            let msg = libc::msghdr {
+                msg_name: null_mut(),
+                msg_namelen: 0,
+                msg_iov: null_mut(),
+                msg_iovlen: 0,
+                msg_control: self.buffer.as_ptr() as *mut _,
+                msg_controllen: self.buffer.len(),
+                msg_flags: 0,
+            };
+
+            let cmsg = if let Some(current) = self.current {
+                libc::CMSG_NXTHDR(&msg, current)
+            } else {
+                libc::CMSG_FIRSTHDR(&msg)
+            };
+
+            let cmsg = cmsg.as_ref()?;
+            self.current = Some(cmsg);
+            let ancillary_data = AncillaryData::from(cmsg);
+            Some(ancillary_data)
+        }
+    }
+}
+
+/// A Unix socket Ancillary data struct.
+///
+/// # Example
+/// ```no_run
+/// #![feature(unix_socket_ancillary_data)]
+/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
+/// use std::io::IoSliceMut;
+///
+/// fn main() -> std::io::Result<()> {
+///     let sock = UnixStream::connect("/tmp/sock")?;
+///
+///     let mut fds = [0; 8];
+///     let mut ancillary_buffer = [0; 128];
+///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+///
+///     let mut buf = [1; 8];
+///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+///
+///     for ancillary_data in ancillary.messages() {
+///         if let AncillaryData::ScmRights(scm_rights) = ancillary_data {
+///             for fd in scm_rights {
+///                 println!("receive file descriptor: {}", fd);
+///             }
+///         }
+///     }
+///     Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+#[derive(Debug)]
+pub struct SocketAncillary<'a> {
+    buffer: &'a mut [u8],
+    length: usize,
+    truncated: bool,
+}
+
+impl<'a> SocketAncillary<'a> {
+    /// Create an ancillary data with the given buffer.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// # #![allow(unused_mut)]
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::SocketAncillary;
+    /// let mut ancillary_buffer = [0; 128];
+    /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    /// ```
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn new(buffer: &'a mut [u8]) -> Self {
+        SocketAncillary { buffer, length: 0, truncated: false }
+    }
+
+    /// Returns the capacity of the buffer.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn capacity(&self) -> usize {
+        self.buffer.len()
+    }
+
+    /// Returns the number of used bytes.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn len(&self) -> usize {
+        self.length
+    }
+
+    #[cfg(any(
+        target_os = "haiku",
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "macos",
+        target_os = "ios",
+        target_os = "freebsd",
+        target_os = "dragonfly",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "linux",
+        target_os = "android",
+        target_os = "emscripten",
+        target_os = "fuchsia",
+        target_env = "uclibc",
+    ))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn messages(&'a self) -> Messages<'a> {
+        Messages { buffer: &self.buffer[..self.length], current: None }
+    }
+
+    /// Is `true` if during a recv operation the ancillary was truncated.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixStream, SocketAncillary};
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixStream::connect("/tmp/sock")?;
+    ///
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///
+    ///     let mut buf = [1; 8];
+    ///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+    ///
+    ///     println!("Is truncated: {}", ancillary.truncated());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn truncated(&self) -> bool {
+        self.truncated
+    }
+
+    /// Add file descriptors to the ancillary data.
+    ///
+    /// The function returns `true` if there was enough space in the buffer.
+    /// If there was not enough space then no file descriptors was appended.
+    /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
+    /// and type `SCM_RIGHTS`.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixStream, SocketAncillary};
+    /// use std::os::unix::io::AsRawFd;
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixStream::connect("/tmp/sock")?;
+    ///
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     ancillary.add_fds(&[sock.as_raw_fd()][..]);
+    ///
+    ///     let mut buf = [1; 8];
+    ///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+    ///     sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[cfg(any(
+        target_os = "haiku",
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "macos",
+        target_os = "ios",
+        target_os = "freebsd",
+        target_os = "dragonfly",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "linux",
+        target_os = "android",
+        target_os = "emscripten",
+        target_os = "fuchsia",
+        target_env = "uclibc",
+    ))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
+        self.truncated = false;
+        add_to_ancillary_data(
+            &mut self.buffer,
+            &mut self.length,
+            fds,
+            libc::SOL_SOCKET,
+            libc::SCM_RIGHTS,
+        )
+    }
+
+    /// Add credentials to the ancillary data.
+    ///
+    /// The function returns `true` if there was enough space in the buffer.
+    /// If there was not enough space then no credentials was appended.
+    /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
+    /// and type `SCM_CREDENTIALS`.
+    ///
+    #[cfg(any(
+        target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "freebsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+        target_os = "ios",
+        target_os = "linux",
+        target_os = "android",
+        target_os = "emscripten",
+        target_os = "fuchsia",
+        target_env = "uclibc",
+    ))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn add_creds(&mut self, creds: &[libc::ucred]) -> bool {
+        self.truncated = false;
+        add_to_ancillary_data(
+            &mut self.buffer,
+            &mut self.length,
+            creds,
+            libc::SOL_SOCKET,
+            #[cfg(any(
+                target_os = "linux",
+                target_os = "android",
+                target_os = "emscripten",
+                target_os = "fuchsia",
+                target_env = "uclibc",
+            ))]
+            libc::SCM_CREDENTIALS,
+            #[cfg(any(
+                target_os = "netbsd",
+                target_os = "openbsd",
+                target_os = "freebsd",
+                target_os = "dragonfly",
+                target_os = "macos",
+                target_os = "ios",
+            ))]
+            libc::SCM_CREDS,
+        )
+    }
+
+    /// Clears the ancillary data, removing all values.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixStream::connect("/tmp/sock")?;
+    ///
+    ///     let mut fds1 = [0; 8];
+    ///     let mut fds2 = [0; 8];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///
+    ///     let mut buf = [1; 8];
+    ///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+    ///
+    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+    ///     for ancillary_data in ancillary.messages() {
+    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_data {
+    ///             for fd in scm_rights {
+    ///                 println!("receive file descriptor: {}", fd);
+    ///             }
+    ///         }
+    ///     }
+    ///
+    ///     ancillary.clear();
+    ///
+    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+    ///     for ancillary_data in ancillary.messages() {
+    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_data {
+    ///             for fd in scm_rights {
+    ///                 println!("receive file descriptor: {}", fd);
+    ///             }
+    ///         }
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn clear(&mut self) {
+        self.length = 0;
+        self.truncated = false;
+    }
+}
+
 struct AsciiEscaped<'a>(&'a [u8]);
 
 impl<'a> fmt::Display for AsciiEscaped<'a> {
@@ -646,6 +1255,91 @@ impl UnixStream {
         self.0.shutdown(how)
     }
 
+    /// Receives data and ancillary data from socket.
+    ///
+    /// On success, returns the number of bytes read.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     let mut buf1 = [1; 8];
+    ///     let mut buf2 = [2; 16];
+    ///     let mut buf3 = [3; 8];
+    ///     let mut bufs = &mut [
+    ///         IoSliceMut::new(&mut buf1),
+    ///         IoSliceMut::new(&mut buf2),
+    ///         IoSliceMut::new(&mut buf3),
+    ///     ][..];
+    ///     let mut fds = [0; 8];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+    ///     println!("received {}", size);
+    ///     for ancillary_data in ancillary.messages() {
+    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_data {
+    ///             for fd in scm_rights {
+    ///                 println!("receive file descriptor: {}", fd);
+    ///             }
+    ///         }
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn recv_vectored_with_ancillary(
+        &self,
+        bufs: &mut [IoSliceMut<'_>],
+        ancillary: &mut SocketAncillary<'_>,
+    ) -> io::Result<usize> {
+        let (count, _, _) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
+
+        Ok(count)
+    }
+
+    /// Sends data and ancillary data on the socket.
+    ///
+    /// On success, returns the number of bytes written.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixStream, SocketAncillary};
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     let mut buf1 = [1; 8];
+    ///     let mut buf2 = [2; 16];
+    ///     let mut buf3 = [3; 8];
+    ///     let mut bufs = &mut [
+    ///         IoSliceMut::new(&mut buf1),
+    ///         IoSliceMut::new(&mut buf2),
+    ///         IoSliceMut::new(&mut buf3),
+    ///     ][..];
+    ///     let fds = [0, 1, 2];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     ancillary.add_fds(&fds[..]);
+    ///     socket.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn send_vectored_with_ancillary(
+        &self,
+        bufs: &mut [IoSliceMut<'_>],
+        ancillary: &mut SocketAncillary<'_>,
+    ) -> io::Result<usize> {
+        send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
+    }
+
     /// Receives data on the socket from the remote address to which it is
     /// connected, without removing that data from the queue. On success,
     /// returns the number of bytes peeked.
@@ -1439,6 +2133,102 @@ impl UnixDatagram {
         self.0.read(buf)
     }
 
+    /// Receives data and ancillary data from socket.
+    ///
+    /// On success, returns the number of bytes read, if the data was truncated and the address from whence the msg came.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     let mut buf1 = [1; 8];
+    ///     let mut buf2 = [2; 16];
+    ///     let mut buf3 = [3; 8];
+    ///     let mut bufs = &mut [
+    ///         IoSliceMut::new(&mut buf1),
+    ///         IoSliceMut::new(&mut buf2),
+    ///         IoSliceMut::new(&mut buf3),
+    ///     ][..];
+    ///     let mut fds = [0; 8];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?;
+    ///     println!("received {}", size);
+    ///     for ancillary_data in ancillary.messages() {
+    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_data {
+    ///             for fd in scm_rights {
+    ///                 println!("receive file descriptor: {}", fd);
+    ///             }
+    ///         }
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn recv_vectored_with_ancillary_from(
+        &self,
+        bufs: &mut [IoSliceMut<'_>],
+        ancillary: &mut SocketAncillary<'_>,
+    ) -> io::Result<(usize, bool, SocketAddr)> {
+        let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
+        let addr = addr?;
+
+        Ok((count, truncated, addr))
+    }
+
+    /// Receives data and ancillary data from socket.
+    ///
+    /// On success, returns the number of bytes read and if the data was truncated.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     let mut buf1 = [1; 8];
+    ///     let mut buf2 = [2; 16];
+    ///     let mut buf3 = [3; 8];
+    ///     let mut bufs = &mut [
+    ///         IoSliceMut::new(&mut buf1),
+    ///         IoSliceMut::new(&mut buf2),
+    ///         IoSliceMut::new(&mut buf3),
+    ///     ][..];
+    ///     let mut fds = [0; 8];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+    ///     println!("received {}", size);
+    ///     for ancillary_data in ancillary.messages() {
+    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_data {
+    ///             for fd in scm_rights {
+    ///                 println!("receive file descriptor: {}", fd);
+    ///             }
+    ///         }
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn recv_vectored_with_ancillary(
+        &self,
+        bufs: &mut [IoSliceMut<'_>],
+        ancillary: &mut SocketAncillary<'_>,
+    ) -> io::Result<(usize, bool)> {
+        let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
+        addr?;
+
+        Ok((count, truncated))
+    }
+
     /// Sends data on the socket to the specified address.
     ///
     /// On success, returns the number of bytes written.
@@ -1498,6 +2288,83 @@ impl UnixDatagram {
         self.0.write(buf)
     }
 
+    /// Sends data and ancillary data on the socket to the specified address.
+    ///
+    /// On success, returns the number of bytes written.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     let mut buf1 = [1; 8];
+    ///     let mut buf2 = [2; 16];
+    ///     let mut buf3 = [3; 8];
+    ///     let mut bufs = &mut [
+    ///         IoSliceMut::new(&mut buf1),
+    ///         IoSliceMut::new(&mut buf2),
+    ///         IoSliceMut::new(&mut buf3),
+    ///     ][..];
+    ///     let fds = [0, 1, 2];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     ancillary.add_fds(&fds[..]);
+    ///     sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock").expect("send_vectored_with_ancillary_to function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn send_vectored_with_ancillary_to<P: AsRef<Path>>(
+        &self,
+        bufs: &mut [IoSliceMut<'_>],
+        ancillary: &mut SocketAncillary<'_>,
+        path: P,
+    ) -> io::Result<usize> {
+        send_vectored_with_ancillary_to(&self.0, Some(path.as_ref()), bufs, ancillary)
+    }
+
+    /// Sends data and ancillary data on the socket.
+    ///
+    /// On success, returns the number of bytes written.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     let mut buf1 = [1; 8];
+    ///     let mut buf2 = [2; 16];
+    ///     let mut buf3 = [3; 8];
+    ///     let mut bufs = &mut [
+    ///         IoSliceMut::new(&mut buf1),
+    ///         IoSliceMut::new(&mut buf2),
+    ///         IoSliceMut::new(&mut buf3),
+    ///     ][..];
+    ///     let fds = [0, 1, 2];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     ancillary.add_fds(&fds[..]);
+    ///     sock.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "none")]
+    pub fn send_vectored_with_ancillary(
+        &self,
+        bufs: &mut [IoSliceMut<'_>],
+        ancillary: &mut SocketAncillary<'_>,
+    ) -> io::Result<usize> {
+        send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
+    }
+
     /// Sets the read timeout for the socket.
     ///
     /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will
diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs
index ee73a6ed538..a4ca81c1c22 100644
--- a/library/std/src/sys/unix/ext/net/tests.rs
+++ b/library/std/src/sys/unix/ext/net/tests.rs
@@ -452,3 +452,155 @@ fn test_unix_datagram_peek_from() {
     assert_eq!(size, 11);
     assert_eq!(msg, &buf[..]);
 }
+
+#[test]
+fn test_send_vectored_fds_unix_stream() {
+    let (s1, s2) = or_panic!(UnixStream::pair());
+
+    let mut buf1 = [1; 8];
+    let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..];
+
+    let mut ancillary1_buffer = [0; 128];
+    let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
+    assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..]));
+
+    let usize = or_panic!(s1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1));
+    assert_eq!(usize, 8);
+
+    let mut buf2 = [0; 8];
+    let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
+
+    let mut ancillary2_buffer = [0; 128];
+    let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
+
+    let usize = or_panic!(s2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2));
+    assert_eq!(usize, 8);
+    assert_eq!(buf1, buf2);
+
+    let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
+    assert_eq!(ancillary_data_vec.len(), 1);
+    if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap() {
+        let fd_vec = Vec::from_iter(scm_rights);
+        assert_eq!(fd_vec.len(), 1);
+        unsafe {
+            libc::close(fd_vec[0]);
+        }
+    } else {
+        assert!(false);
+    }
+}
+
+#[test]
+fn test_send_vectored_with_ancillary_to_unix_datagram() {
+    fn getpid() -> libc::pid_t {
+        unsafe { libc::getpid() }
+    }
+
+    fn getuid() -> libc::uid_t {
+        unsafe { libc::getuid() }
+    }
+
+    fn getgid() -> libc::gid_t {
+        unsafe { libc::getgid() }
+    }
+
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock1");
+    let path2 = dir.path().join("sock2");
+
+    let bsock1 = or_panic!(UnixDatagram::bind(&path1));
+    let bsock2 = or_panic!(UnixDatagram::bind(&path2));
+
+    unsafe {
+        let optval: libc::c_int = 1;
+        libc::setsockopt(
+            bsock2.as_raw_fd(),
+            libc::SOL_SOCKET,
+            libc::SO_PASSCRED,
+            &optval as *const _ as *const _,
+            mem::size_of::<libc::c_int>() as u32,
+        );
+    }
+
+    let mut buf1 = [1; 8];
+    let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..];
+
+    let mut ancillary1_buffer = [0; 128];
+    let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
+    let cred1 = libc::ucred { pid: getpid(), uid: getuid(), gid: getgid() };
+    assert!(ancillary1.add_creds(&[cred1][..]));
+
+    let usize =
+        or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2));
+    assert_eq!(usize, 8);
+
+    let mut buf2 = [0; 8];
+    let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
+
+    let mut ancillary2_buffer = [0; 128];
+    let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
+
+    let (usize, truncated, _addr) =
+        or_panic!(bsock2.recv_vectored_with_ancillary_from(&mut bufs_recv, &mut ancillary2));
+    assert_eq!(ancillary2.truncated(), false);
+    assert_eq!(usize, 8);
+    assert_eq!(truncated, false);
+    assert_eq!(buf1, buf2);
+
+    let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
+    assert_eq!(ancillary_data_vec.len(), 1);
+    if let AncillaryData::ScmCredentials(scm_credentials) = ancillary_data_vec.pop().unwrap() {
+        let cred_vec = Vec::from_iter(scm_credentials);
+        assert_eq!(cred_vec.len(), 1);
+        assert_eq!(cred1.pid, cred_vec[0].pid);
+        assert_eq!(cred1.uid, cred_vec[0].uid);
+        assert_eq!(cred1.gid, cred_vec[0].gid);
+    } else {
+        assert!(false);
+    }
+}
+
+#[test]
+fn test_send_vectored_with_ancillary_unix_datagram() {
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock1");
+    let path2 = dir.path().join("sock2");
+
+    let bsock1 = or_panic!(UnixDatagram::bind(&path1));
+    let bsock2 = or_panic!(UnixDatagram::bind(&path2));
+
+    let mut buf1 = [1; 8];
+    let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..];
+
+    let mut ancillary1_buffer = [0; 128];
+    let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
+    assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..]));
+
+    or_panic!(bsock1.connect(&path2));
+    let usize = or_panic!(bsock1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1));
+    assert_eq!(usize, 8);
+
+    let mut buf2 = [0; 8];
+    let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
+
+    let mut ancillary2_buffer = [0; 128];
+    let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
+
+    let (usize, truncated) =
+        or_panic!(bsock2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2));
+    assert_eq!(usize, 8);
+    assert_eq!(truncated, false);
+    assert_eq!(buf1, buf2);
+
+    let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
+    assert_eq!(ancillary_data_vec.len(), 1);
+    if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap() {
+        let fd_vec = Vec::from_iter(scm_rights);
+        assert_eq!(fd_vec.len(), 1);
+        unsafe {
+            libc::close(fd_vec[0]);
+        }
+    } else {
+        assert!(false);
+    }
+}
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index 011325fddc5..e067edd3774 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -1,8 +1,10 @@
 use crate::cmp;
 use crate::ffi::CStr;
 use crate::io::{self, IoSlice, IoSliceMut};
+use crate::marker::PhantomData;
 use crate::mem;
 use crate::net::{Shutdown, SocketAddr};
+use crate::ptr::null_mut;
 use crate::str;
 use crate::sys::fd::FileDesc;
 use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
@@ -18,6 +20,86 @@ pub extern crate libc as netc;
 
 pub type wrlen_t = size_t;
 
+pub struct AncillaryDataIter<'a, T> {
+    data: &'a [u8],
+    phantom: crate::marker::PhantomData<T>,
+}
+
+impl<'a, T> AncillaryDataIter<'a, T> {
+    pub fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
+        AncillaryDataIter { data, phantom: PhantomData }
+    }
+}
+
+impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        unsafe {
+            let mut unit = mem::zeroed();
+            if mem::size_of::<T>() <= self.data.len() {
+                let unit_ptr: *mut T = &mut unit;
+                libc::memcpy(unit_ptr.cast(), self.data.as_ptr().cast(), mem::size_of::<T>());
+                self.data = &self.data[mem::size_of::<T>()..];
+                Some(unit)
+            } else {
+                None
+            }
+        }
+    }
+}
+
+pub fn add_to_ancillary_data<T: core::clone::Clone>(
+    buffer: &mut [u8],
+    length: &mut usize,
+    source: &[T],
+    cmsg_level: libc::c_int,
+    cmsg_type: libc::c_int,
+) -> bool {
+    let len = (source.len() * mem::size_of::<T>()) as u32;
+
+    unsafe {
+        let additional_space = libc::CMSG_SPACE(len) as usize;
+        if *length + additional_space > buffer.len() {
+            return false;
+        }
+
+        libc::memset(buffer[*length..].as_mut_ptr().cast(), 0, additional_space);
+
+        *length += additional_space;
+
+        let msg = libc::msghdr {
+            msg_name: null_mut(),
+            msg_namelen: 0,
+            msg_iov: null_mut(),
+            msg_iovlen: 0,
+            msg_control: buffer.as_mut_ptr().cast(),
+            msg_controllen: *length,
+            msg_flags: 0,
+        };
+
+        let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
+        let mut previous_cmsg = cmsg;
+        while !cmsg.is_null() {
+            previous_cmsg = cmsg;
+            cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
+        }
+
+        if previous_cmsg.is_null() {
+            return false;
+        }
+
+        (*previous_cmsg).cmsg_level = cmsg_level;
+        (*previous_cmsg).cmsg_type = cmsg_type;
+        (*previous_cmsg).cmsg_len = libc::CMSG_LEN(len) as usize;
+
+        let data = libc::CMSG_DATA(previous_cmsg).cast();
+
+        libc::memcpy(data, source.as_ptr().cast(), len as usize);
+    }
+    true
+}
+
 pub struct Socket(FileDesc);
 
 pub fn init() {}
@@ -237,6 +319,11 @@ impl Socket {
         self.recv_from_with_flags(buf, 0)
     }
 
+    pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
+        let n = cvt(unsafe { libc::recvmsg(self.0.raw(), msg, libc::MSG_CMSG_CLOEXEC) })?;
+        Ok(n as usize)
+    }
+
     pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
         self.recv_from_with_flags(buf, MSG_PEEK)
     }
@@ -254,6 +341,11 @@ impl Socket {
         self.0.is_write_vectored()
     }
 
+    pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
+        let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?;
+        Ok(n as usize)
+    }
+
     pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
         let timeout = match dur {
             Some(dur) => {