From 84ef603c8400db203fefd714de963c88e5523424 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 17 Sep 2020 21:11:22 +0200 Subject: [PATCH 01/60] Fix 'FIXME' about using NonZeroU32 instead of u32. It was blocked by #58732 (const fn NonZeroU32::new), which is fixed now. --- compiler/rustc_feature/src/accepted.rs | 4 ++-- compiler/rustc_feature/src/active.rs | 4 ++-- compiler/rustc_feature/src/lib.rs | 21 +++++++++++---------- compiler/rustc_feature/src/removed.rs | 6 +++--- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 0477f6f149b87..e2492efb9d79e 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -1,6 +1,6 @@ //! List of the accepted feature gates. -use super::{Feature, State}; +use super::{to_nonzero, Feature, State}; use rustc_span::symbol::sym; macro_rules! declare_features { @@ -14,7 +14,7 @@ macro_rules! declare_features { state: State::Accepted, name: sym::$feature, since: $ver, - issue: $issue, + issue: to_nonzero($issue), edition: None, description: concat!($($doc,)*), } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index d4664292a0cbd..7dcd563228f7f 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -1,6 +1,6 @@ //! List of the active feature gates. -use super::{Feature, State}; +use super::{to_nonzero, Feature, State}; use rustc_span::edition::Edition; use rustc_span::symbol::{sym, Symbol}; @@ -29,7 +29,7 @@ macro_rules! declare_features { state: State::Active { set: set!($feature) }, name: sym::$feature, since: $ver, - issue: $issue, + issue: to_nonzero($issue), edition: $edition, description: concat!($($doc,)*), } diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 15564a59658cb..c70f3c3cd402f 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -46,17 +46,11 @@ pub struct Feature { pub state: State, pub name: Symbol, pub since: &'static str, - issue: Option, // FIXME: once #58732 is done make this an Option + issue: Option, pub edition: Option, description: &'static str, } -impl Feature { - fn issue(&self) -> Option { - self.issue.and_then(NonZeroU32::new) - } -} - #[derive(Copy, Clone, Debug)] pub enum Stability { Unstable, @@ -102,8 +96,8 @@ impl UnstableFeatures { fn find_lang_feature_issue(feature: Symbol) -> Option { if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) { // FIXME (#28244): enforce that active features have issue numbers - // assert!(info.issue().is_some()) - info.issue() + // assert!(info.issue.is_some()) + info.issue } else { // search in Accepted, Removed, or Stable Removed features let found = ACCEPTED_FEATURES @@ -112,12 +106,19 @@ fn find_lang_feature_issue(feature: Symbol) -> Option { .chain(STABLE_REMOVED_FEATURES) .find(|t| t.name == feature); match found { - Some(found) => found.issue(), + Some(found) => found.issue, None => panic!("feature `{}` is not declared anywhere", feature), } } } +const fn to_nonzero(n: Option) -> Option { + match n { + None => None, + Some(n) => NonZeroU32::new(n), + } +} + pub enum GateIssue { Language, Library(Option), diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 8d410894e8b19..a480ddc7f34b1 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -1,6 +1,6 @@ //! List of the removed feature gates. -use super::{Feature, State}; +use super::{to_nonzero, Feature, State}; use rustc_span::symbol::sym; macro_rules! declare_features { @@ -14,7 +14,7 @@ macro_rules! declare_features { state: State::Removed { reason: $reason }, name: sym::$feature, since: $ver, - issue: $issue, + issue: to_nonzero($issue), edition: None, description: concat!($($doc,)*), } @@ -32,7 +32,7 @@ macro_rules! declare_features { state: State::Stabilized { reason: None }, name: sym::$feature, since: $ver, - issue: $issue, + issue: to_nonzero($issue), edition: None, description: concat!($($doc,)*), } From 323bcd3021bfd41cab26c0999a111083371ae295 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Fri, 21 Aug 2020 14:52:10 +0200 Subject: [PATCH 02/60] unix: Extend UnixStream and UnixDatagram to send and receive file descriptors Add the functions `recv_vectored_fds` and `send_vectored_fds` to send and receive file descriptors, by using `recvmsg` and `sendmsg` system call. --- library/std/src/sys/unix/ext/net.rs | 867 ++++++++++++++++++++++ library/std/src/sys/unix/ext/net/tests.rs | 152 ++++ library/std/src/sys/unix/net.rs | 92 +++ 3 files changed, 1111 insertions(+) diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs index 3d2366554b5b2..c72800b5d573a 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)> { + 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::() 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 { + 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 { + 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 { + 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> { + 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 { + 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 { + 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>( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + path: P, + ) -> io::Result { + 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 { + 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 ee73a6ed538ff..a4ca81c1c22e0 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::() 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 011325fddc5b9..e067edd377429 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, +} + +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 { + unsafe { + let mut unit = mem::zeroed(); + if mem::size_of::() <= self.data.len() { + let unit_ptr: *mut T = &mut unit; + libc::memcpy(unit_ptr.cast(), self.data.as_ptr().cast(), mem::size_of::()); + self.data = &self.data[mem::size_of::()..]; + Some(unit) + } else { + None + } + } + } +} + +pub fn add_to_ancillary_data( + 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::()) 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 { + 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 { + let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?; + Ok(n as usize) + } + pub fn set_timeout(&self, dur: Option, kind: libc::c_int) -> io::Result<()> { let timeout = match dur { Some(dur) => { From ff87ba1b1a8fe0a52ab88814bb5ef2b0c37bb56c Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 22 Aug 2020 17:27:43 +0200 Subject: [PATCH 03/60] Split net.rs into multiple files --- library/std/src/sys/unix/ext/net.rs | 2635 ----------------- library/std/src/sys/unix/ext/net/addr.rs | 226 ++ library/std/src/sys/unix/ext/net/ancillary.rs | 614 ++++ library/std/src/sys/unix/ext/net/datagram.rs | 819 +++++ library/std/src/sys/unix/ext/net/listener.rs | 323 ++ library/std/src/sys/unix/ext/net/mod.rs | 25 + library/std/src/sys/unix/ext/net/raw_fd.rs | 67 + library/std/src/sys/unix/ext/net/stream.rs | 615 ++++ library/std/src/sys/unix/ext/net/test.rs | 608 ++++ 9 files changed, 3297 insertions(+), 2635 deletions(-) delete mode 100644 library/std/src/sys/unix/ext/net.rs create mode 100644 library/std/src/sys/unix/ext/net/addr.rs create mode 100644 library/std/src/sys/unix/ext/net/ancillary.rs create mode 100644 library/std/src/sys/unix/ext/net/datagram.rs create mode 100644 library/std/src/sys/unix/ext/net/listener.rs create mode 100644 library/std/src/sys/unix/ext/net/mod.rs create mode 100644 library/std/src/sys/unix/ext/net/raw_fd.rs create mode 100644 library/std/src/sys/unix/ext/net/stream.rs create mode 100644 library/std/src/sys/unix/ext/net/test.rs diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs deleted file mode 100644 index c72800b5d573a..0000000000000 --- a/library/std/src/sys/unix/ext/net.rs +++ /dev/null @@ -1,2635 +0,0 @@ -//! Unix-specific networking functionality. - -#![stable(feature = "unix_socket", since = "1.10.0")] - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests; - -// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? -#[cfg(not(unix))] -#[allow(non_camel_case_types)] -mod libc { - pub use libc::c_int; - pub type socklen_t = u32; - pub struct sockaddr; - #[derive(Clone)] - pub struct sockaddr_un; -} - -use crate::ascii; -use crate::ffi::OsStr; -use crate::fmt; -use crate::io::{self, Initializer, IoSlice, IoSliceMut}; -use crate::mem; -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; - -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -use crate::os::unix::ucred; - -#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -pub use ucred::UCred; - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" -))] -use libc::MSG_NOSIGNAL; -#[cfg(not(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" -)))] -const MSG_NOSIGNAL: libc::c_int = 0x0; - -fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { - // Work with an actual instance of the type since using a null pointer is UB - let base = addr as *const _ as usize; - let path = &addr.sun_path as *const _ as usize; - path - base -} - -unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { - let mut addr: libc::sockaddr_un = mem::zeroed(); - addr.sun_family = libc::AF_UNIX as libc::sa_family_t; - - let bytes = path.as_os_str().as_bytes(); - - if bytes.contains(&0) { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "paths may not contain interior null bytes", - )); - } - - if bytes.len() >= addr.sun_path.len() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "path must be shorter than SUN_LEN", - )); - } - for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { - *dst = *src as libc::c_char; - } - // null byte for pathname addresses is already there because we zeroed the - // struct - - let mut len = sun_path_offset(&addr) + bytes.len(); - match bytes.get(0) { - Some(&0) | None => {} - Some(_) => len += 1, - } - 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)> { - 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::() 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 { - 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), - Abstract(&'a [u8]), -} - -/// An address associated with a Unix socket. -/// -/// # Examples -/// -/// ``` -/// use std::os::unix::net::UnixListener; -/// -/// let socket = match UnixListener::bind("/tmp/sock") { -/// Ok(sock) => sock, -/// Err(e) => { -/// println!("Couldn't bind: {:?}", e); -/// return -/// } -/// }; -/// let addr = socket.local_addr().expect("Couldn't get local address"); -/// ``` -#[derive(Clone)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct SocketAddr { - addr: libc::sockaddr_un, - len: libc::socklen_t, -} - -impl SocketAddr { - fn new(f: F) -> io::Result - where - F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int, - { - unsafe { - let mut addr: libc::sockaddr_un = mem::zeroed(); - let mut len = mem::size_of::() as libc::socklen_t; - cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; - SocketAddr::from_parts(addr, len) - } - } - - fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { - if len == 0 { - // When there is a datagram from unnamed unix socket - // linux returns zero bytes of address - len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address - } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "file descriptor did not correspond to a Unix socket", - )); - } - - Ok(SocketAddr { addr, len }) - } - - /// Returns `true` if the address is unnamed. - /// - /// # Examples - /// - /// A named address: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), false); - /// Ok(()) - /// } - /// ``` - /// - /// An unnamed address: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), true); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn is_unnamed(&self) -> bool { - if let AddressKind::Unnamed = self.address() { true } else { false } - } - - /// Returns the contents of this address if it is a `pathname` address. - /// - /// # Examples - /// - /// With a pathname: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// use std::path::Path; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); - /// Ok(()) - /// } - /// ``` - /// - /// Without a pathname: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), None); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn as_pathname(&self) -> Option<&Path> { - if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } - } - - fn address(&self) -> AddressKind<'_> { - let len = self.len as usize - sun_path_offset(&self.addr); - let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; - - // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses - if len == 0 - || (cfg!(not(any(target_os = "linux", target_os = "android"))) - && self.addr.sun_path[0] == 0) - { - AddressKind::Unnamed - } else if self.addr.sun_path[0] == 0 { - AddressKind::Abstract(&path[1..len]) - } else { - AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) - } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.address() { - AddressKind::Unnamed => write!(fmt, "(unnamed)"), - AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), - AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), - } - } -} - -#[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 { - 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 { - 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> { - 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> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "\"")?; - for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { - write!(fmt, "{}", byte as char)?; - } - write!(fmt, "\"") - } -} - -/// A Unix stream socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixStream; -/// use std::io::prelude::*; -/// -/// fn main() -> std::io::Result<()> { -/// let mut stream = UnixStream::connect("/path/to/my/socket")?; -/// stream.write_all(b"hello world")?; -/// let mut response = String::new(); -/// stream.read_to_string(&mut response)?; -/// println!("{}", response); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixStream(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixStream { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixStream"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixStream { - /// Connects to the socket named by `path`. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = match UnixStream::connect("/tmp/sock") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; - Ok(UnixStream(inner)) - } - } - inner(path.as_ref()) - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixStream`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let (sock1, sock2) = match UnixStream::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't create a pair of sockets: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixStream, UnixStream)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; - Ok((UnixStream(i1), UnixStream(i2))) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixStream` is a reference to the same stream that this - /// object references. Both handles will read and write the same stream of - /// data, and options set on one stream will be propagated to the other - /// stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixStream) - } - - /// Returns the socket address of the local half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Returns the socket address of the remote half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) - } - - /// Gets the peer credentials for this Unix domain socket. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(peer_credentials_unix_socket)] - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" - ))] - pub fn peer_cred(&self) -> io::Result { - ucred::peer_cred(self) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`read`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`read`]: io::Read::read - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`write`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// [`read`]: io::Read::read - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UdpSocket::bind("127.0.0.1:34254")?; - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); - /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// if let Ok(Some(err)) = socket.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns `None`. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shuts down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::net::Shutdown; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - 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 { - 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 { - 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. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recv` system call. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.0.peek(buf) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Read for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - io::Read::read(&mut &*self, buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - io::Read::read_vectored(&mut &*self, bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - io::Read::is_read_vectored(&&*self) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Read for &'a UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Write for UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - io::Write::write(&mut &*self, buf) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - io::Write::write_vectored(&mut &*self, bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - io::Write::is_write_vectored(&&*self) - } - - fn flush(&mut self) -> io::Result<()> { - io::Write::flush(&mut &*self) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Write for &'a UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixStream { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixStream { - unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { - UnixStream(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixStream { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let socket = sys::net::Socket::from_inner(fd); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let socket = sys::net::Socket::from_inner(fd); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpStream { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpListener { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::UdpSocket { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} - -/// A structure representing a Unix domain socket server. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// fn main() -> std::io::Result<()> { -/// let listener = UnixListener::bind("/path/to/the/socket")?; -/// -/// // accept connections and process them, spawning a new thread for each one -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// /* connection succeeded */ -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// /* connection failed */ -/// break; -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixListener(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixListener { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixListener"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - builder.finish() - } -} - -impl UnixListener { - /// Creates a new `UnixListener` bound to the specified socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = match UnixListener::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; - cvt(libc::listen(*inner.as_inner(), 128))?; - - Ok(UnixListener(inner)) - } - } - inner(path.as_ref()) - } - - /// Accepts a new incoming connection to this listener. - /// - /// This function will block the calling thread until a new Unix connection - /// is established. When established, the corresponding [`UnixStream`] and - /// the remote peer's address will be returned. - /// - /// [`UnixStream`]: crate::os::unix::net::UnixStream - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// - /// match listener.accept() { - /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), - /// Err(e) => println!("accept function failed: {:?}", e), - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { - let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; - let mut len = mem::size_of_val(&storage) as libc::socklen_t; - let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; - let addr = SocketAddr::from_parts(storage, len)?; - Ok((UnixStream(sock), addr)) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixListener` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one listener will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let listener_copy = listener.try_clone().expect("try_clone failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixListener) - } - - /// Returns the local socket address of this listener. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let addr = listener.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// This will result in the `accept` operation becoming nonblocking, - /// i.e., immediately returning from their calls. If the IO operation is - /// successful, `Ok` is returned and no further action is required. If the - /// IO operation could not be completed and needs to be retried, an error - /// with kind [`io::ErrorKind::WouldBlock`] is returned. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/tmp/sock")?; - /// - /// if let Ok(Some(err)) = listener.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns `None`. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Returns an iterator over incoming connections. - /// - /// The iterator will never return [`None`] and will also not yield the - /// peer's [`SocketAddr`] structure. - /// - /// # Examples - /// - /// ```no_run - /// use std::thread; - /// use std::os::unix::net::{UnixStream, UnixListener}; - /// - /// fn handle_client(stream: UnixStream) { - /// // ... - /// } - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// - /// for stream in listener.incoming() { - /// match stream { - /// Ok(stream) => { - /// thread::spawn(|| handle_client(stream)); - /// } - /// Err(err) => { - /// break; - /// } - /// } - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn incoming(&self) -> Incoming<'_> { - Incoming { listener: self } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixListener { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixListener { - unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { - UnixListener(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixListener { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> IntoIterator for &'a UnixListener { - type Item = io::Result; - type IntoIter = Incoming<'a>; - - fn into_iter(self) -> Incoming<'a> { - self.incoming() - } -} - -/// An iterator over incoming connections to a [`UnixListener`]. -/// -/// It will never return [`None`]. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// fn main() -> std::io::Result<()> { -/// let listener = UnixListener::bind("/path/to/the/socket")?; -/// -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// break; -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -#[derive(Debug)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct Incoming<'a> { - listener: &'a UnixListener, -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> Iterator for Incoming<'a> { - type Item = io::Result; - - fn next(&mut self) -> Option> { - Some(self.listener.accept().map(|s| s.0)) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::MAX, None) - } -} - -/// A Unix datagram socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixDatagram; -/// -/// fn main() -> std::io::Result<()> { -/// let socket = UnixDatagram::bind("/path/to/my/socket")?; -/// socket.send_to(b"hello world", "/path/to/other/socket")?; -/// let mut buf = [0; 100]; -/// let (count, address) = socket.recv_from(&mut buf)?; -/// println!("socket {:?} sent {:?}", address, &buf[..count]); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixDatagram(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixDatagram { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixDatagram"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixDatagram { - /// Creates a Unix datagram socket bound to the given path. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = match UnixDatagram::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't bind: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let socket = UnixDatagram::unbound()?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; - - Ok(socket) - } - } - inner(path.as_ref()) - } - - /// Creates a Unix Datagram socket which is not bound to any address. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = match UnixDatagram::unbound() { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn unbound() -> io::Result { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; - Ok(UnixDatagram(inner)) - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixDatagrams`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let (sock1, sock2) = match UnixDatagram::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; - Ok((UnixDatagram(i1), UnixDatagram(i2))) - } - - /// Connects the socket to the specified address. - /// - /// The [`send`] method may be used to send data to the specified address. - /// [`recv`] and [`recv_from`] will only receive data from that address. - /// - /// [`send`]: UnixDatagram::send - /// [`recv`]: UnixDatagram::recv - /// [`recv_from`]: UnixDatagram::recv_from - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// match sock.connect("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return Err(e) - /// } - /// }; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(&self, path: P) -> io::Result<()> { - fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?; - - Ok(()) - } - } - inner(self, path.as_ref()) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixDatagram` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one side will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let sock_copy = sock.try_clone().expect("try_clone failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixDatagram) - } - - /// Returns the address of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let addr = sock.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Returns the address of this socket's peer. - /// - /// The [`connect`] method will connect the socket to a peer. - /// - /// [`connect`]: UnixDatagram::connect - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.connect("/path/to/the/socket")?; - /// - /// let addr = sock.peer_addr().expect("Couldn't get peer address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) - } - - fn recv_from_flags( - &self, - buf: &mut [u8], - flags: libc::c_int, - ) -> io::Result<(usize, SocketAddr)> { - let mut count = 0; - let addr = SocketAddr::new(|addr, len| unsafe { - count = libc::recvfrom( - *self.0.as_inner(), - buf.as_mut_ptr() as *mut _, - buf.len(), - flags, - addr, - len, - ); - if count > 0 { - 1 - } else if count == 0 { - 0 - } else { - -1 - } - })?; - - Ok((count as usize, addr)) - } - - /// Receives data from the socket. - /// - /// On success, returns the number of bytes read and the address from - /// whence the data came. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// let mut buf = vec![0; 10]; - /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?; - /// println!("received {} bytes from {:?}", size, sender); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_flags(buf, 0) - } - - /// Receives data from the socket. - /// - /// On success, returns the number of bytes read. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let mut buf = vec![0; 10]; - /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn recv(&self, buf: &mut [u8]) -> io::Result { - 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. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { - fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - let count = cvt(libc::sendto( - *d.0.as_inner(), - buf.as_ptr() as *const _, - buf.len(), - MSG_NOSIGNAL, - &addr as *const _ as *const _, - len, - ))?; - Ok(count as usize) - } - } - inner(self, buf, path.as_ref()) - } - - /// Sends data on the socket to the socket's peer. - /// - /// The peer address may be set by the `connect` method, and this method - /// will return an error if the socket has not already been connected. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.connect("/some/sock").expect("Couldn't connect"); - /// sock.send(b"omelette au fromage").expect("send_to function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn send(&self, buf: &[u8]) -> io::Result { - 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>( - &self, - bufs: &mut [IoSliceMut<'_>], - ancillary: &mut SocketAncillary<'_>, - path: P, - ) -> io::Result { - 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 { - 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 - /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] - /// is passed to this method. - /// - /// [`recv`]: UnixDatagram::recv - /// [`recv_from`]: UnixDatagram::recv_from - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will - /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`send`]: UnixDatagram::send - /// [`send_to`]: UnixDatagram::send_to - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); - /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); - /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// if let Ok(Some(err)) = sock.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shut down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// use std::net::Shutdown; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } - - /// 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. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recv` system call. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::bind("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.0.peek(buf) - } - - /// Receives a single datagram message on the socket, without removing it from the - /// queue. On success, returns the number of bytes read and the origin. - /// - /// The function must be called with valid byte array `buf` of sufficient size to - /// hold the message bytes. If a message is too long to fit in the supplied buffer, - /// excess bytes may be discarded. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. - /// - /// Do not use this function to implement busy waiting, instead use `libc::poll` to - /// synchronize IO events on one or more sockets. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::bind("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_flags(buf, libc::MSG_PEEK) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixDatagram { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixDatagram { - unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { - UnixDatagram(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixDatagram { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} diff --git a/library/std/src/sys/unix/ext/net/addr.rs b/library/std/src/sys/unix/ext/net/addr.rs new file mode 100644 index 0000000000000..15fc5bb5b4e6b --- /dev/null +++ b/library/std/src/sys/unix/ext/net/addr.rs @@ -0,0 +1,226 @@ +use crate::ffi::OsStr; +use crate::os::unix::ffi::OsStrExt; +use crate::path::Path; +use crate::sys::unix::cvt; +use crate::{ascii, fmt, io, mem}; + +// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? +#[cfg(not(unix))] +#[allow(non_camel_case_types)] +mod libc { + pub use libc::c_int; + pub type socklen_t = u32; + pub struct sockaddr; + #[derive(Clone)] + pub struct sockaddr_un; +} + +fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { + // Work with an actual instance of the type since using a null pointer is UB + let base = addr as *const _ as usize; + let path = &addr.sun_path as *const _ as usize; + path - base +} + +pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { + let mut addr: libc::sockaddr_un = mem::zeroed(); + addr.sun_family = libc::AF_UNIX as libc::sa_family_t; + + let bytes = path.as_os_str().as_bytes(); + + if bytes.contains(&0) { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "paths may not contain interior null bytes", + )); + } + + if bytes.len() >= addr.sun_path.len() { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "path must be shorter than SUN_LEN", + )); + } + for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { + *dst = *src as libc::c_char; + } + // null byte for pathname addresses is already there because we zeroed the + // struct + + let mut len = sun_path_offset(&addr) + bytes.len(); + match bytes.get(0) { + Some(&0) | None => {} + Some(_) => len += 1, + } + Ok((addr, len as libc::socklen_t)) +} + +enum AddressKind<'a> { + Unnamed, + Pathname(&'a Path), + Abstract(&'a [u8]), +} + +struct AsciiEscaped<'a>(&'a [u8]); + +impl<'a> fmt::Display for AsciiEscaped<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "\"")?; + for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { + write!(fmt, "{}", byte as char)?; + } + write!(fmt, "\"") + } +} + +/// An address associated with a Unix socket. +/// +/// # Examples +/// +/// ``` +/// use std::os::unix::net::UnixListener; +/// +/// let socket = match UnixListener::bind("/tmp/sock") { +/// Ok(sock) => sock, +/// Err(e) => { +/// println!("Couldn't bind: {:?}", e); +/// return +/// } +/// }; +/// let addr = socket.local_addr().expect("Couldn't get local address"); +/// ``` +#[derive(Clone)] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct SocketAddr { + addr: libc::sockaddr_un, + len: libc::socklen_t, +} + +impl SocketAddr { + pub(super) fn new(f: F) -> io::Result + where + F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int, + { + unsafe { + let mut addr: libc::sockaddr_un = mem::zeroed(); + let mut len = mem::size_of::() as libc::socklen_t; + cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; + SocketAddr::from_parts(addr, len) + } + } + + pub(super) fn from_parts( + addr: libc::sockaddr_un, + mut len: libc::socklen_t, + ) -> io::Result { + if len == 0 { + // When there is a datagram from unnamed unix socket + // linux returns zero bytes of address + len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address + } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "file descriptor did not correspond to a Unix socket", + )); + } + + Ok(SocketAddr { addr, len }) + } + + /// Returns `true` if the address is unnamed. + /// + /// # Examples + /// + /// A named address: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixListener::bind("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), false); + /// Ok(()) + /// } + /// ``` + /// + /// An unnamed address: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), true); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn is_unnamed(&self) -> bool { + if let AddressKind::Unnamed = self.address() { true } else { false } + } + + /// Returns the contents of this address if it is a `pathname` address. + /// + /// # Examples + /// + /// With a pathname: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// use std::path::Path; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixListener::bind("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); + /// Ok(()) + /// } + /// ``` + /// + /// Without a pathname: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), None); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn as_pathname(&self) -> Option<&Path> { + if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } + } + + fn address(&self) -> AddressKind<'_> { + let len = self.len as usize - sun_path_offset(&self.addr); + let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; + + // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses + if len == 0 + || (cfg!(not(any(target_os = "linux", target_os = "android"))) + && self.addr.sun_path[0] == 0) + { + AddressKind::Unnamed + } else if self.addr.sun_path[0] == 0 { + AddressKind::Abstract(&path[1..len]) + } else { + AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) + } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.address() { + AddressKind::Unnamed => write!(fmt, "(unnamed)"), + AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), + AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), + } + } +} diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs new file mode 100644 index 0000000000000..4e584cb143faa --- /dev/null +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -0,0 +1,614 @@ +use crate::io::{self, IoSliceMut}; +use crate::mem; +use crate::os::unix::io::RawFd; +use crate::path::Path; +use crate::ptr::null_mut; +use crate::slice::from_raw_parts; +use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +use crate::sys::unix::net::{add_to_ancillary_data, AncillaryDataIter, Socket}; + +pub(super) fn recv_vectored_with_ancillary_from( + socket: &Socket, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, +) -> io::Result<(usize, bool, io::Result)> { + 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::() 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)) + } +} + +pub(super) fn send_vectored_with_ancillary_to( + socket: &Socket, + path: Option<&Path>, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, +) -> io::Result { + 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) + } +} + +#[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 { + 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 { + 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> { + 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; + } +} diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs new file mode 100644 index 0000000000000..e5630127ccbcb --- /dev/null +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -0,0 +1,819 @@ +use crate::io::IoSliceMut; +use crate::net::Shutdown; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::path::Path; +use crate::sys::unix::cvt; +use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +use crate::sys::unix::ext::net::ancillary::{ + recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, +}; +use crate::sys::unix::net::Socket; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::time::Duration; +use crate::{fmt, io}; + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "haiku" +))] +use libc::MSG_NOSIGNAL; +#[cfg(not(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "haiku" +)))] +const MSG_NOSIGNAL: libc::c_int = 0x0; + +/// A Unix datagram socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixDatagram; +/// +/// fn main() -> std::io::Result<()> { +/// let socket = UnixDatagram::bind("/path/to/my/socket")?; +/// socket.send_to(b"hello world", "/path/to/other/socket")?; +/// let mut buf = [0; 100]; +/// let (count, address) = socket.recv_from(&mut buf)?; +/// println!("socket {:?} sent {:?}", address, &buf[..count]); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixDatagram(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixDatagram { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixDatagram"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixDatagram { + /// Creates a Unix datagram socket bound to the given path. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let sock = match UnixDatagram::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't bind: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind>(path: P) -> io::Result { + fn inner(path: &Path) -> io::Result { + unsafe { + let socket = UnixDatagram::unbound()?; + let (addr, len) = sockaddr_un(path)?; + + cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; + + Ok(socket) + } + } + inner(path.as_ref()) + } + + /// Creates a Unix Datagram socket which is not bound to any address. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let sock = match UnixDatagram::unbound() { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't unbound: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn unbound() -> io::Result { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; + Ok(UnixDatagram(inner)) + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixDatagrams`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let (sock1, sock2) = match UnixDatagram::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't unbound: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { + let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; + Ok((UnixDatagram(i1), UnixDatagram(i2))) + } + + /// Connects the socket to the specified address. + /// + /// The [`send`] method may be used to send data to the specified address. + /// [`recv`] and [`recv_from`] will only receive data from that address. + /// + /// [`send`]: UnixDatagram::send + /// [`recv`]: UnixDatagram::recv + /// [`recv_from`]: UnixDatagram::recv_from + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// match sock.connect("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return Err(e) + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect>(&self, path: P) -> io::Result<()> { + fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { + unsafe { + let (addr, len) = sockaddr_un(path)?; + + cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?; + + Ok(()) + } + } + inner(self, path.as_ref()) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixDatagram` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one side will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let sock_copy = sock.try_clone().expect("try_clone failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixDatagram) + } + + /// Returns the address of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let addr = sock.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Returns the address of this socket's peer. + /// + /// The [`connect`] method will connect the socket to a peer. + /// + /// [`connect`]: UnixDatagram::connect + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.connect("/path/to/the/socket")?; + /// + /// let addr = sock.peer_addr().expect("Couldn't get peer address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + } + + fn recv_from_flags( + &self, + buf: &mut [u8], + flags: libc::c_int, + ) -> io::Result<(usize, SocketAddr)> { + let mut count = 0; + let addr = SocketAddr::new(|addr, len| unsafe { + count = libc::recvfrom( + *self.0.as_inner(), + buf.as_mut_ptr() as *mut _, + buf.len(), + flags, + addr, + len, + ); + if count > 0 { + 1 + } else if count == 0 { + 0 + } else { + -1 + } + })?; + + Ok((count as usize, addr)) + } + + /// Receives data from the socket. + /// + /// On success, returns the number of bytes read and the address from + /// whence the data came. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf = vec![0; 10]; + /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?; + /// println!("received {} bytes from {:?}", size, sender); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_flags(buf, 0) + } + + /// Receives data from the socket. + /// + /// On success, returns the number of bytes read. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let mut buf = vec![0; 10]; + /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn recv(&self, buf: &mut [u8]) -> io::Result { + 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. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { + fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result { + unsafe { + let (addr, len) = sockaddr_un(path)?; + + let count = cvt(libc::sendto( + *d.0.as_inner(), + buf.as_ptr() as *const _, + buf.len(), + MSG_NOSIGNAL, + &addr as *const _ as *const _, + len, + ))?; + Ok(count as usize) + } + } + inner(self, buf, path.as_ref()) + } + + /// Sends data on the socket to the socket's peer. + /// + /// The peer address may be set by the `connect` method, and this method + /// will return an error if the socket has not already been connected. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.connect("/some/sock").expect("Couldn't connect"); + /// sock.send(b"omelette au fromage").expect("send_to function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn send(&self, buf: &[u8]) -> io::Result { + 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>( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + path: P, + ) -> io::Result { + 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 { + 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 + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] + /// is passed to this method. + /// + /// [`recv`]: UnixDatagram::recv + /// [`recv_from`]: UnixDatagram::recv_from + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_read_timeout(Some(Duration::new(1, 0))) + /// .expect("set_read_timeout function failed"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_RCVTIMEO) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`send`]: UnixDatagram::send + /// [`send_to`]: UnixDatagram::send_to + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("set_write_timeout function failed"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_SNDTIMEO) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_read_timeout(Some(Duration::new(1, 0))) + /// .expect("set_read_timeout function failed"); + /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_RCVTIMEO) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("set_write_timeout function failed"); + /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_SNDTIMEO) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// if let Ok(Some(err)) = sock.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Shut down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// use std::net::Shutdown; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } + + /// 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. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + + /// Receives a single datagram message on the socket, without removing it from the + /// queue. On success, returns the number of bytes read and the origin. + /// + /// The function must be called with valid byte array `buf` of sufficient size to + /// hold the message bytes. If a message is too long to fit in the supplied buffer, + /// excess bytes may be discarded. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. + /// + /// Do not use this function to implement busy waiting, instead use `libc::poll` to + /// synchronize IO events on one or more sockets. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_flags(buf, libc::MSG_PEEK) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixDatagram { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixDatagram { + unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { + UnixDatagram(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixDatagram { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} diff --git a/library/std/src/sys/unix/ext/net/listener.rs b/library/std/src/sys/unix/ext/net/listener.rs new file mode 100644 index 0000000000000..84386ea6381c1 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/listener.rs @@ -0,0 +1,323 @@ +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::path::Path; +use crate::sys::net::Socket; +use crate::sys::unix::cvt; +use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +use crate::sys::unix::ext::net::stream::UnixStream; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::{fmt, io, mem}; + +/// A structure representing a Unix domain socket server. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// fn main() -> std::io::Result<()> { +/// let listener = UnixListener::bind("/path/to/the/socket")?; +/// +/// // accept connections and process them, spawning a new thread for each one +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// /* connection succeeded */ +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// /* connection failed */ +/// break; +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixListener(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixListener { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixListener"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + builder.finish() + } +} + +impl UnixListener { + /// Creates a new `UnixListener` bound to the specified socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = match UnixListener::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind>(path: P) -> io::Result { + fn inner(path: &Path) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path)?; + + cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; + cvt(libc::listen(*inner.as_inner(), 128))?; + + Ok(UnixListener(inner)) + } + } + inner(path.as_ref()) + } + + /// Accepts a new incoming connection to this listener. + /// + /// This function will block the calling thread until a new Unix connection + /// is established. When established, the corresponding [`UnixStream`] and + /// the remote peer's address will be returned. + /// + /// [`UnixStream`]: crate::os::unix::net::UnixStream + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// + /// match listener.accept() { + /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), + /// Err(e) => println!("accept function failed: {:?}", e), + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; + let mut len = mem::size_of_val(&storage) as libc::socklen_t; + let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; + let addr = SocketAddr::from_parts(storage, len)?; + Ok((UnixStream(sock), addr)) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixListener` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one listener will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixListener) + } + + /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// This will result in the `accept` operation becoming nonblocking, + /// i.e., immediately returning from their calls. If the IO operation is + /// successful, `Ok` is returned and no further action is required. If the + /// IO operation could not be completed and needs to be retried, an error + /// with kind [`io::ErrorKind::WouldBlock`] is returned. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/tmp/sock")?; + /// + /// if let Ok(Some(err)) = listener.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns `None`. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Returns an iterator over incoming connections. + /// + /// The iterator will never return [`None`] and will also not yield the + /// peer's [`SocketAddr`] structure. + /// + /// # Examples + /// + /// ```no_run + /// use std::thread; + /// use std::os::unix::net::{UnixStream, UnixListener}; + /// + /// fn handle_client(stream: UnixStream) { + /// // ... + /// } + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// thread::spawn(|| handle_client(stream)); + /// } + /// Err(err) => { + /// break; + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn incoming(&self) -> Incoming<'_> { + Incoming { listener: self } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixListener { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixListener { + unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { + UnixListener(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixListener { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> IntoIterator for &'a UnixListener { + type Item = io::Result; + type IntoIter = Incoming<'a>; + + fn into_iter(self) -> Incoming<'a> { + self.incoming() + } +} + +/// An iterator over incoming connections to a [`UnixListener`]. +/// +/// It will never return [`None`]. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// fn main() -> std::io::Result<()> { +/// let listener = UnixListener::bind("/path/to/the/socket")?; +/// +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// break; +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[derive(Debug)] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct Incoming<'a> { + listener: &'a UnixListener, +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + Some(self.listener.accept().map(|s| s.0)) + } + + fn size_hint(&self) -> (usize, Option) { + (usize::MAX, None) + } +} diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs new file mode 100644 index 0000000000000..93b72df520aa3 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -0,0 +1,25 @@ +//! Unix-specific networking functionality + +#![stable(feature = "unix_socket", since = "1.10.0")] + +mod addr; +mod ancillary; +mod datagram; +mod listener; +mod raw_fd; +mod stream; +#[cfg(all(test, not(target_os = "emscripten")))] +mod test; + +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::addr::*; +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +pub use self::ancillary::*; +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::datagram::*; +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::listener::*; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::raw_fd::*; +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::stream::*; diff --git a/library/std/src/sys/unix/ext/net/raw_fd.rs b/library/std/src/sys/unix/ext/net/raw_fd.rs new file mode 100644 index 0000000000000..059c0fec06f2f --- /dev/null +++ b/library/std/src/sys/unix/ext/net/raw_fd.rs @@ -0,0 +1,67 @@ +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::sys_common::{self, AsInner, FromInner, IntoInner}; +use crate::{net, sys}; + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::TcpStream { + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::TcpListener { + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::UdpSocket { + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawFd for net::TcpStream { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { + let socket = sys::net::Socket::from_inner(fd); + net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawFd for net::TcpListener { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { + let socket = sys::net::Socket::from_inner(fd); + net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawFd for net::UdpSocket { + unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { + let socket = sys::net::Socket::from_inner(fd); + net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for net::TcpStream { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for net::TcpListener { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for net::UdpSocket { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs new file mode 100644 index 0000000000000..75b9190266811 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -0,0 +1,615 @@ +use crate::fmt; +use crate::io::{self, Initializer, IoSlice, IoSliceMut}; +use crate::net::Shutdown; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +use crate::os::unix::ucred; +use crate::path::Path; +use crate::sys::cvt; +use crate::sys::net::Socket; +use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +use crate::sys::unix::ext::net::ancillary::{ + recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, +}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::time::Duration; + +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub use ucred::UCred; + +/// A Unix stream socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixStream; +/// use std::io::prelude::*; +/// +/// fn main() -> std::io::Result<()> { +/// let mut stream = UnixStream::connect("/path/to/my/socket")?; +/// stream.write_all(b"hello world")?; +/// let mut response = String::new(); +/// stream.read_to_string(&mut response)?; +/// println!("{}", response); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixStream(pub(super) Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixStream { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixStream"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixStream { + /// Connects to the socket named by `path`. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = match UnixStream::connect("/tmp/sock") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect>(path: P) -> io::Result { + fn inner(path: &Path) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path)?; + + cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; + Ok(UnixStream(inner)) + } + } + inner(path.as_ref()) + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixStream`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let (sock1, sock2) = match UnixStream::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't create a pair of sockets: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixStream, UnixStream)> { + let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; + Ok((UnixStream(i1), UnixStream(i2))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixStream` is a reference to the same stream that this + /// object references. Both handles will read and write the same stream of + /// data, and options set on one stream will be propagated to the other + /// stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixStream) + } + + /// Returns the socket address of the local half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Returns the socket address of the remote half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + } + + /// Gets the peer credentials for this Unix domain socket. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(peer_credentials_unix_socket)] + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" + ))] + pub fn peer_cred(&self) -> io::Result { + ucred::peer_cred(self) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`read`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`read`]: io::Read::read + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_RCVTIMEO) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`write`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. + /// + /// [`read`]: io::Read::read + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("Couldn't set write timeout"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UdpSocket::bind("127.0.0.1:34254")?; + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_SNDTIMEO) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_RCVTIMEO) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("Couldn't set write timeout"); + /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_SNDTIMEO) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// if let Ok(Some(err)) = socket.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns `None`. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::net::Shutdown; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } + + /// 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. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + + /// 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 { + 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 { + send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Read for UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + io::Read::read(&mut &*self, buf) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + io::Read::read_vectored(&mut &*self, bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + io::Read::is_read_vectored(&&*self) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Write for UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + io::Write::write(&mut &*self, buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + io::Write::write_vectored(&mut &*self, bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + io::Write::is_write_vectored(&&*self) + } + + fn flush(&mut self) -> io::Result<()> { + io::Write::flush(&mut &*self) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixStream { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixStream { + unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { + UnixStream(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixStream { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} diff --git a/library/std/src/sys/unix/ext/net/test.rs b/library/std/src/sys/unix/ext/net/test.rs new file mode 100644 index 0000000000000..724d73c9b1ed9 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/test.rs @@ -0,0 +1,608 @@ +use super::*; +use crate::io::prelude::*; +use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; +use crate::iter::FromIterator; +use crate::mem; +use crate::sys::unix::ext::io::AsRawFd; +use crate::sys_common::io::test::tmpdir; +use crate::thread; +use crate::time::Duration; + +macro_rules! or_panic { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{}", e), + } + }; +} + +#[test] +fn basic() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + let msg1 = b"hello"; + let msg2 = b"world!"; + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + let mut buf = [0; 5]; + or_panic!(stream.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(stream.write_all(msg2)); + }); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname()); + or_panic!(stream.write_all(msg1)); + let mut buf = vec![]; + or_panic!(stream.read_to_end(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(stream); + + thread.join().unwrap(); +} + +#[test] +fn vectored() { + let (mut s1, mut s2) = or_panic!(UnixStream::pair()); + + let len = or_panic!(s1.write_vectored(&[ + IoSlice::new(b"hello"), + IoSlice::new(b" "), + IoSlice::new(b"world!") + ],)); + assert_eq!(len, 12); + + let mut buf1 = [0; 6]; + let mut buf2 = [0; 7]; + let len = + or_panic!(s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)); + assert_eq!(len, 12); + assert_eq!(&buf1, b"hello "); + assert_eq!(&buf2, b"world!\0"); +} + +#[test] +fn pair() { + let msg1 = b"hello"; + let msg2 = b"world!"; + + let (mut s1, mut s2) = or_panic!(UnixStream::pair()); + let thread = thread::spawn(move || { + // s1 must be moved in or the test will hang! + let mut buf = [0; 5]; + or_panic!(s1.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(s1.write_all(msg2)); + }); + + or_panic!(s2.write_all(msg1)); + let mut buf = vec![]; + or_panic!(s2.read_to_end(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(s2); + + thread.join().unwrap(); +} + +#[test] +fn try_clone() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + let msg1 = b"hello"; + let msg2 = b"world"; + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + or_panic!(stream.write_all(msg1)); + or_panic!(stream.write_all(msg2)); + }); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + let mut stream2 = or_panic!(stream.try_clone()); + + let mut buf = [0; 5]; + or_panic!(stream.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(stream2.read(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + + thread.join().unwrap(); +} + +#[test] +fn iter() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let thread = thread::spawn(move || { + for stream in listener.incoming().take(2) { + let mut stream = or_panic!(stream); + let mut buf = [0]; + or_panic!(stream.read(&mut buf)); + } + }); + + for _ in 0..2 { + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + or_panic!(stream.write_all(&[0])); + } + + thread.join().unwrap(); +} + +#[test] +fn long_path() { + let dir = tmpdir(); + let socket_path = dir.path().join( + "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\ + sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf", + ); + match UnixStream::connect(&socket_path) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } + + match UnixListener::bind(&socket_path) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } + + match UnixDatagram::bind(&socket_path) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } +} + +#[test] +fn timeouts() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let _listener = or_panic!(UnixListener::bind(&socket_path)); + + let stream = or_panic!(UnixStream::connect(&socket_path)); + let dur = Duration::new(15410, 0); + + assert_eq!(None, or_panic!(stream.read_timeout())); + + or_panic!(stream.set_read_timeout(Some(dur))); + assert_eq!(Some(dur), or_panic!(stream.read_timeout())); + + assert_eq!(None, or_panic!(stream.write_timeout())); + + or_panic!(stream.set_write_timeout(Some(dur))); + assert_eq!(Some(dur), or_panic!(stream.write_timeout())); + + or_panic!(stream.set_read_timeout(None)); + assert_eq!(None, or_panic!(stream.read_timeout())); + + or_panic!(stream.set_write_timeout(None)); + assert_eq!(None, or_panic!(stream.write_timeout())); +} + +#[test] +fn test_read_timeout() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let _listener = or_panic!(UnixListener::bind(&socket_path)); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut buf = [0; 10]; + let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); +} + +#[test] +fn test_read_with_timeout() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut other_end = or_panic!(listener.accept()).0; + or_panic!(other_end.write_all(b"hello world")); + + let mut buf = [0; 11]; + or_panic!(stream.read(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + + let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); +} + +// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors +// when passed zero Durations +#[test] +fn test_unix_stream_timeout_zero_duration() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let stream = or_panic!(UnixStream::connect(&socket_path)); + + let result = stream.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = stream.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + drop(listener); +} + +#[test] +fn test_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::bind(&path2)); + + let msg = b"hello world"; + or_panic!(sock1.send_to(msg, &path2)); + let mut buf = [0; 11]; + or_panic!(sock2.recv_from(&mut buf)); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_unnamed_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + + let msg = b"hello world"; + or_panic!(sock2.send_to(msg, &path1)); + let mut buf = [0; 11]; + let (usize, addr) = or_panic!(sock1.recv_from(&mut buf)); + assert_eq!(usize, 11); + assert!(addr.is_unnamed()); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_connect_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 sock = or_panic!(UnixDatagram::unbound()); + or_panic!(sock.connect(&path1)); + + // Check send() + let msg = b"hello there"; + or_panic!(sock.send(msg)); + let mut buf = [0; 11]; + let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf)); + assert_eq!(usize, 11); + assert!(addr.is_unnamed()); + assert_eq!(msg, &buf[..]); + + // Changing default socket works too + or_panic!(sock.connect(&path2)); + or_panic!(sock.send(msg)); + or_panic!(bsock2.recv_from(&mut buf)); +} + +#[test] +fn test_unix_datagram_recv() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn datagram_pair() { + let msg1 = b"hello"; + let msg2 = b"world!"; + + let (s1, s2) = or_panic!(UnixDatagram::pair()); + let thread = thread::spawn(move || { + // s1 must be moved in or the test will hang! + let mut buf = [0; 5]; + or_panic!(s1.recv(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(s1.send(msg2)); + }); + + or_panic!(s2.send(msg1)); + let mut buf = [0; 6]; + or_panic!(s2.recv(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(s2); + + thread.join().unwrap(); +} + +// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors +// when passed zero Durations +#[test] +fn test_unix_datagram_timeout_zero_duration() { + let dir = tmpdir(); + let path = dir.path().join("sock"); + + let datagram = or_panic!(UnixDatagram::bind(&path)); + + let result = datagram.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = datagram.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); +} + +#[test] +fn abstract_namespace_not_allowed() { + assert!(UnixStream::connect("\0asdf").is_err()); +} + +#[test] +fn test_unix_stream_peek() { + let (txdone, rxdone) = crate::sync::mpsc::channel(); + + let dir = tmpdir(); + let path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&path)); + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + or_panic!(stream.write_all(&[1, 3, 3, 7])); + or_panic!(rxdone.recv()); + }); + + let mut stream = or_panic!(UnixStream::connect(&path)); + let mut buf = [0; 10]; + for _ in 0..2 { + assert_eq!(or_panic!(stream.peek(&mut buf)), 4); + } + assert_eq!(or_panic!(stream.read(&mut buf)), 4); + + or_panic!(stream.set_nonblocking(true)); + match stream.peek(&mut buf) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error: {}", e), + } + + or_panic!(txdone.send(())); + thread.join().unwrap(); +} + +#[test] +fn test_unix_datagram_peek() { + let dir = tmpdir(); + let path1 = dir.path().join("sock"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + for _ in 0..2 { + let mut buf = [0; 11]; + let size = or_panic!(sock1.peek(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); + } + + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_unix_datagram_peek_from() { + let dir = tmpdir(); + let path1 = dir.path().join("sock"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + for _ in 0..2 { + let mut buf = [0; 11]; + let (size, _) = or_panic!(sock1.peek_from(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); + } + + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + 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::() 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); + } +} From e7b8925134db61d3b3d3f307995e99d71ca7aa8d Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 22 Aug 2020 20:25:43 +0200 Subject: [PATCH 04/60] Add AncillaryError --- library/std/src/sys/unix/ext/net/ancillary.rs | 53 ++++++++++++------- library/std/src/sys/unix/ext/net/datagram.rs | 8 +-- library/std/src/sys/unix/ext/net/stream.rs | 4 +- library/std/src/sys/unix/ext/net/test.rs | 8 +-- 4 files changed, 44 insertions(+), 29 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 4e584cb143faa..77214801e3e0e 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -1,3 +1,4 @@ +use crate::convert::TryFrom; use crate::io::{self, IoSliceMut}; use crate::mem; use crate::os::unix::io::RawFd; @@ -145,6 +146,13 @@ impl<'a> Iterator for ScmCredentials<'a> { } } +#[non_exhaustive] +#[derive(Debug)] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +pub enum AncillaryError { + Unknown { cmsg_level: i32, cmsg_type: i32 }, +} + #[cfg(any( target_os = "haiku", target_os = "solaris", @@ -240,17 +248,19 @@ impl<'a> AncillaryData<'a> { target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] -impl<'a> AncillaryData<'a> { - fn from(cmsg: &'a libc::cmsghdr) -> Self { +impl<'a> TryFrom<&'a libc::cmsghdr> for AncillaryData<'a> { + type Error = AncillaryError; + + fn try_from(cmsg: &'a libc::cmsghdr) -> Result { 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), + match (*cmsg).cmsg_level { + libc::SOL_SOCKET => match (*cmsg).cmsg_type { + libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)), #[cfg(any( target_os = "linux", target_os = "android", @@ -258,7 +268,7 @@ impl<'a> AncillaryData<'a> { target_os = "fuchsia", target_env = "uclibc", ))] - libc::SCM_CREDENTIALS => AncillaryData::as_credentials(data), + libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)), #[cfg(any( target_os = "netbsd", target_os = "openbsd", @@ -267,11 +277,14 @@ impl<'a> AncillaryData<'a> { target_os = "macos", target_os = "ios", ))] - libc::SCM_CREDS => AncillaryData::as_credentials(data), - _ => panic!("Unknown cmsg type"), + libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)), + cmsg_type => { + Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type }) + } + }, + cmsg_level => { + Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type }) } - } else { - panic!("Unknown cmsg level"); } } } @@ -317,9 +330,9 @@ pub struct Messages<'a> { ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] impl<'a> Iterator for Messages<'a> { - type Item = AncillaryData<'a>; + type Item = Result, AncillaryError>; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option { unsafe { let msg = libc::msghdr { msg_name: null_mut(), @@ -339,8 +352,8 @@ impl<'a> Iterator for Messages<'a> { let cmsg = cmsg.as_ref()?; self.current = Some(cmsg); - let ancillary_data = AncillaryData::from(cmsg); - Some(ancillary_data) + let ancillary_result = AncillaryData::try_from(cmsg); + Some(ancillary_result) } } } @@ -364,8 +377,8 @@ impl<'a> Iterator for Messages<'a> { /// 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 ancillary_result in ancillary.messages() { +/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { /// println!("receive file descriptor: {}", fd); /// } @@ -585,8 +598,8 @@ impl<'a> SocketAncillary<'a> { /// 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 ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { /// println!("receive file descriptor: {}", fd); /// } @@ -596,8 +609,8 @@ impl<'a> SocketAncillary<'a> { /// 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 ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { /// println!("receive file descriptor: {}", fd); /// } diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index e5630127ccbcb..e2fa65572e1e5 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -343,8 +343,8 @@ impl UnixDatagram { /// 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 ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { /// println!("receive file descriptor: {}", fd); /// } @@ -391,8 +391,8 @@ impl UnixDatagram { /// 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 ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { /// println!("receive file descriptor: {}", fd); /// } diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 75b9190266811..d144c41de3c81 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -451,8 +451,8 @@ impl UnixStream { /// 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 ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { /// println!("receive file descriptor: {}", fd); /// } diff --git a/library/std/src/sys/unix/ext/net/test.rs b/library/std/src/sys/unix/ext/net/test.rs index 724d73c9b1ed9..3be9bb48583fb 100644 --- a/library/std/src/sys/unix/ext/net/test.rs +++ b/library/std/src/sys/unix/ext/net/test.rs @@ -481,7 +481,7 @@ fn test_send_vectored_fds_unix_stream() { 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() { + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { let fd_vec = Vec::from_iter(scm_rights); assert_eq!(fd_vec.len(), 1); unsafe { @@ -551,7 +551,9 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { 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() { + if let AncillaryData::ScmCredentials(scm_credentials) = + ancillary_data_vec.pop().unwrap().unwrap() + { let cred_vec = Vec::from_iter(scm_credentials); assert_eq!(cred_vec.len(), 1); assert_eq!(cred1.pid, cred_vec[0].pid); @@ -596,7 +598,7 @@ fn test_send_vectored_with_ancillary_unix_datagram() { 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() { + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { let fd_vec = Vec::from_iter(scm_rights); assert_eq!(fd_vec.len(), 1); unsafe { From 656d7b97d3606e97d20bd703ca6f105e8510aa29 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 23 Aug 2020 14:34:12 +0200 Subject: [PATCH 05/60] Add UCred struct --- library/std/src/sys/unix/ext/net/ancillary.rs | 49 +++++++++++++++++-- library/std/src/sys/unix/ext/net/test.rs | 13 +++-- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 77214801e3e0e..7d0f43ab87f81 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -64,6 +64,47 @@ pub(super) fn send_vectored_with_ancillary_to( } } +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[derive(Clone)] +pub struct UCred(libc::ucred); + +impl UCred { + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn new() -> UCred { + UCred(libc::ucred { pid: 0, uid: 0, gid: 0 }) + } + + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn set_pid(&mut self, pid: i32) { + self.0.pid = pid; + } + + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn get_pid(&self) -> i32 { + self.0.pid + } + + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn set_uid(&mut self, uid: u32) { + self.0.uid = uid; + } + + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn get_uid(&self) -> u32 { + self.0.uid + } + + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn set_gid(&mut self, gid: u32) { + self.0.gid = gid; + } + + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn get_gid(&self) -> u32 { + self.0.gid + } +} + #[cfg(any( target_os = "haiku", target_os = "solaris", @@ -139,10 +180,10 @@ pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] impl<'a> Iterator for ScmCredentials<'a> { - type Item = libc::ucred; + type Item = UCred; - fn next(&mut self) -> Option { - self.0.next() + fn next(&mut self) -> Option { + Some(UCred(self.0.next()?)) } } @@ -550,7 +591,7 @@ impl<'a> SocketAncillary<'a> { target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn add_creds(&mut self, creds: &[libc::ucred]) -> bool { + pub fn add_creds(&mut self, creds: &[UCred]) -> bool { self.truncated = false; add_to_ancillary_data( &mut self.buffer, diff --git a/library/std/src/sys/unix/ext/net/test.rs b/library/std/src/sys/unix/ext/net/test.rs index 3be9bb48583fb..a39b97f2c31b9 100644 --- a/library/std/src/sys/unix/ext/net/test.rs +++ b/library/std/src/sys/unix/ext/net/test.rs @@ -529,8 +529,11 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { 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 mut cred1 = UCred::new(); + cred1.set_pid(getpid()); + cred1.set_uid(getuid()); + cred1.set_gid(getgid()); + assert!(ancillary1.add_creds(&[cred1.clone()][..])); let usize = or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2)); @@ -556,9 +559,9 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { { 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); + assert_eq!(cred1.get_pid(), cred_vec[0].get_pid()); + assert_eq!(cred1.get_uid(), cred_vec[0].get_uid()); + assert_eq!(cred1.get_gid(), cred_vec[0].get_gid()); } else { assert!(false); } From baa7c2198a448e855da94b708a0b489fe02b10db Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 23 Aug 2020 14:50:54 +0200 Subject: [PATCH 06/60] Move `add_to_ancillary_data` and `AncillaryDataIter` to ancillary.rs --- library/std/src/sys/unix/ext/net/ancillary.rs | 91 ++++++++++++++++++- library/std/src/sys/unix/net.rs | 82 ----------------- 2 files changed, 86 insertions(+), 87 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 7d0f43ab87f81..03fd288b8701f 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -1,12 +1,13 @@ use crate::convert::TryFrom; use crate::io::{self, IoSliceMut}; -use crate::mem; +use crate::marker::PhantomData; +use crate::mem::{size_of, zeroed}; use crate::os::unix::io::RawFd; use crate::path::Path; use crate::ptr::null_mut; use crate::slice::from_raw_parts; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; -use crate::sys::unix::net::{add_to_ancillary_data, AncillaryDataIter, Socket}; +use crate::sys::unix::net::Socket; pub(super) fn recv_vectored_with_ancillary_from( socket: &Socket, @@ -14,11 +15,11 @@ pub(super) fn recv_vectored_with_ancillary_from( ancillary: &mut SocketAncillary<'_>, ) -> io::Result<(usize, bool, io::Result)> { unsafe { - let mut msg_name: libc::sockaddr_un = mem::zeroed(); + let mut msg_name: libc::sockaddr_un = zeroed(); let mut msg = libc::msghdr { msg_name: &mut msg_name as *mut _ as *mut _, - msg_namelen: mem::size_of::() as libc::socklen_t, + msg_namelen: size_of::() as libc::socklen_t, msg_iov: bufs.as_mut_ptr().cast(), msg_iovlen: bufs.len(), msg_control: ancillary.buffer.as_mut_ptr().cast(), @@ -46,7 +47,7 @@ pub(super) fn send_vectored_with_ancillary_to( ) -> io::Result { unsafe { let (mut msg_name, msg_namelen) = - if let Some(path) = path { sockaddr_un(path)? } else { (mem::zeroed(), 0) }; + if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) }; let mut msg = libc::msghdr { msg_name: &mut msg_name as *mut _ as *mut _, @@ -64,6 +65,86 @@ pub(super) fn send_vectored_with_ancillary_to( } } +fn add_to_ancillary_data( + buffer: &mut [u8], + length: &mut usize, + source: &[T], + cmsg_level: libc::c_int, + cmsg_type: libc::c_int, +) -> bool { + let len = (source.len() * size_of::()) 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 +} + +struct AncillaryDataIter<'a, T> { + data: &'a [u8], + phantom: crate::marker::PhantomData, +} + +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 { + unsafe { + let mut unit = zeroed(); + if size_of::() <= self.data.len() { + let unit_ptr: *mut T = &mut unit; + libc::memcpy(unit_ptr.cast(), self.data.as_ptr().cast(), size_of::()); + self.data = &self.data[size_of::()..]; + Some(unit) + } else { + None + } + } + } +} + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] #[derive(Clone)] pub struct UCred(libc::ucred); diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index e067edd377429..1a514ed0238cf 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -1,10 +1,8 @@ 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}; @@ -20,86 +18,6 @@ pub extern crate libc as netc; pub type wrlen_t = size_t; -pub struct AncillaryDataIter<'a, T> { - data: &'a [u8], - phantom: crate::marker::PhantomData, -} - -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 { - unsafe { - let mut unit = mem::zeroed(); - if mem::size_of::() <= self.data.len() { - let unit_ptr: *mut T = &mut unit; - libc::memcpy(unit_ptr.cast(), self.data.as_ptr().cast(), mem::size_of::()); - self.data = &self.data[mem::size_of::()..]; - Some(unit) - } else { - None - } - } - } -} - -pub fn add_to_ancillary_data( - 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::()) 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() {} From b4bc663f3f7ce52cefd01f0d1c3bd76ba3d0fc4b Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 25 Aug 2020 18:09:35 +0200 Subject: [PATCH 07/60] Using `read_unaligned` instead of `memcpy`. --- library/std/src/sys/unix/ext/net/ancillary.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 03fd288b8701f..039cdd8ff91be 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -4,7 +4,7 @@ use crate::marker::PhantomData; use crate::mem::{size_of, zeroed}; use crate::os::unix::io::RawFd; use crate::path::Path; -use crate::ptr::null_mut; +use crate::ptr::{null_mut, read_unaligned}; use crate::slice::from_raw_parts; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; use crate::sys::unix::net::Socket; @@ -131,16 +131,14 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { type Item = T; fn next(&mut self) -> Option { - unsafe { - let mut unit = zeroed(); - if size_of::() <= self.data.len() { - let unit_ptr: *mut T = &mut unit; - libc::memcpy(unit_ptr.cast(), self.data.as_ptr().cast(), size_of::()); + if size_of::() <= self.data.len() { + unsafe { + let unit = read_unaligned(self.data.as_ptr().cast()); self.data = &self.data[size_of::()..]; Some(unit) - } else { - None } + } else { + None } } } From 383aaac9208f75bc0b2ebaca1b93274d34a47ad3 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 25 Aug 2020 18:14:10 +0200 Subject: [PATCH 08/60] Replace `TryFrom` of `AncillaryData` with a private method. --- library/std/src/sys/unix/ext/net/ancillary.rs | 41 ++++++++----------- 1 file changed, 18 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 039cdd8ff91be..142526f3a4197 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -349,29 +349,24 @@ impl<'a> AncillaryData<'a> { 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> TryFrom<&'a libc::cmsghdr> for AncillaryData<'a> { - type Error = AncillaryError; - - fn try_from(cmsg: &'a libc::cmsghdr) -> Result { + #[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 try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result { unsafe { let cmsg_len_zero = libc::CMSG_LEN(0) as usize; let data_len = (*cmsg).cmsg_len - cmsg_len_zero; @@ -472,7 +467,7 @@ impl<'a> Iterator for Messages<'a> { let cmsg = cmsg.as_ref()?; self.current = Some(cmsg); - let ancillary_result = AncillaryData::try_from(cmsg); + let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg); Some(ancillary_result) } } From 83cb07505c3f907c46982ea880ca7002cd5c449f Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 25 Aug 2020 18:38:25 +0200 Subject: [PATCH 09/60] Add integer overflow check --- library/std/src/sys/unix/ext/net/ancillary.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 142526f3a4197..8ba389762fbfe 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -72,7 +72,15 @@ fn add_to_ancillary_data( cmsg_level: libc::c_int, cmsg_type: libc::c_int, ) -> bool { - let len = (source.len() * size_of::()) as u32; + let len = if let Some(len) = source.len().checked_mul(size_of::()) { + if let Ok(len) = u32::try_from(len) { + len + } else { + return false; + } + } else { + return false; + }; unsafe { let additional_space = libc::CMSG_SPACE(len) as usize; From 24938eeb554f86d2264db7629313bb2fcfec7d8d Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 25 Aug 2020 18:43:41 +0200 Subject: [PATCH 10/60] Remove `Clone` trait bound in `add_to_ancillary_data` --- library/std/src/sys/unix/ext/net/ancillary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 8ba389762fbfe..6175c0ae34317 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -65,7 +65,7 @@ pub(super) fn send_vectored_with_ancillary_to( } } -fn add_to_ancillary_data( +fn add_to_ancillary_data( buffer: &mut [u8], length: &mut usize, source: &[T], From acd7dbe988e1665127a34945729bd6892e0b4d7e Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 25 Aug 2020 18:48:27 +0200 Subject: [PATCH 11/60] Remove lifetime annotation in `messages` function --- library/std/src/sys/unix/ext/net/ancillary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 6175c0ae34317..8c61c8dec5444 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -564,7 +564,7 @@ impl<'a> SocketAncillary<'a> { target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn messages(&'a self) -> Messages<'a> { + pub fn messages(&self) -> Messages<'_> { Messages { buffer: &self.buffer[..self.length], current: None } } From 5bf5db95e142f258a03d88817d6a2ece8cc8053e Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 25 Aug 2020 19:33:33 +0200 Subject: [PATCH 12/60] Remove inner function in `bind`, `connect` and `send_to` --- library/std/src/sys/unix/ext/net/datagram.rs | 52 ++++++++------------ library/std/src/sys/unix/ext/net/listener.rs | 15 +++--- library/std/src/sys/unix/ext/net/stream.rs | 15 +++--- 3 files changed, 33 insertions(+), 49 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index e2fa65572e1e5..7225b3e5f66d3 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -85,17 +85,14 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let socket = UnixDatagram::unbound()?; - let (addr, len) = sockaddr_un(path)?; + unsafe { + let socket = UnixDatagram::unbound()?; + let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; + cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; - Ok(socket) - } + Ok(socket) } - inner(path.as_ref()) } /// Creates a Unix Datagram socket which is not bound to any address. @@ -170,16 +167,12 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn connect>(&self, path: P) -> io::Result<()> { - fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?; + unsafe { + let (addr, len) = sockaddr_un(path.as_ref())?; - Ok(()) - } + cvt(libc::connect(*self.0.as_inner(), &addr as *const _ as *const _, len))?; } - inner(self, path.as_ref()) + Ok(()) } /// Creates a new independently owned handle to the underlying socket. @@ -430,22 +423,19 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { - fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - let count = cvt(libc::sendto( - *d.0.as_inner(), - buf.as_ptr() as *const _, - buf.len(), - MSG_NOSIGNAL, - &addr as *const _ as *const _, - len, - ))?; - Ok(count as usize) - } + unsafe { + let (addr, len) = sockaddr_un(path.as_ref())?; + + let count = cvt(libc::sendto( + *self.0.as_inner(), + buf.as_ptr() as *const _, + buf.len(), + MSG_NOSIGNAL, + &addr as *const _ as *const _, + len, + ))?; + Ok(count as usize) } - inner(self, buf, path.as_ref()) } /// Sends data on the socket to the socket's peer. diff --git a/library/std/src/sys/unix/ext/net/listener.rs b/library/std/src/sys/unix/ext/net/listener.rs index 84386ea6381c1..2bedfb74dcb60 100644 --- a/library/std/src/sys/unix/ext/net/listener.rs +++ b/library/std/src/sys/unix/ext/net/listener.rs @@ -71,18 +71,15 @@ impl UnixListener { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; - cvt(libc::listen(*inner.as_inner(), 128))?; + cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; + cvt(libc::listen(*inner.as_inner(), 128))?; - Ok(UnixListener(inner)) - } + Ok(UnixListener(inner)) } - inner(path.as_ref()) } /// Accepts a new incoming connection to this listener. diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index d144c41de3c81..091026d6cfc77 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -87,16 +87,13 @@ impl UnixStream { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn connect>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; - Ok(UnixStream(inner)) - } + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path.as_ref())?; + + cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; + Ok(UnixStream(inner)) } - inner(path.as_ref()) } /// Creates an unnamed pair of connected sockets. From 7106d764207f6c70865cf14e54cabd06a3db40c5 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Thu, 27 Aug 2020 16:03:41 +0200 Subject: [PATCH 13/60] Use `fill` instead of `memset` --- library/std/src/lib.rs | 1 + library/std/src/sys/unix/ext/net/ancillary.rs | 25 ++++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 70533189d8e0b..2a390533f17f2 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -295,6 +295,7 @@ #![feature(rustc_private)] #![feature(shrink_to)] #![feature(slice_concat_ext)] +#![feature(slice_fill)] #![feature(slice_internals)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 8c61c8dec5444..4f821a12e12ee 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -72,9 +72,9 @@ fn add_to_ancillary_data( cmsg_level: libc::c_int, cmsg_type: libc::c_int, ) -> bool { - let len = if let Some(len) = source.len().checked_mul(size_of::()) { - if let Ok(len) = u32::try_from(len) { - len + let source_len = if let Some(source_len) = source.len().checked_mul(size_of::()) { + if let Ok(source_len) = u32::try_from(source_len) { + source_len } else { return false; } @@ -83,14 +83,21 @@ fn add_to_ancillary_data( }; unsafe { - let additional_space = libc::CMSG_SPACE(len) as usize; - if *length + additional_space > buffer.len() { + let additional_space = libc::CMSG_SPACE(source_len) as usize; + + let new_length = if let Some(new_length) = additional_space.checked_add(*length) { + new_length + } else { + return false; + }; + + if new_length > buffer.len() { return false; } - libc::memset(buffer[*length..].as_mut_ptr().cast(), 0, additional_space); + buffer[*length..new_length].fill(0); - *length += additional_space; + *length = new_length; let msg = libc::msghdr { msg_name: null_mut(), @@ -115,11 +122,11 @@ fn add_to_ancillary_data( (*previous_cmsg).cmsg_level = cmsg_level; (*previous_cmsg).cmsg_type = cmsg_type; - (*previous_cmsg).cmsg_len = libc::CMSG_LEN(len) as usize; + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as usize; let data = libc::CMSG_DATA(previous_cmsg).cast(); - libc::memcpy(data, source.as_ptr().cast(), len as usize); + libc::memcpy(data, source.as_ptr().cast(), source_len as usize); } true } From 09688530414bc76c79e06686d203c5eb6c1c4e69 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Thu, 27 Aug 2020 16:09:57 +0200 Subject: [PATCH 14/60] Remove unnecessary path --- library/std/src/sys/unix/ext/net/ancillary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 4f821a12e12ee..84a73ef8afd53 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -133,7 +133,7 @@ fn add_to_ancillary_data( struct AncillaryDataIter<'a, T> { data: &'a [u8], - phantom: crate::marker::PhantomData, + phantom: PhantomData, } impl<'a, T> AncillaryDataIter<'a, T> { From 1f3f10a414a6fe5c74f2c3daed45575b3e2af354 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Fri, 28 Aug 2020 18:41:48 +0200 Subject: [PATCH 15/60] Move conditional compilation to the upper module and sort the target OS list alphabetically --- library/std/src/sys/unix/ext/net/ancillary.rs | 260 +++++------------- library/std/src/sys/unix/ext/net/datagram.rs | 48 ++++ library/std/src/sys/unix/ext/net/mod.rs | 32 +++ library/std/src/sys/unix/ext/net/stream.rs | 48 ++++ 4 files changed, 199 insertions(+), 189 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 84a73ef8afd53..1da3370b07d35 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -158,10 +158,36 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { } } +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", +))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] #[derive(Clone)] pub struct UCred(libc::ucred); +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", +))] impl UCred { #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn new() -> UCred { @@ -199,41 +225,9 @@ impl UCred { } } -#[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; @@ -244,32 +238,32 @@ impl<'a> Iterator for 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 = "dragonfly", target_os = "emscripten", + target_os = "freebsd", target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", 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 = "dragonfly", target_os = "emscripten", + target_os = "freebsd", target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] @@ -288,58 +282,26 @@ pub enum AncillaryError { Unknown { cmsg_level: i32, cmsg_type: i32 }, } -#[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 = "dragonfly", target_os = "emscripten", + target_os = "freebsd", target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", 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); @@ -347,16 +309,16 @@ impl<'a> AncillaryData<'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 = "dragonfly", target_os = "emscripten", + target_os = "freebsd", target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", target_env = "uclibc", ))] fn as_credentials(data: &'a [u8]) -> Self { @@ -365,22 +327,6 @@ impl<'a> AncillaryData<'a> { 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", - ))] fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result { unsafe { let cmsg_len_zero = libc::CMSG_LEN(0) as usize; @@ -392,20 +338,20 @@ impl<'a> AncillaryData<'a> { libc::SOL_SOCKET => match (*cmsg).cmsg_type { libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)), #[cfg(any( - target_os = "linux", target_os = "android", target_os = "emscripten", target_os = "fuchsia", + target_os = "linux", target_env = "uclibc", ))] libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)), #[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", target_os = "dragonfly", - target_os = "macos", + target_os = "freebsd", target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", ))] libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)), cmsg_type => { @@ -420,44 +366,12 @@ 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", -))] #[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 = Result, AncillaryError>; @@ -554,22 +468,6 @@ impl<'a> SocketAncillary<'a> { 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(&self) -> Messages<'_> { Messages { buffer: &self.buffer[..self.length], current: None } @@ -631,22 +529,6 @@ impl<'a> SocketAncillary<'a> { /// 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; @@ -667,16 +549,16 @@ impl<'a> SocketAncillary<'a> { /// 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 = "dragonfly", target_os = "emscripten", + target_os = "freebsd", target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] @@ -688,20 +570,20 @@ impl<'a> SocketAncillary<'a> { creds, libc::SOL_SOCKET, #[cfg(any( - target_os = "linux", target_os = "android", target_os = "emscripten", target_os = "fuchsia", + target_os = "linux", 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 = "freebsd", target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", ))] libc::SCM_CREDS, ) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 7225b3e5f66d3..5df45e6465b46 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -4,6 +4,22 @@ use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::Path; use crate::sys::unix::cvt; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", +))] use crate::sys::unix::ext::net::ancillary::{ recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, }; @@ -346,6 +362,22 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", + ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn recv_vectored_with_ancillary_from( &self, @@ -394,6 +426,22 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", + ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn recv_vectored_with_ancillary( &self, diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs index 93b72df520aa3..125432b2b711d 100644 --- a/library/std/src/sys/unix/ext/net/mod.rs +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -3,6 +3,22 @@ #![stable(feature = "unix_socket", since = "1.10.0")] mod addr; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", +))] mod ancillary; mod datagram; mod listener; @@ -13,6 +29,22 @@ mod test; #[stable(feature = "unix_socket", since = "1.10.0")] pub use self::addr::*; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", +))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub use self::ancillary::*; #[stable(feature = "unix_socket", since = "1.10.0")] diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 091026d6cfc77..907832399d84d 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -16,6 +16,22 @@ use crate::path::Path; use crate::sys::cvt; use crate::sys::net::Socket; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", +))] use crate::sys::unix::ext::net::ancillary::{ recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, }; @@ -458,6 +474,22 @@ impl UnixStream { /// Ok(()) /// } /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", + ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn recv_vectored_with_ancillary( &self, @@ -498,6 +530,22 @@ impl UnixStream { /// Ok(()) /// } /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", + ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn send_vectored_with_ancillary( &self, From 748d31068797d88caadbd8639784588161eb3c11 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Fri, 28 Aug 2020 19:15:53 +0200 Subject: [PATCH 16/60] Reduce impl trait by using macro in `raw_fd.rs` --- library/std/src/sys/unix/ext/net/raw_fd.rs | 95 ++++++++-------------- 1 file changed, 34 insertions(+), 61 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/raw_fd.rs b/library/std/src/sys/unix/ext/net/raw_fd.rs index 059c0fec06f2f..c42fee4c73bcd 100644 --- a/library/std/src/sys/unix/ext/net/raw_fd.rs +++ b/library/std/src/sys/unix/ext/net/raw_fd.rs @@ -2,66 +2,39 @@ use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys_common::{self, AsInner, FromInner, IntoInner}; use crate::{net, sys}; -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} +macro_rules! impl_as_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "rust1", since = "1.0.0")] + impl AsRawFd for net::$t { + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } + } + )*}; +} +impl_as_raw_fd! { TcpStream TcpListener UdpSocket } -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} +macro_rules! impl_from_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "from_raw_os", since = "1.1.0")] + impl FromRawFd for net::$t { + unsafe fn from_raw_fd(fd: RawFd) -> net::$t { + let socket = sys::net::Socket::from_inner(fd); + net::$t::from_inner(sys_common::net::$t::from_inner(socket)) + } + } + )*}; +} +impl_from_raw_fd! { TcpStream TcpListener UdpSocket } -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let socket = sys::net::Socket::from_inner(fd); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let socket = sys::net::Socket::from_inner(fd); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpStream { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpListener { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::UdpSocket { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} +macro_rules! impl_into_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "into_raw_os", since = "1.4.0")] + impl IntoRawFd for net::$t { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } + } + )*}; +} +impl_into_raw_fd! { TcpStream TcpListener UdpSocket } From f947d2f493dcefbf263f1305e27e4ee67a721ad0 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 29 Aug 2020 19:22:03 +0200 Subject: [PATCH 17/60] Add doc(cfg(...)) --- library/std/src/sys/unix/ext/net/ancillary.rs | 7 +++++++ library/std/src/sys/unix/ext/net/mod.rs | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 1da3370b07d35..eba884ad8b48f 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -159,6 +159,7 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { } #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", @@ -176,6 +177,7 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { pub struct UCred(libc::ucred); #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", @@ -238,6 +240,7 @@ impl<'a> Iterator for ScmRights<'a> { } #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", @@ -254,6 +257,7 @@ impl<'a> Iterator for ScmRights<'a> { pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", @@ -286,6 +290,7 @@ pub enum AncillaryError { pub enum AncillaryData<'a> { ScmRights(ScmRights<'a>), #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", @@ -309,6 +314,7 @@ impl<'a> AncillaryData<'a> { } #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", @@ -549,6 +555,7 @@ impl<'a> SocketAncillary<'a> { /// and type `SCM_CREDENTIALS`. /// #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs index 125432b2b711d..d1c943b4f2f1b 100644 --- a/library/std/src/sys/unix/ext/net/mod.rs +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -3,7 +3,24 @@ #![stable(feature = "unix_socket", since = "1.10.0")] mod addr; +#[doc(cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", +)))] #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", From e66b92189535a648f82a6f8ff0b23ee1fac3ecdb Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 29 Aug 2020 20:03:18 +0200 Subject: [PATCH 18/60] Add doc comments --- library/std/src/sys/unix/ext/net/ancillary.rs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index eba884ad8b48f..bfca7ae4a9b8c 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -158,6 +158,7 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { } } +/// Unix credential. #[cfg(any( doc, target_os = "android", @@ -191,42 +192,54 @@ pub struct UCred(libc::ucred); target_env = "uclibc", ))] impl UCred { + /// Create a Unix credential struct. + /// + /// PID, UID and GID is set to 0. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn new() -> UCred { UCred(libc::ucred { pid: 0, uid: 0, gid: 0 }) } + /// Set the PID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn set_pid(&mut self, pid: i32) { self.0.pid = pid; } + /// Get the current PID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn get_pid(&self) -> i32 { self.0.pid } + /// Set the UID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn set_uid(&mut self, uid: u32) { self.0.uid = uid; } + /// Get the current UID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn get_uid(&self) -> u32 { self.0.uid } + /// Set the GID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn set_gid(&mut self, gid: u32) { self.0.gid = gid; } + /// Get the current GID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn get_gid(&self) -> u32 { self.0.gid } } +/// This control message contains file descriptors. +/// +/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>); @@ -239,6 +252,9 @@ impl<'a> Iterator for ScmRights<'a> { } } +/// This control message contains unix credentials. +/// +/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`. #[cfg(any( doc, target_os = "android", @@ -279,6 +295,7 @@ impl<'a> Iterator for ScmCredentials<'a> { } } +/// The error type which is returned from parsing the type a control message. #[non_exhaustive] #[derive(Debug)] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] @@ -286,6 +303,7 @@ pub enum AncillaryError { Unknown { cmsg_level: i32, cmsg_type: i32 }, } +/// This enum represent one control message of variable type. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub enum AncillaryData<'a> { ScmRights(ScmRights<'a>), @@ -372,6 +390,7 @@ impl<'a> AncillaryData<'a> { } } +/// This struct is used to iterate through the control messages. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub struct Messages<'a> { buffer: &'a [u8], @@ -474,6 +493,7 @@ impl<'a> SocketAncillary<'a> { self.length } + /// Returns the iterator of the control messages. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn messages(&self) -> Messages<'_> { Messages { buffer: &self.buffer[..self.length], current: None } @@ -552,7 +572,7 @@ impl<'a> SocketAncillary<'a> { /// 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`. + /// and type `SCM_CREDENTIALS` or `SCM_CREDS`. /// #[cfg(any( doc, From ab469ba02a42ff741c08ac605224cae17323e007 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 1 Sep 2020 16:32:13 +0200 Subject: [PATCH 19/60] Rename `test.rs` to `tests.rs` --- library/std/src/sys/unix/ext/net/mod.rs | 2 +- library/std/src/sys/unix/ext/net/test.rs | 613 ---------------------- library/std/src/sys/unix/ext/net/tests.rs | 29 +- 3 files changed, 19 insertions(+), 625 deletions(-) delete mode 100644 library/std/src/sys/unix/ext/net/test.rs diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs index d1c943b4f2f1b..c37e856e5bc22 100644 --- a/library/std/src/sys/unix/ext/net/mod.rs +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -42,7 +42,7 @@ mod listener; mod raw_fd; mod stream; #[cfg(all(test, not(target_os = "emscripten")))] -mod test; +mod tests; #[stable(feature = "unix_socket", since = "1.10.0")] pub use self::addr::*; diff --git a/library/std/src/sys/unix/ext/net/test.rs b/library/std/src/sys/unix/ext/net/test.rs deleted file mode 100644 index a39b97f2c31b9..0000000000000 --- a/library/std/src/sys/unix/ext/net/test.rs +++ /dev/null @@ -1,613 +0,0 @@ -use super::*; -use crate::io::prelude::*; -use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; -use crate::iter::FromIterator; -use crate::mem; -use crate::sys::unix::ext::io::AsRawFd; -use crate::sys_common::io::test::tmpdir; -use crate::thread; -use crate::time::Duration; - -macro_rules! or_panic { - ($e:expr) => { - match $e { - Ok(e) => e, - Err(e) => panic!("{}", e), - } - }; -} - -#[test] -fn basic() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - let msg1 = b"hello"; - let msg2 = b"world!"; - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let thread = thread::spawn(move || { - let mut stream = or_panic!(listener.accept()).0; - let mut buf = [0; 5]; - or_panic!(stream.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(stream.write_all(msg2)); - }); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname()); - or_panic!(stream.write_all(msg1)); - let mut buf = vec![]; - or_panic!(stream.read_to_end(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(stream); - - thread.join().unwrap(); -} - -#[test] -fn vectored() { - let (mut s1, mut s2) = or_panic!(UnixStream::pair()); - - let len = or_panic!(s1.write_vectored(&[ - IoSlice::new(b"hello"), - IoSlice::new(b" "), - IoSlice::new(b"world!") - ],)); - assert_eq!(len, 12); - - let mut buf1 = [0; 6]; - let mut buf2 = [0; 7]; - let len = - or_panic!(s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)); - assert_eq!(len, 12); - assert_eq!(&buf1, b"hello "); - assert_eq!(&buf2, b"world!\0"); -} - -#[test] -fn pair() { - let msg1 = b"hello"; - let msg2 = b"world!"; - - let (mut s1, mut s2) = or_panic!(UnixStream::pair()); - let thread = thread::spawn(move || { - // s1 must be moved in or the test will hang! - let mut buf = [0; 5]; - or_panic!(s1.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(s1.write_all(msg2)); - }); - - or_panic!(s2.write_all(msg1)); - let mut buf = vec![]; - or_panic!(s2.read_to_end(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(s2); - - thread.join().unwrap(); -} - -#[test] -fn try_clone() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - let msg1 = b"hello"; - let msg2 = b"world"; - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let thread = thread::spawn(move || { - let mut stream = or_panic!(listener.accept()).0; - or_panic!(stream.write_all(msg1)); - or_panic!(stream.write_all(msg2)); - }); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - let mut stream2 = or_panic!(stream.try_clone()); - - let mut buf = [0; 5]; - or_panic!(stream.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(stream2.read(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - - thread.join().unwrap(); -} - -#[test] -fn iter() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let thread = thread::spawn(move || { - for stream in listener.incoming().take(2) { - let mut stream = or_panic!(stream); - let mut buf = [0]; - or_panic!(stream.read(&mut buf)); - } - }); - - for _ in 0..2 { - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.write_all(&[0])); - } - - thread.join().unwrap(); -} - -#[test] -fn long_path() { - let dir = tmpdir(); - let socket_path = dir.path().join( - "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\ - sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf", - ); - match UnixStream::connect(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } - - match UnixListener::bind(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } - - match UnixDatagram::bind(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } -} - -#[test] -fn timeouts() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let _listener = or_panic!(UnixListener::bind(&socket_path)); - - let stream = or_panic!(UnixStream::connect(&socket_path)); - let dur = Duration::new(15410, 0); - - assert_eq!(None, or_panic!(stream.read_timeout())); - - or_panic!(stream.set_read_timeout(Some(dur))); - assert_eq!(Some(dur), or_panic!(stream.read_timeout())); - - assert_eq!(None, or_panic!(stream.write_timeout())); - - or_panic!(stream.set_write_timeout(Some(dur))); - assert_eq!(Some(dur), or_panic!(stream.write_timeout())); - - or_panic!(stream.set_read_timeout(None)); - assert_eq!(None, or_panic!(stream.read_timeout())); - - or_panic!(stream.set_write_timeout(None)); - assert_eq!(None, or_panic!(stream.write_timeout())); -} - -#[test] -fn test_read_timeout() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let _listener = or_panic!(UnixListener::bind(&socket_path)); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut buf = [0; 10]; - let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); -} - -#[test] -fn test_read_with_timeout() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut other_end = or_panic!(listener.accept()).0; - or_panic!(other_end.write_all(b"hello world")); - - let mut buf = [0; 11]; - or_panic!(stream.read(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - - let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); -} - -// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors -// when passed zero Durations -#[test] -fn test_unix_stream_timeout_zero_duration() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let stream = or_panic!(UnixStream::connect(&socket_path)); - - let result = stream.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = stream.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - drop(listener); -} - -#[test] -fn test_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - let path2 = dir.path().join("sock2"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::bind(&path2)); - - let msg = b"hello world"; - or_panic!(sock1.send_to(msg, &path2)); - let mut buf = [0; 11]; - or_panic!(sock2.recv_from(&mut buf)); - assert_eq!(msg, &buf[..]); -} - -#[test] -fn test_unnamed_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - - let msg = b"hello world"; - or_panic!(sock2.send_to(msg, &path1)); - let mut buf = [0; 11]; - let (usize, addr) = or_panic!(sock1.recv_from(&mut buf)); - assert_eq!(usize, 11); - assert!(addr.is_unnamed()); - assert_eq!(msg, &buf[..]); -} - -#[test] -fn test_connect_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 sock = or_panic!(UnixDatagram::unbound()); - or_panic!(sock.connect(&path1)); - - // Check send() - let msg = b"hello there"; - or_panic!(sock.send(msg)); - let mut buf = [0; 11]; - let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf)); - assert_eq!(usize, 11); - assert!(addr.is_unnamed()); - assert_eq!(msg, &buf[..]); - - // Changing default socket works too - or_panic!(sock.connect(&path2)); - or_panic!(sock.send(msg)); - or_panic!(bsock2.recv_from(&mut buf)); -} - -#[test] -fn test_unix_datagram_recv() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - or_panic!(sock2.connect(&path1)); - - let msg = b"hello world"; - or_panic!(sock2.send(msg)); - let mut buf = [0; 11]; - let size = or_panic!(sock1.recv(&mut buf)); - assert_eq!(size, 11); - assert_eq!(msg, &buf[..]); -} - -#[test] -fn datagram_pair() { - let msg1 = b"hello"; - let msg2 = b"world!"; - - let (s1, s2) = or_panic!(UnixDatagram::pair()); - let thread = thread::spawn(move || { - // s1 must be moved in or the test will hang! - let mut buf = [0; 5]; - or_panic!(s1.recv(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(s1.send(msg2)); - }); - - or_panic!(s2.send(msg1)); - let mut buf = [0; 6]; - or_panic!(s2.recv(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(s2); - - thread.join().unwrap(); -} - -// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors -// when passed zero Durations -#[test] -fn test_unix_datagram_timeout_zero_duration() { - let dir = tmpdir(); - let path = dir.path().join("sock"); - - let datagram = or_panic!(UnixDatagram::bind(&path)); - - let result = datagram.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = datagram.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); -} - -#[test] -fn abstract_namespace_not_allowed() { - assert!(UnixStream::connect("\0asdf").is_err()); -} - -#[test] -fn test_unix_stream_peek() { - let (txdone, rxdone) = crate::sync::mpsc::channel(); - - let dir = tmpdir(); - let path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&path)); - let thread = thread::spawn(move || { - let mut stream = or_panic!(listener.accept()).0; - or_panic!(stream.write_all(&[1, 3, 3, 7])); - or_panic!(rxdone.recv()); - }); - - let mut stream = or_panic!(UnixStream::connect(&path)); - let mut buf = [0; 10]; - for _ in 0..2 { - assert_eq!(or_panic!(stream.peek(&mut buf)), 4); - } - assert_eq!(or_panic!(stream.read(&mut buf)), 4); - - or_panic!(stream.set_nonblocking(true)); - match stream.peek(&mut buf) { - Ok(_) => panic!("expected error"), - Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error: {}", e), - } - - or_panic!(txdone.send(())); - thread.join().unwrap(); -} - -#[test] -fn test_unix_datagram_peek() { - let dir = tmpdir(); - let path1 = dir.path().join("sock"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - or_panic!(sock2.connect(&path1)); - - let msg = b"hello world"; - or_panic!(sock2.send(msg)); - for _ in 0..2 { - let mut buf = [0; 11]; - let size = or_panic!(sock1.peek(&mut buf)); - assert_eq!(size, 11); - assert_eq!(msg, &buf[..]); - } - - let mut buf = [0; 11]; - let size = or_panic!(sock1.recv(&mut buf)); - assert_eq!(size, 11); - assert_eq!(msg, &buf[..]); -} - -#[test] -fn test_unix_datagram_peek_from() { - let dir = tmpdir(); - let path1 = dir.path().join("sock"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - or_panic!(sock2.connect(&path1)); - - let msg = b"hello world"; - or_panic!(sock2.send(msg)); - for _ in 0..2 { - let mut buf = [0; 11]; - let (size, _) = or_panic!(sock1.peek_from(&mut buf)); - assert_eq!(size, 11); - assert_eq!(msg, &buf[..]); - } - - let mut buf = [0; 11]; - let size = or_panic!(sock1.recv(&mut buf)); - 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().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::() 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 mut cred1 = UCred::new(); - cred1.set_pid(getpid()); - cred1.set_uid(getuid()); - cred1.set_gid(getgid()); - assert!(ancillary1.add_creds(&[cred1.clone()][..])); - - 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().unwrap() - { - let cred_vec = Vec::from_iter(scm_credentials); - assert_eq!(cred_vec.len(), 1); - assert_eq!(cred1.get_pid(), cred_vec[0].get_pid()); - assert_eq!(cred1.get_uid(), cred_vec[0].get_uid()); - assert_eq!(cred1.get_gid(), cred_vec[0].get_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().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/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index a4ca81c1c22e0..a39b97f2c31b9 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -1,11 +1,13 @@ +use super::*; use crate::io::prelude::*; -use crate::io::{self, ErrorKind}; +use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; +use crate::iter::FromIterator; +use crate::mem; +use crate::sys::unix::ext::io::AsRawFd; use crate::sys_common::io::test::tmpdir; use crate::thread; use crate::time::Duration; -use super::*; - macro_rules! or_panic { ($e:expr) => { match $e { @@ -479,7 +481,7 @@ fn test_send_vectored_fds_unix_stream() { 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() { + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { let fd_vec = Vec::from_iter(scm_rights); assert_eq!(fd_vec.len(), 1); unsafe { @@ -527,8 +529,11 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { 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 mut cred1 = UCred::new(); + cred1.set_pid(getpid()); + cred1.set_uid(getuid()); + cred1.set_gid(getgid()); + assert!(ancillary1.add_creds(&[cred1.clone()][..])); let usize = or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2)); @@ -549,12 +554,14 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { 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() { + if let AncillaryData::ScmCredentials(scm_credentials) = + ancillary_data_vec.pop().unwrap().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); + assert_eq!(cred1.get_pid(), cred_vec[0].get_pid()); + assert_eq!(cred1.get_uid(), cred_vec[0].get_uid()); + assert_eq!(cred1.get_gid(), cred_vec[0].get_gid()); } else { assert!(false); } @@ -594,7 +601,7 @@ fn test_send_vectored_with_ancillary_unix_datagram() { 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() { + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { let fd_vec = Vec::from_iter(scm_rights); assert_eq!(fd_vec.len(), 1); unsafe { From dce9b21aa18a78d506a29dc9fdc93103223103e9 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Mon, 7 Sep 2020 18:00:01 +0200 Subject: [PATCH 20/60] Add `set_passcred` and `passcred` methods to `UnixStream` and `UnixDatagram` --- library/std/src/sys/unix/ext/net/datagram.rs | 60 ++++++++++++++++++++ library/std/src/sys/unix/ext/net/stream.rs | 60 ++++++++++++++++++++ library/std/src/sys/unix/ext/net/tests.rs | 12 +--- library/std/src/sys/unix/net.rs | 10 ++++ 4 files changed, 131 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 5df45e6465b46..e5309e54e7950 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -735,6 +735,66 @@ impl UnixDatagram { self.0.set_nonblocking(nonblocking) } + /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`]. + /// + /// Set the socket option `SO_PASSCRED`. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_passcred(true).expect("set_passcred function failed"); + /// Ok(()) + /// } + /// ``` + #[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { + self.0.set_passcred(passcred) + } + + /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`]. + /// This value can be change by [`set_passcred`]. + /// + /// Get the socket option `SO_PASSCRED`. + /// + /// [`set_passcred`]: UnixDatagram::set_passcred + #[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn passcred(&self) -> io::Result { + self.0.passcred() + } + /// Returns the value of the `SO_ERROR` option. /// /// # Examples diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 907832399d84d..68e8429dd3b26 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -366,6 +366,66 @@ impl UnixStream { self.0.set_nonblocking(nonblocking) } + /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`]. + /// + /// Set the socket option `SO_PASSCRED`. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_passcred(true).expect("Couldn't set passcred"); + /// Ok(()) + /// } + /// ``` + #[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { + self.0.set_passcred(passcred) + } + + /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`]. + /// This value can be change by [`set_passcred`]. + /// + /// Get the socket option `SO_PASSCRED`. + /// + /// [`set_passcred`]: UnixStream::set_passcred + #[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn passcred(&self) -> io::Result { + self.0.passcred() + } + /// Returns the value of the `SO_ERROR` option. /// /// # Examples diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index a39b97f2c31b9..db6a972e7d2dc 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -2,7 +2,6 @@ use super::*; use crate::io::prelude::*; use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; use crate::iter::FromIterator; -use crate::mem; use crate::sys::unix::ext::io::AsRawFd; use crate::sys_common::io::test::tmpdir; use crate::thread; @@ -513,16 +512,7 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { 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::() as u32, - ); - } + or_panic!(bsock2.set_passcred(true)); let mut buf1 = [1; 8]; let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 1a514ed0238cf..c01d2fa5f23e2 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -323,6 +323,16 @@ impl Socket { Ok(raw != 0) } + pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { + let boolean: libc::c_int = if passcred { 1 } else { 0 }; + setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, boolean) + } + + pub fn passcred(&self) -> io::Result { + let passcred: libc::c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)?; + Ok(passcred != 0) + } + #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let mut nonblocking = nonblocking as libc::c_int; From 031521a62460e457c0ebe9b4c67d297bea711c6c Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 12 Sep 2020 15:37:02 +0200 Subject: [PATCH 21/60] Change API to unsafe and add doc comments --- library/std/src/sys/unix/ext/net/ancillary.rs | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index bfca7ae4a9b8c..d41984a532b64 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -137,7 +137,12 @@ struct AncillaryDataIter<'a, T> { } impl<'a, T> AncillaryDataIter<'a, T> { - pub fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> { + /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message. + /// + /// # Safety + /// + /// `data` must contain a valid control message. + unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> { AncillaryDataIter { data, phantom: PhantomData } } } @@ -325,12 +330,24 @@ pub enum AncillaryData<'a> { } impl<'a> AncillaryData<'a> { - fn as_rights(data: &'a [u8]) -> Self { + /// Create a `AncillaryData::ScmRights` variant. + /// + /// # Safety + /// + /// `data` must contain a valid control message and the control message must be type of + /// `SOL_SOCKET` and level of `SCM_RIGHTS`. + unsafe 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) } + /// Create a `AncillaryData::ScmCredentials` variant. + /// + /// # Safety + /// + /// `data` must contain a valid control message and the control message must be type of + /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`. #[cfg(any( doc, target_os = "android", @@ -345,7 +362,7 @@ impl<'a> AncillaryData<'a> { target_os = "openbsd", target_env = "uclibc", ))] - fn as_credentials(data: &'a [u8]) -> Self { + unsafe 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) From e78467b62b8c052ab61262650354d90cc81a1810 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Wed, 16 Sep 2020 20:30:59 +0200 Subject: [PATCH 22/60] Change name of struct to SocketCred --- library/std/src/sys/unix/ext/net/ancillary.rs | 16 ++++++++-------- library/std/src/sys/unix/ext/net/tests.rs | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index d41984a532b64..8dc74062fdfbb 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -180,7 +180,7 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] #[derive(Clone)] -pub struct UCred(libc::ucred); +pub struct SocketCred(libc::ucred); #[cfg(any( doc, @@ -196,13 +196,13 @@ pub struct UCred(libc::ucred); target_os = "openbsd", target_env = "uclibc", ))] -impl UCred { +impl SocketCred { /// Create a Unix credential struct. /// /// PID, UID and GID is set to 0. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn new() -> UCred { - UCred(libc::ucred { pid: 0, uid: 0, gid: 0 }) + pub fn new() -> SocketCred { + SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 }) } /// Set the PID. @@ -293,10 +293,10 @@ pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] impl<'a> Iterator for ScmCredentials<'a> { - type Item = UCred; + type Item = SocketCred; - fn next(&mut self) -> Option { - Some(UCred(self.0.next()?)) + fn next(&mut self) -> Option { + Some(SocketCred(self.0.next()?)) } } @@ -606,7 +606,7 @@ impl<'a> SocketAncillary<'a> { target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn add_creds(&mut self, creds: &[UCred]) -> bool { + pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool { self.truncated = false; add_to_ancillary_data( &mut self.buffer, diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index db6a972e7d2dc..16915a4cc1efc 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -519,7 +519,7 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { let mut ancillary1_buffer = [0; 128]; let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); - let mut cred1 = UCred::new(); + let mut cred1 = SocketCred::new(); cred1.set_pid(getpid()); cred1.set_uid(getuid()); cred1.set_gid(getgid()); From 263f0b2fc37e9306774aeb69179ee1453fd9a5cb Mon Sep 17 00:00:00 2001 From: LinkTed Date: Wed, 16 Sep 2020 20:37:47 +0200 Subject: [PATCH 23/60] Change standard types to libc types --- library/std/src/sys/unix/ext/net/ancillary.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 8dc74062fdfbb..d8c2939cd8b50 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -9,6 +9,8 @@ use crate::slice::from_raw_parts; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; use crate::sys::unix::net::Socket; +use libc::{gid_t, pid_t, uid_t}; + pub(super) fn recv_vectored_with_ancillary_from( socket: &Socket, bufs: &mut [IoSliceMut<'_>], @@ -207,37 +209,37 @@ impl SocketCred { /// Set the PID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn set_pid(&mut self, pid: i32) { + pub fn set_pid(&mut self, pid: pid_t) { self.0.pid = pid; } /// Get the current PID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn get_pid(&self) -> i32 { + pub fn get_pid(&self) -> pid_t { self.0.pid } /// Set the UID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn set_uid(&mut self, uid: u32) { + pub fn set_uid(&mut self, uid: uid_t) { self.0.uid = uid; } /// Get the current UID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn get_uid(&self) -> u32 { + pub fn get_uid(&self) -> uid_t { self.0.uid } /// Set the GID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn set_gid(&mut self, gid: u32) { + pub fn set_gid(&mut self, gid: gid_t) { self.0.gid = gid; } /// Get the current GID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn get_gid(&self) -> u32 { + pub fn get_gid(&self) -> gid_t { self.0.gid } } From e74dbac02d9906fc17bdcdaaf74268e5ff6c0526 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Thu, 17 Sep 2020 11:25:51 +0200 Subject: [PATCH 24/60] Remove unsupported target_os for SocketCred --- library/std/src/sys/unix/ext/net/ancillary.rs | 132 +----------------- 1 file changed, 7 insertions(+), 125 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index d8c2939cd8b50..cfe1e328e2c9a 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -166,38 +166,12 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { } /// Unix credential. -#[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", -))] +#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] #[derive(Clone)] pub struct SocketCred(libc::ucred); -#[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", -))] +#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] impl SocketCred { /// Create a Unix credential struct. /// @@ -262,37 +236,11 @@ impl<'a> Iterator for ScmRights<'a> { /// This control message contains unix credentials. /// /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`. -#[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", -))] +#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); -#[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", -))] +#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] impl<'a> Iterator for ScmCredentials<'a> { type Item = SocketCred; @@ -314,20 +262,7 @@ pub enum AncillaryError { #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub enum AncillaryData<'a> { ScmRights(ScmRights<'a>), - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] ScmCredentials(ScmCredentials<'a>), } @@ -350,20 +285,7 @@ impl<'a> AncillaryData<'a> { /// /// `data` must contain a valid control message and the control message must be type of /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`. - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] unsafe fn as_credentials(data: &'a [u8]) -> Self { let ancillary_data_iter = AncillaryDataIter::new(data); let scm_credentials = ScmCredentials(ancillary_data_iter); @@ -383,20 +305,9 @@ impl<'a> AncillaryData<'a> { #[cfg(any( target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", - target_env = "uclibc", ))] libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] - libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)), cmsg_type => { Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type }) } @@ -593,20 +504,7 @@ impl<'a> SocketAncillary<'a> { /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` /// and type `SCM_CREDENTIALS` or `SCM_CREDS`. /// - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool { self.truncated = false; @@ -615,23 +513,7 @@ impl<'a> SocketAncillary<'a> { &mut self.length, creds, libc::SOL_SOCKET, - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux", - target_env = "uclibc", - ))] libc::SCM_CREDENTIALS, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] - libc::SCM_CREDS, ) } From e9ff53ccaf5c1b0178ce1990022eabca33a56943 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Thu, 17 Sep 2020 11:32:20 +0200 Subject: [PATCH 25/60] Cast boolean into int directly in function set_passcred --- library/std/src/sys/unix/net.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index c01d2fa5f23e2..2bd6b84d67174 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -324,8 +324,7 @@ impl Socket { } pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { - let boolean: libc::c_int = if passcred { 1 } else { 0 }; - setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, boolean) + setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) } pub fn passcred(&self) -> io::Result { From a86761e39caf286a67dd53d738112600cf8915d2 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Fri, 18 Sep 2020 14:08:31 +0200 Subject: [PATCH 26/60] Replace `assert` with `unreachable` --- library/std/src/sys/unix/ext/net/tests.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index 16915a4cc1efc..6cb2e7291434c 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -487,7 +487,7 @@ fn test_send_vectored_fds_unix_stream() { libc::close(fd_vec[0]); } } else { - assert!(false); + unreachable!("must be ScmRights"); } } @@ -553,7 +553,7 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { assert_eq!(cred1.get_uid(), cred_vec[0].get_uid()); assert_eq!(cred1.get_gid(), cred_vec[0].get_gid()); } else { - assert!(false); + unreachable!("must be ScmCredentials"); } } @@ -598,6 +598,6 @@ fn test_send_vectored_with_ancillary_unix_datagram() { libc::close(fd_vec[0]); } } else { - assert!(false); + unreachable!("must be ScmRights"); } } From 05765ac8c716662d2661948f816cb87e7bfcfc46 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 19 Sep 2020 13:09:18 +0200 Subject: [PATCH 27/60] Add the code of the tracking issue --- library/std/src/sys/unix/ext/net/ancillary.rs | 50 +++++++++---------- library/std/src/sys/unix/ext/net/datagram.rs | 12 ++--- library/std/src/sys/unix/ext/net/mod.rs | 2 +- library/std/src/sys/unix/ext/net/stream.rs | 8 +-- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index cfe1e328e2c9a..4473c4e5da803 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -167,7 +167,7 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { /// Unix credential. #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] #[derive(Clone)] pub struct SocketCred(libc::ucred); @@ -176,43 +176,43 @@ impl SocketCred { /// Create a Unix credential struct. /// /// PID, UID and GID is set to 0. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn new() -> SocketCred { SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 }) } /// Set the PID. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_pid(&mut self, pid: pid_t) { self.0.pid = pid; } /// Get the current PID. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_pid(&self) -> pid_t { self.0.pid } /// Set the UID. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_uid(&mut self, uid: uid_t) { self.0.uid = uid; } /// Get the current UID. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_uid(&self) -> uid_t { self.0.uid } /// Set the GID. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_gid(&mut self, gid: gid_t) { self.0.gid = gid; } /// Get the current GID. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_gid(&self) -> gid_t { self.0.gid } @@ -221,10 +221,10 @@ impl SocketCred { /// This control message contains file descriptors. /// /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`. -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>); -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] impl<'a> Iterator for ScmRights<'a> { type Item = RawFd; @@ -237,11 +237,11 @@ impl<'a> Iterator for ScmRights<'a> { /// /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`. #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] impl<'a> Iterator for ScmCredentials<'a> { type Item = SocketCred; @@ -253,13 +253,13 @@ impl<'a> Iterator for ScmCredentials<'a> { /// The error type which is returned from parsing the type a control message. #[non_exhaustive] #[derive(Debug)] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub enum AncillaryError { Unknown { cmsg_level: i32, cmsg_type: i32 }, } /// This enum represent one control message of variable type. -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub enum AncillaryData<'a> { ScmRights(ScmRights<'a>), #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] @@ -321,13 +321,13 @@ impl<'a> AncillaryData<'a> { } /// This struct is used to iterate through the control messages. -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub struct Messages<'a> { buffer: &'a [u8], current: Option<&'a libc::cmsghdr>, } -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] impl<'a> Iterator for Messages<'a> { type Item = Result, AncillaryError>; @@ -386,7 +386,7 @@ impl<'a> Iterator for Messages<'a> { /// Ok(()) /// } /// ``` -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] #[derive(Debug)] pub struct SocketAncillary<'a> { buffer: &'a mut [u8], @@ -406,25 +406,25 @@ impl<'a> SocketAncillary<'a> { /// let mut ancillary_buffer = [0; 128]; /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] 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")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn capacity(&self) -> usize { self.buffer.len() } /// Returns the number of used bytes. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn len(&self) -> usize { self.length } /// Returns the iterator of the control messages. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn messages(&self) -> Messages<'_> { Messages { buffer: &self.buffer[..self.length], current: None } } @@ -452,7 +452,7 @@ impl<'a> SocketAncillary<'a> { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn truncated(&self) -> bool { self.truncated } @@ -485,7 +485,7 @@ impl<'a> SocketAncillary<'a> { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn add_fds(&mut self, fds: &[RawFd]) -> bool { self.truncated = false; add_to_ancillary_data( @@ -505,7 +505,7 @@ impl<'a> SocketAncillary<'a> { /// and type `SCM_CREDENTIALS` or `SCM_CREDS`. /// #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool { self.truncated = false; add_to_ancillary_data( @@ -559,7 +559,7 @@ impl<'a> SocketAncillary<'a> { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn clear(&mut self) { self.length = 0; self.truncated = false; diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index e5309e54e7950..5b813ac648186 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -378,7 +378,7 @@ impl UnixDatagram { target_os = "solaris", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary_from( &self, bufs: &mut [IoSliceMut<'_>], @@ -442,7 +442,7 @@ impl UnixDatagram { target_os = "solaris", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary( &self, bufs: &mut [IoSliceMut<'_>], @@ -539,7 +539,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary_to>( &self, bufs: &mut [IoSliceMut<'_>], @@ -578,7 +578,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( &self, bufs: &mut [IoSliceMut<'_>], @@ -765,7 +765,7 @@ impl UnixDatagram { target_os = "openbsd", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.0.set_passcred(passcred) } @@ -790,7 +790,7 @@ impl UnixDatagram { target_os = "openbsd", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn passcred(&self) -> io::Result { self.0.passcred() } diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs index c37e856e5bc22..1c792b251b6ee 100644 --- a/library/std/src/sys/unix/ext/net/mod.rs +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -62,7 +62,7 @@ pub use self::addr::*; target_os = "solaris", target_env = "uclibc", ))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub use self::ancillary::*; #[stable(feature = "unix_socket", since = "1.10.0")] pub use self::datagram::*; diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 68e8429dd3b26..49f16861afca2 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -396,7 +396,7 @@ impl UnixStream { target_os = "openbsd", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.0.set_passcred(passcred) } @@ -421,7 +421,7 @@ impl UnixStream { target_os = "openbsd", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn passcred(&self) -> io::Result { self.0.passcred() } @@ -550,7 +550,7 @@ impl UnixStream { target_os = "solaris", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary( &self, bufs: &mut [IoSliceMut<'_>], @@ -606,7 +606,7 @@ impl UnixStream { target_os = "solaris", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( &self, bufs: &mut [IoSliceMut<'_>], From 112b7dc07e83227ac8ae75cdcf352e4c8b8cd5a4 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 20 Sep 2020 14:44:03 +0200 Subject: [PATCH 28/60] Remove `target_os`, which does not have `MSG_CMSG_CLOEXEC` constant in `libc` --- library/std/src/sys/unix/ext/net/datagram.rs | 38 ++++++++++---------- library/std/src/sys/unix/ext/net/mod.rs | 18 ---------- library/std/src/sys/unix/ext/net/stream.rs | 18 ---------- library/std/src/sys/unix/ext/net/tests.rs | 11 ++++++ 4 files changed, 31 insertions(+), 54 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 5b813ac648186..116375ad48b62 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -9,15 +9,9 @@ use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] use crate::sys::unix::ext::net::ancillary::{ @@ -367,15 +361,9 @@ impl UnixDatagram { target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -431,15 +419,9 @@ impl UnixDatagram { target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -539,6 +521,16 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", + ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary_to>( &self, @@ -578,6 +570,16 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", + ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( &self, diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs index 1c792b251b6ee..366ee7edf2afd 100644 --- a/library/std/src/sys/unix/ext/net/mod.rs +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -8,15 +8,9 @@ mod addr; target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", )))] #[cfg(any( @@ -25,15 +19,9 @@ mod addr; target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] mod ancillary; @@ -51,15 +39,9 @@ pub use self::addr::*; target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 49f16861afca2..671639949cb68 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -21,15 +21,9 @@ use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] use crate::sys::unix::ext::net::ancillary::{ @@ -539,15 +533,9 @@ impl UnixStream { target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -595,15 +583,9 @@ impl UnixStream { target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index 6cb2e7291434c..7690590b68bc1 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -557,6 +557,17 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { } } +#[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", +))] #[test] fn test_send_vectored_with_ancillary_unix_datagram() { let dir = tmpdir(); From 3806579d010b4628e78508a57d6847be9ffea02f Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 20 Sep 2020 14:53:21 +0200 Subject: [PATCH 29/60] Remove `target_os`, which does not have `cmsghdr` struct in `libc` --- library/std/src/sys/unix/ext/net/datagram.rs | 5 ----- library/std/src/sys/unix/ext/net/mod.rs | 3 --- library/std/src/sys/unix/ext/net/stream.rs | 3 --- library/std/src/sys/unix/ext/net/tests.rs | 1 - 4 files changed, 12 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 116375ad48b62..52cb3c0d9048d 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -12,7 +12,6 @@ use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] use crate::sys::unix::ext::net::ancillary::{ recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, @@ -364,7 +363,6 @@ impl UnixDatagram { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary_from( @@ -422,7 +420,6 @@ impl UnixDatagram { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary( @@ -529,7 +526,6 @@ impl UnixDatagram { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary_to>( @@ -578,7 +574,6 @@ impl UnixDatagram { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs index 366ee7edf2afd..d2799bbcaf859 100644 --- a/library/std/src/sys/unix/ext/net/mod.rs +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -11,7 +11,6 @@ mod addr; target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", )))] #[cfg(any( doc, @@ -22,7 +21,6 @@ mod addr; target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] mod ancillary; mod datagram; @@ -42,7 +40,6 @@ pub use self::addr::*; target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub use self::ancillary::*; diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 671639949cb68..21b13a083a03f 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -24,7 +24,6 @@ use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] use crate::sys::unix::ext::net::ancillary::{ recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, @@ -536,7 +535,6 @@ impl UnixStream { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary( @@ -586,7 +584,6 @@ impl UnixStream { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index 7690590b68bc1..9f34059d011b9 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -566,7 +566,6 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[test] fn test_send_vectored_with_ancillary_unix_datagram() { From d5f070b537e6a31d59f7390376fc027cb7b710e9 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 20 Sep 2020 15:04:09 +0200 Subject: [PATCH 30/60] Remove `target_os`, which does not have `SO_PASSCRED` constant in `libc` --- library/std/src/sys/unix/ext/net/datagram.rs | 30 ++------------------ library/std/src/sys/unix/ext/net/stream.rs | 30 ++------------------ library/std/src/sys/unix/ext/net/tests.rs | 1 + 3 files changed, 5 insertions(+), 56 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 52cb3c0d9048d..46061200be74d 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -748,20 +748,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.0.set_passcred(passcred) @@ -773,20 +760,7 @@ impl UnixDatagram { /// Get the socket option `SO_PASSCRED`. /// /// [`set_passcred`]: UnixDatagram::set_passcred - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn passcred(&self) -> io::Result { self.0.passcred() diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 21b13a083a03f..783a50e09b2bc 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -375,20 +375,7 @@ impl UnixStream { /// Ok(()) /// } /// ``` - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.0.set_passcred(passcred) @@ -400,20 +387,7 @@ impl UnixStream { /// Get the socket option `SO_PASSCRED`. /// /// [`set_passcred`]: UnixStream::set_passcred - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn passcred(&self) -> io::Result { self.0.passcred() diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index 9f34059d011b9..abf45ad2d1bc8 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -491,6 +491,7 @@ fn test_send_vectored_fds_unix_stream() { } } +#[cfg(any(test, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[test] fn test_send_vectored_with_ancillary_to_unix_datagram() { fn getpid() -> libc::pid_t { From 6626e5b3aa8db444b58c3a3eaa95a0d82d347e0c Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 20 Sep 2020 15:06:41 +0200 Subject: [PATCH 31/60] Fix cfg condition for test --- library/std/src/sys/unix/ext/net/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index abf45ad2d1bc8..cb04de1882803 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -559,7 +559,7 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { } #[cfg(any( - doc, + test, target_os = "android", target_os = "dragonfly", target_os = "emscripten", From b50153dd0cd3be18207e0d6123e0bc12e456aad4 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 20 Sep 2020 15:22:28 +0200 Subject: [PATCH 32/60] Add conditional compilation for import --- library/std/src/sys/unix/ext/net/ancillary.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 4473c4e5da803..0266df460982a 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -9,6 +9,7 @@ use crate::slice::from_raw_parts; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; use crate::sys::unix::net::Socket; +#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] use libc::{gid_t, pid_t, uid_t}; pub(super) fn recv_vectored_with_ancillary_from( From 4ee7a855e4cd7bc21317fe2f8b883a69f7c9a53b Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 22 Sep 2020 13:17:12 +0200 Subject: [PATCH 33/60] Fix `MSG_CMSG_CLOEXEC` for macos --- library/std/src/sys/unix/net.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 2bd6b84d67174..8f28c75641fe0 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -237,6 +237,15 @@ impl Socket { self.recv_from_with_flags(buf, 0) } + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result { let n = cvt(unsafe { libc::recvmsg(self.0.raw(), msg, libc::MSG_CMSG_CLOEXEC) })?; Ok(n as usize) @@ -259,6 +268,15 @@ impl Socket { self.0.is_write_vectored() } + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result { let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?; Ok(n as usize) From d839df3676d811bb327bc8fb2436935eba506a93 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 22 Sep 2020 13:18:06 +0200 Subject: [PATCH 34/60] Fix `SO_PASSCRED` for macos --- library/std/src/sys/unix/net.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 8f28c75641fe0..f27786dbf79ea 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -341,10 +341,12 @@ impl Socket { Ok(raw != 0) } + #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) } + #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] pub fn passcred(&self) -> io::Result { let passcred: libc::c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)?; Ok(passcred != 0) From 168d0636a605aea32b276b49cbbc3d5cbca61e76 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 22 Sep 2020 13:18:56 +0200 Subject: [PATCH 35/60] Fix unused import for `IoSliceMut` for macos --- library/std/src/sys/unix/ext/net/datagram.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 46061200be74d..99d90da3820f3 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -1,3 +1,12 @@ +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] use crate::io::IoSliceMut; use crate::net::Shutdown; use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; From 4e9714b0ef48894f25d0b2dd4ff47cd80b2b58cb Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 22 Sep 2020 22:21:27 +0200 Subject: [PATCH 36/60] Remove `SocketCred` for `emscripten` --- library/std/src/sys/unix/ext/net/ancillary.rs | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 0266df460982a..112d72dc29bc7 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -9,7 +9,7 @@ use crate::slice::from_raw_parts; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; use crate::sys::unix::net::Socket; -#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[cfg(any(target_os = "android", target_os = "linux",))] use libc::{gid_t, pid_t, uid_t}; pub(super) fn recv_vectored_with_ancillary_from( @@ -167,12 +167,12 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { } /// Unix credential. -#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] #[derive(Clone)] pub struct SocketCred(libc::ucred); -#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[cfg(any(doc, target_os = "android", target_os = "linux",))] impl SocketCred { /// Create a Unix credential struct. /// @@ -237,11 +237,11 @@ impl<'a> Iterator for ScmRights<'a> { /// This control message contains unix credentials. /// /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`. -#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); -#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] impl<'a> Iterator for ScmCredentials<'a> { type Item = SocketCred; @@ -263,7 +263,7 @@ pub enum AncillaryError { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub enum AncillaryData<'a> { ScmRights(ScmRights<'a>), - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] ScmCredentials(ScmCredentials<'a>), } @@ -286,7 +286,7 @@ impl<'a> AncillaryData<'a> { /// /// `data` must contain a valid control message and the control message must be type of /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`. - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] unsafe fn as_credentials(data: &'a [u8]) -> Self { let ancillary_data_iter = AncillaryDataIter::new(data); let scm_credentials = ScmCredentials(ancillary_data_iter); @@ -303,11 +303,7 @@ impl<'a> AncillaryData<'a> { match (*cmsg).cmsg_level { libc::SOL_SOCKET => match (*cmsg).cmsg_type { libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)), - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "linux", - ))] + #[cfg(any(target_os = "android", target_os = "linux",))] libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)), cmsg_type => { Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type }) @@ -505,7 +501,7 @@ impl<'a> SocketAncillary<'a> { /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` /// and type `SCM_CREDENTIALS` or `SCM_CREDS`. /// - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool { self.truncated = false; From f289468045c248e3543f2b0cd50cc37ecd3fd717 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 23 Sep 2020 17:02:58 +0200 Subject: [PATCH 37/60] Stabilize slice_ptr_range. Closes #65807. --- library/core/src/slice/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 12dcd6c6ba8d0..b3fff060eadbe 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -458,8 +458,6 @@ impl [T] { /// element of this slice: /// /// ``` - /// #![feature(slice_ptr_range)] - /// /// let a = [1, 2, 3]; /// let x = &a[1] as *const _; /// let y = &5 as *const _; @@ -469,7 +467,7 @@ impl [T] { /// ``` /// /// [`as_ptr`]: #method.as_ptr - #[unstable(feature = "slice_ptr_range", issue = "65807")] + #[stable(feature = "slice_ptr_range", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] pub const fn as_ptr_range(&self) -> Range<*const T> { @@ -511,7 +509,7 @@ impl [T] { /// common in C++. /// /// [`as_mut_ptr`]: #method.as_mut_ptr - #[unstable(feature = "slice_ptr_range", issue = "65807")] + #[stable(feature = "slice_ptr_range", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> { From d77477e4db0492cffa740945bb1bac28cd5c952a Mon Sep 17 00:00:00 2001 From: LinkTed Date: Fri, 25 Sep 2020 20:19:02 +0200 Subject: [PATCH 38/60] Fix type mismatching for different OSes. --- library/std/src/sys/unix/ext/net/ancillary.rs | 146 +++++++++++++----- 1 file changed, 105 insertions(+), 41 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 112d72dc29bc7..c53b213e0f933 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -4,7 +4,7 @@ use crate::marker::PhantomData; use crate::mem::{size_of, zeroed}; use crate::os::unix::io::RawFd; use crate::path::Path; -use crate::ptr::{null_mut, read_unaligned}; +use crate::ptr::read_unaligned; use crate::slice::from_raw_parts; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; use crate::sys::unix::net::Socket; @@ -20,19 +20,31 @@ pub(super) fn recv_vectored_with_ancillary_from( unsafe { let mut msg_name: libc::sockaddr_un = zeroed(); - let mut msg = libc::msghdr { - msg_name: &mut msg_name as *mut _ as *mut _, - msg_namelen: size_of::() 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 mut msg: libc::msghdr = zeroed(); + msg.msg_name = &mut msg_name as *mut _ as *mut _; + msg.msg_namelen = size_of::() 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; + msg.msg_controllen = ancillary.buffer.len() as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_iovlen = bufs.len() as libc::c_int; + msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t; + } + } let count = socket.recv_msg(&mut msg)?; - ancillary.length = msg.msg_controllen; + ancillary.length = msg.msg_controllen as usize; ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC; let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC; @@ -52,15 +64,27 @@ pub(super) fn send_vectored_with_ancillary_to( let (mut msg_name, msg_namelen) = if let Some(path) = path { sockaddr_un(path)? } else { (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, - }; + let mut msg: libc::msghdr = zeroed(); + msg.msg_name = &mut msg_name as *mut _ as *mut _; + msg.msg_namelen = msg_namelen; + 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; + msg.msg_controllen = ancillary.length as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_iovlen = bufs.len() as libc::c_int; + msg.msg_controllen = ancillary.length as libc::socklen_t; + } + } ancillary.truncated = false; @@ -102,15 +126,22 @@ fn add_to_ancillary_data( *length = new_length; - 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 msg: libc::msghdr = zeroed(); + msg.msg_control = buffer.as_mut_ptr().cast(); + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_controllen = *length as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_controllen = *length as libc::socklen_t; + } + } let mut cmsg = libc::CMSG_FIRSTHDR(&msg); let mut previous_cmsg = cmsg; @@ -125,7 +156,20 @@ fn add_to_ancillary_data( (*previous_cmsg).cmsg_level = cmsg_level; (*previous_cmsg).cmsg_type = cmsg_type; - (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as usize; + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::socklen_t; + } + } let data = libc::CMSG_DATA(previous_cmsg).cast(); @@ -295,10 +339,23 @@ impl<'a> AncillaryData<'a> { fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result { unsafe { - let cmsg_len_zero = libc::CMSG_LEN(0) as usize; + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + let cmsg_len_zero = libc::CMSG_LEN(0) as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + let cmsg_len_zero = libc::CMSG_LEN(0) as libc::socklen_t; + } + } let data_len = (*cmsg).cmsg_len - cmsg_len_zero; let data = libc::CMSG_DATA(cmsg).cast(); - let data = from_raw_parts(data, data_len); + let data = from_raw_parts(data, data_len as usize); match (*cmsg).cmsg_level { libc::SOL_SOCKET => match (*cmsg).cmsg_type { @@ -330,15 +387,22 @@ impl<'a> Iterator for Messages<'a> { fn next(&mut self) -> Option { 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 mut msg: libc::msghdr = zeroed(); + msg.msg_control = self.buffer.as_ptr() as *mut _; + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_controllen = self.buffer.len() as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_controllen = self.buffer.len() as libc::socklen_t;; + } + } let cmsg = if let Some(current) = self.current { libc::CMSG_NXTHDR(&msg, current) From 3efcf7299a4876ee3dbeb04be008b0245047c833 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 26 Sep 2020 20:04:10 +0200 Subject: [PATCH 39/60] Remove unnecessary trailing semicolon --- library/std/src/sys/unix/ext/net/ancillary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index c53b213e0f933..547c9c7dcbe19 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -400,7 +400,7 @@ impl<'a> Iterator for Messages<'a> { target_os = "netbsd", target_os = "openbsd", ))] { - msg.msg_controllen = self.buffer.len() as libc::socklen_t;; + msg.msg_controllen = self.buffer.len() as libc::socklen_t; } } From 20c88ddd5fe668b29e8fc2c3838710093e8eb94b Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 26 Sep 2020 22:40:02 +0200 Subject: [PATCH 40/60] Remove `passcred` for `emscripten` --- library/std/src/sys/unix/ext/net/datagram.rs | 4 ++-- library/std/src/sys/unix/ext/net/stream.rs | 4 ++-- library/std/src/sys/unix/net.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 99d90da3820f3..9d9df6959b267 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -757,7 +757,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.0.set_passcred(passcred) @@ -769,7 +769,7 @@ impl UnixDatagram { /// Get the socket option `SO_PASSCRED`. /// /// [`set_passcred`]: UnixDatagram::set_passcred - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn passcred(&self) -> io::Result { self.0.passcred() diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 783a50e09b2bc..8337487ff47bc 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -375,7 +375,7 @@ impl UnixStream { /// Ok(()) /// } /// ``` - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.0.set_passcred(passcred) @@ -387,7 +387,7 @@ impl UnixStream { /// Get the socket option `SO_PASSCRED`. /// /// [`set_passcred`]: UnixStream::set_passcred - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn passcred(&self) -> io::Result { self.0.passcred() diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index f27786dbf79ea..ddabb3f054710 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -341,12 +341,12 @@ impl Socket { Ok(raw != 0) } - #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(target_os = "android", target_os = "linux",))] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) } - #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(target_os = "android", target_os = "linux",))] pub fn passcred(&self) -> io::Result { let passcred: libc::c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)?; Ok(passcred != 0) From c297e20e03452c659b6d3f026ce4beee42ed8738 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 21 Sep 2020 11:32:06 -0700 Subject: [PATCH 41/60] Add accessors to Command. --- library/std/src/process.rs | 125 ++++++++++++++++++ library/std/src/sys/unix/process/mod.rs | 3 +- .../src/sys/unix/process/process_common.rs | 53 +++++++- .../src/sys/unix/process/process_fuchsia.rs | 2 +- .../std/src/sys/unix/process/process_unix.rs | 4 +- library/std/src/sys/unsupported/process.rs | 39 +++++- library/std/src/sys/windows/process.rs | 48 ++++++- library/std/src/sys_common/process.rs | 37 ++++++ 8 files changed, 303 insertions(+), 8 deletions(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 9f3796e11ed1a..3d238b7f764ef 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -110,6 +110,8 @@ use crate::path::Path; use crate::str; use crate::sys::pipe::{read2, AnonPipe}; use crate::sys::process as imp; +#[unstable(feature = "command_access", issue = "44434")] +pub use crate::sys_common::process::CommandEnvs; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// Representation of a running or exited child process. @@ -894,6 +896,98 @@ impl Command { .map(Child::from_inner) .and_then(|mut p| p.wait()) } + + /// Returns the path to the program that was given to [`Command::new`]. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::process::Command; + /// + /// let cmd = Command::new("echo"); + /// assert_eq!(cmd.get_program(), "echo"); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_program(&self) -> &OsStr { + self.inner.get_program() + } + + /// Returns an iterator of the arguments that will be passed to the program. + /// + /// This does not include the path to the program as the first argument; + /// it only includes the arguments specified with [`Command::arg`] and + /// [`Command::args`]. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::ffi::OsStr; + /// use std::process::Command; + /// + /// let mut cmd = Command::new("echo"); + /// cmd.arg("first").arg("second"); + /// let args: Vec<&OsStr> = cmd.get_args().collect(); + /// assert_eq!(args, &["first", "second"]); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_args(&self) -> CommandArgs<'_> { + CommandArgs { inner: self.inner.get_args() } + } + + /// Returns an iterator of the environment variables that will be set when + /// the process is spawned. + /// + /// Each element is a tuple `(&OsStr, Option<&OsStr>)`, where the first + /// value is the key, and the second is the value, which is [`None`] if + /// the environment variable is to be explicitly removed. + /// + /// This only includes environment variables explicitly set with + /// [`Command::env`], [`Command::envs`], and [`Command::env_remove`]. It + /// does not include environment variables that will be inherited by the + /// child process. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::ffi::OsStr; + /// use std::process::Command; + /// + /// let mut cmd = Command::new("ls"); + /// cmd.env("TERM", "dumb").env_remove("TZ"); + /// let envs: Vec<(&OsStr, Option<&OsStr>)> = cmd.get_envs().collect(); + /// assert_eq!(envs, &[ + /// (OsStr::new("TERM"), Some(OsStr::new("dumb"))), + /// (OsStr::new("TZ"), None) + /// ]); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.inner.get_envs() + } + + /// Returns the working directory for the child process. + /// + /// This returns [`None`] if the working directory will not be changed. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::path::Path; + /// use std::process::Command; + /// + /// let mut cmd = Command::new("ls"); + /// assert_eq!(cmd.get_current_dir(), None); + /// cmd.current_dir("/bin"); + /// assert_eq!(cmd.get_current_dir(), Some(Path::new("/bin"))); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_current_dir(&self) -> Option<&Path> { + self.inner.get_current_dir() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -918,6 +1012,37 @@ impl AsInnerMut for Command { } } +/// An iterator over the command arguments. +/// +/// This struct is created by [`Command::get_args`]. See its documentation for +/// more. +#[unstable(feature = "command_access", issue = "44434")] +#[derive(Debug)] +pub struct CommandArgs<'a> { + inner: imp::CommandArgs<'a>, +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.inner.next() + } + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.inner.len() + } + fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + /// The output of a finished process. /// /// This is returned in a Result by either the [`output`] method of a diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs index 553e980f08e97..1b7b93f9d4a5f 100644 --- a/library/std/src/sys/unix/process/mod.rs +++ b/library/std/src/sys/unix/process/mod.rs @@ -1,6 +1,7 @@ -pub use self::process_common::{Command, ExitCode, Stdio, StdioPipes}; +pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes}; pub use self::process_inner::{ExitStatus, Process}; pub use crate::ffi::OsString as EnvKey; +pub use crate::sys_common::process::CommandEnvs; mod process_common; #[cfg(not(target_os = "fuchsia"))] diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index f8666485eeccb..9ddd4ad4000ef 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -7,11 +7,12 @@ use crate::collections::BTreeMap; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; use crate::io; +use crate::path::Path; use crate::ptr; use crate::sys::fd::FileDesc; use crate::sys::fs::File; use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::CommandEnv; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; #[cfg(not(target_os = "fuchsia"))] use crate::sys::fs::OpenOptions; @@ -184,11 +185,30 @@ impl Command { pub fn saw_nul(&self) -> bool { self.saw_nul } + + pub fn get_program(&self) -> &OsStr { + OsStr::from_bytes(self.program.as_bytes()) + } + + pub fn get_args(&self) -> CommandArgs<'_> { + let mut iter = self.args.iter(); + iter.next(); + CommandArgs { iter } + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.env.iter() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + self.cwd.as_ref().map(|cs| Path::new(OsStr::from_bytes(cs.as_bytes()))) + } + pub fn get_argv(&self) -> &Vec<*const c_char> { &self.argv.0 } - pub fn get_program(&self) -> &CStr { + pub fn get_program_cstr(&self) -> &CStr { &*self.program } @@ -402,3 +422,32 @@ impl ExitCode { self.0 as i32 } } + +pub struct CommandArgs<'a> { + iter: crate::slice::Iter<'a, CString>, +} + +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.iter.next().map(|cs| OsStr::from_bytes(cs.as_bytes())) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter.clone()).finish() + } +} diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs index fab27cd9f7085..b64636c3f3d15 100644 --- a/library/std/src/sys/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/unix/process/process_fuchsia.rs @@ -120,7 +120,7 @@ impl Command { | FDIO_SPAWN_CLONE_NAMESPACE | FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null | FDIO_SPAWN_CLONE_UTC_CLOCK, - self.get_program().as_ptr(), + self.get_program_cstr().as_ptr(), self.get_argv().as_ptr(), envp, actions.len() as size_t, diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 08efe154e4c3b..50f5e78cf2a88 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -245,7 +245,7 @@ impl Command { *sys::os::environ() = envp.as_ptr(); } - libc::execvp(self.get_program().as_ptr(), self.get_argv().as_ptr()); + libc::execvp(self.get_program_cstr().as_ptr(), self.get_argv().as_ptr()); Err(io::Error::last_os_error()) } @@ -383,7 +383,7 @@ impl Command { let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _); let ret = libc::posix_spawnp( &mut p.pid, - self.get_program().as_ptr(), + self.get_program_cstr().as_ptr(), file_actions.0.as_ptr(), attrs.0.as_ptr(), self.get_argv().as_ptr() as *const _, diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index 7156c9ab92f2b..3ede2291d5a91 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -1,10 +1,12 @@ use crate::ffi::OsStr; use crate::fmt; use crate::io; +use crate::marker::PhantomData; +use crate::path::Path; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::{unsupported, Void}; -use crate::sys_common::process::CommandEnv; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; pub use crate::ffi::OsString as EnvKey; @@ -49,6 +51,22 @@ impl Command { pub fn stderr(&mut self, _stderr: Stdio) {} + pub fn get_program(&self) -> &OsStr { + panic!("unsupported") + } + + pub fn get_args(&self) -> CommandArgs<'_> { + CommandArgs { _p: PhantomData } + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.env.iter() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + None + } + pub fn spawn( &mut self, _default: Stdio, @@ -147,3 +165,22 @@ impl Process { match self.0 {} } } + +pub struct CommandArgs<'a> { + _p: PhantomData<&'a ()>, +} + +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + None + } +} + +impl<'a> ExactSizeIterator for CommandArgs<'a> {} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().finish() + } +} diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index e18521bb30d91..243065b94b125 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -22,7 +22,7 @@ use crate::sys::handle::Handle; use crate::sys::mutex::Mutex; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::stdio; -use crate::sys_common::process::CommandEnv; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::sys_common::AsInner; use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS}; @@ -134,6 +134,23 @@ impl Command { self.flags = flags; } + pub fn get_program(&self) -> &OsStr { + &self.program + } + + pub fn get_args(&self) -> CommandArgs<'_> { + let iter = self.args.iter(); + CommandArgs { iter } + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.env.iter() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + self.cwd.as_ref().map(|cwd| Path::new(cwd)) + } + pub fn spawn( &mut self, default: Stdio, @@ -529,3 +546,32 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec)> { None => Ok((ptr::null(), Vec::new())), } } + +pub struct CommandArgs<'a> { + iter: crate::slice::Iter<'a, OsString>, +} + +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.iter.next().map(|s| s.as_ref()) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter.clone()).finish() + } +} diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs index f3a2962098b4d..fe89b11043c0f 100644 --- a/library/std/src/sys_common/process.rs +++ b/library/std/src/sys_common/process.rs @@ -92,4 +92,41 @@ impl CommandEnv { self.saw_path = true; } } + + pub fn iter(&self) -> CommandEnvs<'_> { + let iter = self.vars.iter(); + CommandEnvs { iter } + } +} + +/// An iterator over the command environment variables. +/// +/// This struct is created by +/// [`Command::get_envs`][crate::process::Command::get_envs]. See its +/// documentation for more. +#[unstable(feature = "command_access", issue = "44434")] +#[derive(Debug)] +pub struct CommandEnvs<'a> { + iter: crate::collections::btree_map::Iter<'a, EnvKey, Option>, +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> Iterator for CommandEnvs<'a> { + type Item = (&'a OsStr, Option<&'a OsStr>); + fn next(&mut self) -> Option { + self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref())) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> ExactSizeIterator for CommandEnvs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } } From 6f6336b4a187b03312b978703496ea0ee9020ec9 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 24 Sep 2020 16:03:20 +0200 Subject: [PATCH 42/60] Split sys_common::Mutex in StaticMutex and MovableMutex. The (unsafe) Mutex from sys_common had a rather complicated interface. You were supposed to call init() manually, unless you could guarantee it was neither moved nor used reentrantly. Calling `destroy()` was also optional, although it was unclear if 1) resources might be leaked or not, and 2) if destroy() should only be called when `init()` was called. This allowed for a number of interesting (confusing?) different ways to use this Mutex, all captured in a single type. In practice, this type was only ever used in two ways: 1. As a static variable. In this case, neither init() nor destroy() are called. The variable is never moved, and it is never used reentrantly. It is only ever locked using the LockGuard, never with raw_lock. 2. As a Boxed variable. In this case, both init() and destroy() are called, it will be moved and possibly used reentrantly. No other combinations are used anywhere in `std`. This change simplifies things by splitting this Mutex type into two types matching the two use cases: StaticMutex and MovableMutex. The interface of both new types is now both safer and simpler. The first one does not call nor expose init/destroy, and the second one calls those automatically in its new() and Drop functions. Also, the locking functions of MovableMutex are no longer unsafe. --- library/std/src/sync/condvar.rs | 4 +- library/std/src/sync/mutex.rs | 30 +---- library/std/src/sys/hermit/args.rs | 4 +- library/std/src/sys/unix/args.rs | 4 +- library/std/src/sys/unix/os.rs | 9 +- library/std/src/sys/vxworks/args.rs | 4 +- library/std/src/sys/vxworks/os.rs | 9 +- library/std/src/sys_common/at_exit_imp.rs | 7 +- library/std/src/sys_common/condvar.rs | 10 +- library/std/src/sys_common/mutex.rs | 127 +++++++++--------- .../std/src/sys_common/thread_local_key.rs | 4 +- library/std/src/thread/mod.rs | 5 +- library/std/src/time.rs | 4 +- 13 files changed, 100 insertions(+), 121 deletions(-) diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index 7e2155dae6fce..1376d8ebe8f4a 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -553,8 +553,8 @@ impl Condvar { unsafe { self.inner.notify_all() } } - fn verify(&self, mutex: &sys_mutex::Mutex) { - let addr = mutex as *const _ as usize; + fn verify(&self, mutex: &sys_mutex::MovableMutex) { + let addr = mutex.raw() as *const _ as usize; match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) { // If we got out 0, then we have successfully bound the mutex to // this cvar. diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index a1703c731d44d..e8f5a6f429486 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -166,12 +166,7 @@ use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "mutex_type")] pub struct Mutex { - // Note that this mutex is in a *box*, not inlined into the struct itself. - // Once a native mutex has been used once, its address can never change (it - // can't be moved). This mutex type can be safely moved at any time, so to - // ensure that the native mutex is used correctly we box the inner mutex to - // give it a constant address. - inner: Box, + inner: sys::MovableMutex, poison: poison::Flag, data: UnsafeCell, } @@ -218,15 +213,11 @@ impl Mutex { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(t: T) -> Mutex { - let mut m = Mutex { - inner: box sys::Mutex::new(), + Mutex { + inner: sys::MovableMutex::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t), - }; - unsafe { - m.inner.init(); } - m } } @@ -378,7 +369,6 @@ impl Mutex { (ptr::read(inner), ptr::read(poison), ptr::read(data)) }; mem::forget(self); - inner.destroy(); // Keep in sync with the `Drop` impl. drop(inner); poison::map_result(poison.borrow(), |_| data.into_inner()) @@ -411,18 +401,6 @@ impl Mutex { } } -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex { - fn drop(&mut self) { - // This is actually safe b/c we know that there is no further usage of - // this mutex (it's up to the user to arrange for a mutex to get - // dropped, that's not our job) - // - // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`. - unsafe { self.inner.destroy() } - } -} - #[stable(feature = "mutex_from", since = "1.24.0")] impl From for Mutex { /// Creates a new mutex in an unlocked state ready for use. @@ -509,7 +487,7 @@ impl fmt::Display for MutexGuard<'_, T> { } } -pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { +pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::MovableMutex { &guard.lock.inner } diff --git a/library/std/src/sys/hermit/args.rs b/library/std/src/sys/hermit/args.rs index 72c1b8511cac8..7727293927282 100644 --- a/library/std/src/sys/hermit/args.rs +++ b/library/std/src/sys/hermit/args.rs @@ -57,11 +57,11 @@ mod imp { use crate::ptr; use crate::sys_common::os_str_bytes::*; - use crate::sys_common::mutex::Mutex; + use crate::sys_common::mutex::StaticMutex; static mut ARGC: isize = 0; static mut ARGV: *const *const u8 = ptr::null(); - static LOCK: Mutex = Mutex::new(); + static LOCK: StaticMutex = StaticMutex::new(); pub unsafe fn init(argc: isize, argv: *const *const u8) { let _guard = LOCK.lock(); diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index 9bc44a59482a0..f7c3f16371818 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -80,13 +80,13 @@ mod imp { use crate::ptr; use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering}; - use crate::sys_common::mutex::Mutex; + use crate::sys_common::mutex::StaticMutex; static ARGC: AtomicIsize = AtomicIsize::new(0); static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut()); // We never call `ENV_LOCK.init()`, so it is UB to attempt to // acquire this mutex reentrantly! - static LOCK: Mutex = Mutex::new(); + static LOCK: StaticMutex = StaticMutex::new(); unsafe fn really_init(argc: isize, argv: *const *const u8) { let _guard = LOCK.lock(); diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 4aa61fc5bf687..c9f9ed01e120e 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -21,7 +21,7 @@ use crate::slice; use crate::str; use crate::sys::cvt; use crate::sys::fd; -use crate::sys_common::mutex::{Mutex, MutexGuard}; +use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; use crate::vec; use libc::{c_char, c_int, c_void}; @@ -470,10 +470,9 @@ pub unsafe fn environ() -> *mut *const *const c_char { &mut environ } -pub unsafe fn env_lock() -> MutexGuard<'static> { - // We never call `ENV_LOCK.init()`, so it is UB to attempt to - // acquire this mutex reentrantly! - static ENV_LOCK: Mutex = Mutex::new(); +pub unsafe fn env_lock() -> StaticMutexGuard<'static> { + // It is UB to attempt to acquire this mutex reentrantly! + static ENV_LOCK: StaticMutex = StaticMutex::new(); ENV_LOCK.lock() } diff --git a/library/std/src/sys/vxworks/args.rs b/library/std/src/sys/vxworks/args.rs index adff6c489bbc9..30cf7a707c7af 100644 --- a/library/std/src/sys/vxworks/args.rs +++ b/library/std/src/sys/vxworks/args.rs @@ -57,11 +57,11 @@ mod imp { use crate::marker::PhantomData; use crate::ptr; - use crate::sys_common::mutex::Mutex; + use crate::sys_common::mutex::StaticMutex; static mut ARGC: isize = 0; static mut ARGV: *const *const u8 = ptr::null(); - static LOCK: Mutex = Mutex::new(); + static LOCK: StaticMutex = StaticMutex::new(); pub unsafe fn init(argc: isize, argv: *const *const u8) { let _guard = LOCK.lock(); diff --git a/library/std/src/sys/vxworks/os.rs b/library/std/src/sys/vxworks/os.rs index 1fadf71613561..08394a8d29de1 100644 --- a/library/std/src/sys/vxworks/os.rs +++ b/library/std/src/sys/vxworks/os.rs @@ -10,7 +10,7 @@ use crate::path::{self, Path, PathBuf}; use crate::slice; use crate::str; use crate::sys::cvt; -use crate::sys_common::mutex::{Mutex, MutexGuard}; +use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; use libc::{self, c_char /*,c_void */, c_int}; /*use sys::fd; this one is probably important */ use crate::vec; @@ -212,10 +212,9 @@ pub unsafe fn environ() -> *mut *const *const c_char { &mut environ } -pub unsafe fn env_lock() -> MutexGuard<'static> { - // We never call `ENV_LOCK.init()`, so it is UB to attempt to - // acquire this mutex reentrantly! - static ENV_LOCK: Mutex = Mutex::new(); +pub unsafe fn env_lock() -> StaticMutexGuard<'static> { + // It is UB to attempt to acquire this mutex reentrantly! + static ENV_LOCK: StaticMutex = StaticMutex::new(); ENV_LOCK.lock() } diff --git a/library/std/src/sys_common/at_exit_imp.rs b/library/std/src/sys_common/at_exit_imp.rs index 6b799db856eb1..90d5d3a78987f 100644 --- a/library/std/src/sys_common/at_exit_imp.rs +++ b/library/std/src/sys_common/at_exit_imp.rs @@ -4,7 +4,7 @@ use crate::mem; use crate::ptr; -use crate::sys_common::mutex::Mutex; +use crate::sys_common::mutex::StaticMutex; type Queue = Vec>; @@ -12,9 +12,8 @@ type Queue = Vec>; // on poisoning and this module needs to operate at a lower level than requiring // the thread infrastructure to be in place (useful on the borders of // initialization/destruction). -// We never call `LOCK.init()`, so it is UB to attempt to -// acquire this mutex reentrantly! -static LOCK: Mutex = Mutex::new(); +// It is UB to attempt to acquire this mutex reentrantly! +static LOCK: StaticMutex = StaticMutex::new(); static mut QUEUE: *mut Queue = ptr::null_mut(); const DONE: *mut Queue = 1_usize as *mut _; diff --git a/library/std/src/sys_common/condvar.rs b/library/std/src/sys_common/condvar.rs index f9611bc6f7bc9..a48d301f8127b 100644 --- a/library/std/src/sys_common/condvar.rs +++ b/library/std/src/sys_common/condvar.rs @@ -1,5 +1,5 @@ use crate::sys::condvar as imp; -use crate::sys_common::mutex::{self, Mutex}; +use crate::sys_common::mutex::MovableMutex; use crate::time::Duration; /// An OS-based condition variable. @@ -46,8 +46,8 @@ impl Condvar { /// Behavior is also undefined if more than one mutex is used concurrently /// on this condition variable. #[inline] - pub unsafe fn wait(&self, mutex: &Mutex) { - self.0.wait(mutex::raw(mutex)) + pub unsafe fn wait(&self, mutex: &MovableMutex) { + self.0.wait(mutex.raw()) } /// Waits for a signal on the specified mutex with a timeout duration @@ -57,8 +57,8 @@ impl Condvar { /// Behavior is also undefined if more than one mutex is used concurrently /// on this condition variable. #[inline] - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - self.0.wait_timeout(mutex::raw(mutex), dur) + pub unsafe fn wait_timeout(&self, mutex: &MovableMutex, dur: Duration) -> bool { + self.0.wait_timeout(mutex.raw(), dur) } /// Deallocates all resources associated with this condition variable. diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs index e66d8994147e1..93ec7d89bc5c7 100644 --- a/library/std/src/sys_common/mutex.rs +++ b/library/std/src/sys_common/mutex.rs @@ -1,101 +1,106 @@ use crate::sys::mutex as imp; -/// An OS-based mutual exclusion lock. +/// An OS-based mutual exclusion lock, meant for use in static variables. +/// +/// This mutex has a const constructor ([`StaticMutex::new`]), does not +/// implement `Drop` to cleanup resources, and causes UB when moved or used +/// reentrantly. +/// +/// This mutex does not implement poisoning. /// -/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of -/// this mutex is unsafe and it is recommended to instead use the safe wrapper -/// at the top level of the crate instead of this type. -pub struct Mutex(imp::Mutex); +/// This is a wrapper around `imp::Mutex` that does *not* call `init()` and +/// `destroy()`. +pub struct StaticMutex(imp::Mutex); -unsafe impl Sync for Mutex {} +unsafe impl Sync for StaticMutex {} -impl Mutex { +impl StaticMutex { /// Creates a new mutex for use. /// /// Behavior is undefined if the mutex is moved after it is /// first used with any of the functions below. - /// Also, until `init` is called, behavior is undefined if this - /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock` - /// are called by the thread currently holding the lock. + /// Also, the behavior is undefined if this mutex is ever used reentrantly, + /// i.e., `lock` is called by the thread currently holding the lock. #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")] - pub const fn new() -> Mutex { - Mutex(imp::Mutex::new()) + pub const fn new() -> Self { + Self(imp::Mutex::new()) } - /// Prepare the mutex for use. + /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex + /// will be unlocked. /// - /// This should be called once the mutex is at a stable memory address. - /// If called, this must be the very first thing that happens to the mutex. - /// Calling it in parallel with or after any operation (including another - /// `init()`) is undefined behavior. + /// It is undefined behaviour to call this function while locked, or if the + /// mutex has been moved since the last time this was called. #[inline] - pub unsafe fn init(&mut self) { - self.0.init() + pub unsafe fn lock(&self) -> StaticMutexGuard<'_> { + self.0.lock(); + StaticMutexGuard(&self.0) } +} - /// Locks the mutex blocking the current thread until it is available. - /// - /// Behavior is undefined if the mutex has been moved between this and any - /// previous function call. +#[must_use] +pub struct StaticMutexGuard<'a>(&'a imp::Mutex); + +impl Drop for StaticMutexGuard<'_> { #[inline] - pub unsafe fn raw_lock(&self) { - self.0.lock() + fn drop(&mut self) { + unsafe { + self.0.unlock(); + } } +} - /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex - /// will be unlocked. +/// An OS-based mutual exclusion lock. +/// +/// This mutex does *not* have a const constructor, cleans up its resources in +/// its `Drop` implementation, may safely be moved (when not borrowed), and +/// does not cause UB when used reentrantly. +/// +/// This mutex does not implement poisoning. +/// +/// This is a wrapper around `Box`, to allow the object to be moved +/// without moving the raw mutex. +pub struct MovableMutex(Box); + +unsafe impl Sync for MovableMutex {} + +impl MovableMutex { + /// Creates a new mutex. + pub fn new() -> Self { + let mut mutex = box imp::Mutex::new(); + unsafe { mutex.init() }; + Self(mutex) + } + + pub(crate) fn raw(&self) -> &imp::Mutex { + &self.0 + } + + /// Locks the mutex blocking the current thread until it is available. #[inline] - pub unsafe fn lock(&self) -> MutexGuard<'_> { - self.raw_lock(); - MutexGuard(&self.0) + pub fn raw_lock(&self) { + unsafe { self.0.lock() } } /// Attempts to lock the mutex without blocking, returning whether it was /// successfully acquired or not. - /// - /// Behavior is undefined if the mutex has been moved between this and any - /// previous function call. #[inline] - pub unsafe fn try_lock(&self) -> bool { - self.0.try_lock() + pub fn try_lock(&self) -> bool { + unsafe { self.0.try_lock() } } /// Unlocks the mutex. /// /// Behavior is undefined if the current thread does not actually hold the /// mutex. - /// - /// Consider switching from the pair of raw_lock() and raw_unlock() to - /// lock() whenever possible. #[inline] pub unsafe fn raw_unlock(&self) { self.0.unlock() } - - /// Deallocates all resources associated with this mutex. - /// - /// Behavior is undefined if there are current or will be future users of - /// this mutex. - #[inline] - pub unsafe fn destroy(&self) { - self.0.destroy() - } } -// not meant to be exported to the outside world, just the containing module -pub fn raw(mutex: &Mutex) -> &imp::Mutex { - &mutex.0 -} - -#[must_use] -/// A simple RAII utility for the above Mutex without the poisoning semantics. -pub struct MutexGuard<'a>(&'a imp::Mutex); - -impl Drop for MutexGuard<'_> { - #[inline] +impl Drop for MovableMutex { fn drop(&mut self) { - unsafe { - self.0.unlock(); - } + unsafe { self.0.destroy() }; } } diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs index 676eadd1fac3b..dbcb7b36265f5 100644 --- a/library/std/src/sys_common/thread_local_key.rs +++ b/library/std/src/sys_common/thread_local_key.rs @@ -53,7 +53,7 @@ mod tests; use crate::sync::atomic::{self, AtomicUsize, Ordering}; use crate::sys::thread_local_key as imp; -use crate::sys_common::mutex::Mutex; +use crate::sys_common::mutex::StaticMutex; /// A type for TLS keys that are statically allocated. /// @@ -157,7 +157,7 @@ impl StaticKey { if imp::requires_synchronized_create() { // We never call `INIT_LOCK.init()`, so it is UB to attempt to // acquire this mutex reentrantly! - static INIT_LOCK: Mutex = Mutex::new(); + static INIT_LOCK: StaticMutex = StaticMutex::new(); let _guard = INIT_LOCK.lock(); let mut key = self.key.load(Ordering::SeqCst); if key == 0 { diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 8c353e2484ef2..85a79642f5d91 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1034,9 +1034,8 @@ pub struct ThreadId(NonZeroU64); impl ThreadId { // Generate a new unique thread ID. fn new() -> ThreadId { - // We never call `GUARD.init()`, so it is UB to attempt to - // acquire this mutex reentrantly! - static GUARD: mutex::Mutex = mutex::Mutex::new(); + // It is UB to attempt to acquire this mutex reentrantly! + static GUARD: mutex::StaticMutex = mutex::StaticMutex::new(); static mut COUNTER: u64 = 1; unsafe { diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 18e38c6299b72..e7df38411478d 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -20,7 +20,7 @@ use crate::error::Error; use crate::fmt; use crate::ops::{Add, AddAssign, Sub, SubAssign}; use crate::sys::time; -use crate::sys_common::mutex::Mutex; +use crate::sys_common::mutex::StaticMutex; use crate::sys_common::FromInner; #[stable(feature = "time", since = "1.3.0")] @@ -243,7 +243,7 @@ impl Instant { return Instant(os_now); } - static LOCK: Mutex = Mutex::new(); + static LOCK: StaticMutex = StaticMutex::new(); static mut LAST_NOW: time::Instant = time::Instant::zero(); unsafe { let _lock = LOCK.lock(); From 825dda80601bdb34ef21065052a8866df0fe0838 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 24 Sep 2020 17:11:16 +0200 Subject: [PATCH 43/60] Fix ui test. This test checks if the compiler complains about accesing a private field before complaining (or crashing) about the private function on it not marked as stable/unstable. The interface of the internal type (sys_common's Mutex) used for this was changed. With this change, it uses another function to test for the same issue. --- src/test/ui/issues/issue-54062.rs | 3 +-- src/test/ui/issues/issue-54062.stderr | 13 +++---------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/test/ui/issues/issue-54062.rs b/src/test/ui/issues/issue-54062.rs index 60a9b00d5d4bd..093d6601d4e2e 100644 --- a/src/test/ui/issues/issue-54062.rs +++ b/src/test/ui/issues/issue-54062.rs @@ -7,7 +7,6 @@ struct Test { fn main() {} fn testing(test: Test) { - let _ = test.comps.inner.lock().unwrap(); + let _ = test.comps.inner.try_lock(); //~^ ERROR: field `inner` of struct `Mutex` is private - //~| ERROR: no method named `unwrap` found } diff --git a/src/test/ui/issues/issue-54062.stderr b/src/test/ui/issues/issue-54062.stderr index e9e8080d4679d..5361ee1d3455f 100644 --- a/src/test/ui/issues/issue-54062.stderr +++ b/src/test/ui/issues/issue-54062.stderr @@ -1,16 +1,9 @@ error[E0616]: field `inner` of struct `Mutex` is private --> $DIR/issue-54062.rs:10:24 | -LL | let _ = test.comps.inner.lock().unwrap(); +LL | let _ = test.comps.inner.try_lock(); | ^^^^^ private field -error[E0599]: no method named `unwrap` found for struct `std::sys_common::mutex::MutexGuard<'_>` in the current scope - --> $DIR/issue-54062.rs:10:37 - | -LL | let _ = test.comps.inner.lock().unwrap(); - | ^^^^^^ method not found in `std::sys_common::mutex::MutexGuard<'_>` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0599, E0616. -For more information about an error, try `rustc --explain E0599`. +For more information about this error, try `rustc --explain E0616`. From 7eea071d1da262783523d3039ad8b316de0d2990 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 27 Sep 2020 22:29:02 +0200 Subject: [PATCH 44/60] Change imports for `cfg(doc)` --- library/std/src/sys/unix/ext/net/addr.rs | 2 +- library/std/src/sys/unix/ext/net/ancillary.rs | 4 +-- library/std/src/sys/unix/ext/net/datagram.rs | 20 +++++++------- library/std/src/sys/unix/ext/net/listener.rs | 5 ++-- library/std/src/sys/unix/ext/net/stream.rs | 26 +++++++++---------- library/std/src/sys/unix/ext/net/tests.rs | 2 +- 6 files changed, 29 insertions(+), 30 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/addr.rs b/library/std/src/sys/unix/ext/net/addr.rs index 15fc5bb5b4e6b..1f9036242eb59 100644 --- a/library/std/src/sys/unix/ext/net/addr.rs +++ b/library/std/src/sys/unix/ext/net/addr.rs @@ -1,7 +1,7 @@ use crate::ffi::OsStr; use crate::os::unix::ffi::OsStrExt; use crate::path::Path; -use crate::sys::unix::cvt; +use crate::sys::cvt; use crate::{ascii, fmt, io, mem}; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 547c9c7dcbe19..9e8da6306ca2d 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -1,3 +1,4 @@ +use super::{sockaddr_un, SocketAddr}; use crate::convert::TryFrom; use crate::io::{self, IoSliceMut}; use crate::marker::PhantomData; @@ -6,8 +7,7 @@ use crate::os::unix::io::RawFd; use crate::path::Path; use crate::ptr::read_unaligned; use crate::slice::from_raw_parts; -use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; -use crate::sys::unix::net::Socket; +use crate::sys::net::Socket; #[cfg(any(target_os = "android", target_os = "linux",))] use libc::{gid_t, pid_t, uid_t}; diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 9d9df6959b267..ce91b403efd70 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -7,12 +7,10 @@ target_os = "netbsd", target_os = "openbsd", ))] -use crate::io::IoSliceMut; -use crate::net::Shutdown; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use crate::path::Path; -use crate::sys::unix::cvt; -use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +use super::{ + recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, sockaddr_un, SocketAddr, + SocketAncillary, +}; #[cfg(any( target_os = "android", target_os = "dragonfly", @@ -22,10 +20,12 @@ use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; target_os = "netbsd", target_os = "openbsd", ))] -use crate::sys::unix::ext::net::ancillary::{ - recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, -}; -use crate::sys::unix::net::Socket; +use crate::io::IoSliceMut; +use crate::net::Shutdown; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::path::Path; +use crate::sys::cvt; +use crate::sys::net::Socket; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; use crate::{fmt, io}; diff --git a/library/std/src/sys/unix/ext/net/listener.rs b/library/std/src/sys/unix/ext/net/listener.rs index 2bedfb74dcb60..9803c6e27462c 100644 --- a/library/std/src/sys/unix/ext/net/listener.rs +++ b/library/std/src/sys/unix/ext/net/listener.rs @@ -1,9 +1,8 @@ +use super::{sockaddr_un, SocketAddr, UnixStream}; use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::Path; +use crate::sys::cvt; use crate::sys::net::Socket; -use crate::sys::unix::cvt; -use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; -use crate::sys::unix::ext::net::stream::UnixStream; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, io, mem}; diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 8337487ff47bc..e13c863bdbb77 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -1,3 +1,16 @@ +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +use super::{ + recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, sockaddr_un, SocketAddr, + SocketAncillary, +}; use crate::fmt; use crate::io::{self, Initializer, IoSlice, IoSliceMut}; use crate::net::Shutdown; @@ -15,19 +28,6 @@ use crate::os::unix::ucred; use crate::path::Path; use crate::sys::cvt; use crate::sys::net::Socket; -use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", -))] -use crate::sys::unix::ext::net::ancillary::{ - recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, -}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index cb04de1882803..bf114bbe6e5b8 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -2,7 +2,7 @@ use super::*; use crate::io::prelude::*; use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; use crate::iter::FromIterator; -use crate::sys::unix::ext::io::AsRawFd; +use crate::os::unix::io::AsRawFd; use crate::sys_common::io::test::tmpdir; use crate::thread; use crate::time::Duration; From 6533c29bea5416c62c098f369553ed2b6c2c9eae Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 29 Sep 2020 18:00:19 -0400 Subject: [PATCH 45/60] Remove --cfg dox from rustdoc.rs This was added in https://github.com/rust-lang/rust/pull/53076 because several dependencies were using `cfg(dox)` instead of `cfg(rustdoc)`. I ran `rg 'cfg\(dox\)'` on the source tree with no matches, so I think this is now safe to remove. --- src/bootstrap/bin/rustdoc.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index cb58eb89ad870..95c55ffe75a6d 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -24,14 +24,10 @@ fn main() { let mut dylib_path = bootstrap::util::dylib_path(); dylib_path.insert(0, PathBuf::from(libdir.clone())); - //FIXME(misdreavus): once stdsimd uses cfg(doc) instead of cfg(dox), remove the `--cfg dox` - //arguments here let mut cmd = Command::new(rustdoc); cmd.args(&args) .arg("--cfg") .arg(format!("stage{}", stage)) - .arg("--cfg") - .arg("dox") .arg("--sysroot") .arg(&sysroot) .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); From 351f850d33e0a000c8fd8b43e71e03d91f470383 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 29 Sep 2020 18:20:21 -0400 Subject: [PATCH 46/60] Remove unused --cfg stageN --- src/bootstrap/bin/rustdoc.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index 95c55ffe75a6d..cba17c8e6085b 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -11,7 +11,6 @@ fn main() { let args = env::args_os().skip(1).collect::>(); let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set"); let libdir = env::var_os("RUSTDOC_LIBDIR").expect("RUSTDOC_LIBDIR was not set"); - let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set"); let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); use std::str::FromStr; @@ -26,8 +25,6 @@ fn main() { let mut cmd = Command::new(rustdoc); cmd.args(&args) - .arg("--cfg") - .arg(format!("stage{}", stage)) .arg("--sysroot") .arg(&sysroot) .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); From 384eb2691f53bb0cdeb17a5ccf73c83e861d9aa1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 30 Sep 2020 22:49:59 +0300 Subject: [PATCH 47/60] rustc_metadata: Do not forget to encode inherent impls for foreign types --- compiler/rustc_metadata/src/rmeta/encoder.rs | 1 + .../auxiliary/extern-types-inherent-impl.rs | 9 ++++++++ .../ui/extern/extern-types-inherent-impl.rs | 23 ++++++++++++------- 3 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 757156e5a7d27..f58a792ef585e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1753,6 +1753,7 @@ impl EncodeContext<'a, 'tcx> { self.encode_const_stability(def_id); self.encode_deprecation(def_id); self.encode_item_type(def_id); + self.encode_inherent_implementations(def_id); if let hir::ForeignItemKind::Fn(..) = nitem.kind { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.encode_variances_of(def_id); diff --git a/src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs b/src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs new file mode 100644 index 0000000000000..a1efe181843b2 --- /dev/null +++ b/src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs @@ -0,0 +1,9 @@ +#![feature(extern_types)] + +extern "C" { + pub type CrossCrate; +} + +impl CrossCrate { + pub fn foo(&self) {} +} diff --git a/src/test/ui/extern/extern-types-inherent-impl.rs b/src/test/ui/extern/extern-types-inherent-impl.rs index fc98f55dc07bf..3f09ac7b8c388 100644 --- a/src/test/ui/extern/extern-types-inherent-impl.rs +++ b/src/test/ui/extern/extern-types-inherent-impl.rs @@ -1,19 +1,26 @@ -// run-pass -#![allow(dead_code)] // Test that inherent impls can be defined for extern types. +// check-pass +// aux-build:extern-types-inherent-impl.rs + #![feature(extern_types)] -extern { - type A; +extern crate extern_types_inherent_impl; +use extern_types_inherent_impl::CrossCrate; + +extern "C" { + type Local; } -impl A { - fn foo(&self) { } +impl Local { + fn foo(&self) {} } -fn use_foo(x: &A) { +fn use_foo(x: &Local, y: &CrossCrate) { + Local::foo(x); x.foo(); + CrossCrate::foo(y); + y.foo(); } -fn main() { } +fn main() {} From 20202da09e86bd15ffcd0ce22b5ebe8a27ef17a0 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 30 Sep 2020 20:00:09 -0700 Subject: [PATCH 48/60] Improve the example for ptr::copy Fixes #77220 --- library/core/src/intrinsics.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 243fc7bfaa51f..18b54c8ea3e89 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1901,11 +1901,21 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { /// ``` /// use std::ptr; /// +/// /// # Safety: +/// /// * `ptr` must be correctly aligned for its type and non-zero. +/// /// * `ptr` must be valid for reads of `elts` contiguous objects of type `T`. +/// /// * Those elements must not be used after calling this function. /// # #[allow(dead_code)] /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { /// let mut dst = Vec::with_capacity(elts); -/// dst.set_len(elts); +/// +/// // SAFETY: Our precondition ensures the source is aligned and valid, +/// // and `Vec::with_capacity` ensures that we have usable space to write them. /// ptr::copy(ptr, dst.as_mut_ptr(), elts); +/// +/// // SAFETY: We created it with this much capacity earlier, +/// // and the previous `copy` has initialized these elements. +/// dst.set_len(elts); /// dst /// } /// ``` From 8164218181d8fc22a7247a686ec9af9d61f70d44 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 1 Oct 2020 01:23:08 -0400 Subject: [PATCH 49/60] Fix some clippy issues Found while working on https://github.com/rust-lang/rust/pull/77351; these are just the ones that could be fixed automatically. --- library/test/src/bench.rs | 2 +- library/test/src/formatters/pretty.rs | 2 +- library/test/src/formatters/terse.rs | 4 ++-- library/test/src/lib.rs | 8 +++----- library/test/src/stats.rs | 2 +- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/library/test/src/bench.rs b/library/test/src/bench.rs index a03cf9dd79115..10546de17641d 100644 --- a/library/test/src/bench.rs +++ b/library/test/src/bench.rs @@ -159,7 +159,7 @@ where return summ5; } - total_run = total_run + loop_run; + total_run += loop_run; // Longest we ever run for is 3s. if total_run > Duration::from_secs(3) { return summ5; diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs index 4a93e084df178..8c90b57b3bac3 100644 --- a/library/test/src/formatters/pretty.rs +++ b/library/test/src/formatters/pretty.rs @@ -139,7 +139,7 @@ impl PrettyFormatter { stdouts.push_str(&format!("---- {} stdout ----\n", f.name)); let output = String::from_utf8_lossy(stdout); stdouts.push_str(&output); - stdouts.push_str("\n"); + stdouts.push('\n'); } } if !stdouts.is_empty() { diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs index 5a264d2005744..1ae7846a99e3a 100644 --- a/library/test/src/formatters/terse.rs +++ b/library/test/src/formatters/terse.rs @@ -114,7 +114,7 @@ impl TerseFormatter { stdouts.push_str(&format!("---- {} stdout ----\n", f.name)); let output = String::from_utf8_lossy(stdout); stdouts.push_str(&output); - stdouts.push_str("\n"); + stdouts.push('\n'); } } if !stdouts.is_empty() { @@ -140,7 +140,7 @@ impl TerseFormatter { fail_out.push_str(&format!("---- {} stdout ----\n", f.name)); let output = String::from_utf8_lossy(stdout); fail_out.push_str(&output); - fail_out.push_str("\n"); + fail_out.push('\n'); } } if !fail_out.is_empty() { diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index caea4b1e30941..b0b81f85fe08f 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -237,11 +237,9 @@ where let event = TestEvent::TeFiltered(filtered_descs); notify_about_test_event(event)?; - let (filtered_tests, filtered_benchs): (Vec<_>, _) = - filtered_tests.into_iter().partition(|e| match e.testfn { - StaticTestFn(_) | DynTestFn(_) => true, - _ => false, - }); + let (filtered_tests, filtered_benchs): (Vec<_>, _) = filtered_tests + .into_iter() + .partition(|e| matches!(e.testfn, StaticTestFn(_) | DynTestFn(_))); let concurrency = opts.test_threads.unwrap_or_else(get_concurrency); diff --git a/library/test/src/stats.rs b/library/test/src/stats.rs index 1a2cb893a8a4f..53f3889447453 100644 --- a/library/test/src/stats.rs +++ b/library/test/src/stats.rs @@ -199,7 +199,7 @@ impl Stats for [f64] { let mut v: f64 = 0.0; for s in self { let x = *s - mean; - v = v + x * x; + v += x * x; } // N.B., this is _supposed to be_ len-1, not len. If you // change it back to len, you will be calculating a From e58f3d352d1c6f0ccc0b089754939bbcb7a2c294 Mon Sep 17 00:00:00 2001 From: scottmcm Date: Thu, 1 Oct 2020 07:04:20 +0000 Subject: [PATCH 50/60] Things are only moved if non-copy --- library/core/src/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 18b54c8ea3e89..4e4b31c0cb4ce 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1904,7 +1904,7 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { /// /// # Safety: /// /// * `ptr` must be correctly aligned for its type and non-zero. /// /// * `ptr` must be valid for reads of `elts` contiguous objects of type `T`. -/// /// * Those elements must not be used after calling this function. +/// /// * Those elements must not be used after calling this function unless `T: Copy`. /// # #[allow(dead_code)] /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { /// let mut dst = Vec::with_capacity(elts); From 424347527dca62e648425298838e6b6bca095c9f Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sat, 26 Sep 2020 20:49:22 +0200 Subject: [PATCH 51/60] BTreeMap: use Unique::from to avoid a cast where type information exists --- library/alloc/src/collections/btree/node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index c3f27c105994f..ba08f65f903e5 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -128,7 +128,7 @@ impl BoxedNode { } fn from_internal(node: Box>) -> Self { - BoxedNode { ptr: Box::into_unique(node).cast() } + BoxedNode { ptr: Unique::from(&mut Box::leak(node).data) } } unsafe fn from_ptr(ptr: NonNull>) -> Self { From 8b2bdfd453d196f4d108183efe1f5a58292d5f11 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 20 Sep 2020 14:46:10 +0200 Subject: [PATCH 52/60] Improve std::sys::windows::compat. - Module name can now be any string, not just an ident. (Not all Windows api modules are valid Rust identifiers.) - Adds c::FuncName::is_available() for checking if a function is really available without having to do a duplicate lookup. - Add comment explaining the lack of locking. - Use `$_:block` to simplify the macro_rules. - Apply allow(unused_variables) only to the fallback instead of everything. --- library/std/src/sys/windows/c.rs | 2 +- library/std/src/sys/windows/compat.rs | 61 +++++++++++++++------------ 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index f440442ca3062..559c4dc9c7cd8 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -1032,7 +1032,7 @@ extern "system" { // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. compat_fn! { - kernel32: + "kernel32": pub fn CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, _lpTargetFileName: LPCWSTR, diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs index d6d433f9d086b..897f49445eefb 100644 --- a/library/std/src/sys/windows/compat.rs +++ b/library/std/src/sys/windows/compat.rs @@ -12,7 +12,6 @@ //! function is available but afterwards it's just a load and a jump. use crate::ffi::CString; -use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::c; pub fn lookup(module: &str, symbol: &str) -> Option { @@ -28,45 +27,53 @@ pub fn lookup(module: &str, symbol: &str) -> Option { } } -pub fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, fallback: usize) -> usize { - let value = lookup(module, symbol).unwrap_or(fallback); - ptr.store(value, Ordering::SeqCst); - value -} - macro_rules! compat_fn { - ($module:ident: $( + ($module:literal: $( $(#[$meta:meta])* - pub fn $symbol:ident($($argname:ident: $argtype:ty),*) - -> $rettype:ty { - $($body:expr);* - } + pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $body:block )*) => ($( - #[allow(unused_variables)] $(#[$meta])* - pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { + pub mod $symbol { + use super::*; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::mem; - type F = unsafe extern "system" fn($($argtype),*) -> $rettype; static PTR: AtomicUsize = AtomicUsize::new(0); + #[allow(unused_variables)] + unsafe extern "system" fn fallback($($argname: $argtype),*) -> $rettype $body + + #[cold] fn load() -> usize { - crate::sys::compat::store_func(&PTR, - stringify!($module), - stringify!($symbol), - fallback as usize) + // There is no locking here. It's okay if this is executed by multiple threads in + // parallel. `lookup` will result in the same value, and it's okay if they overwrite + // eachothers result as long as they do so atomically. We don't need any guarantees + // about memory ordering, as this involves just a single atomic variable which is + // not used to protect or order anything else. + let addr = crate::sys::compat::lookup($module, stringify!($symbol)) + .unwrap_or(fallback as usize); + PTR.store(addr, Ordering::Relaxed); + addr } - unsafe extern "system" fn fallback($($argname: $argtype),*) - -> $rettype { - $($body);* + + fn addr() -> usize { + match PTR.load(Ordering::Relaxed) { + 0 => load(), + addr => addr, + } } - let addr = match PTR.load(Ordering::SeqCst) { - 0 => load(), - n => n, - }; - mem::transmute::(addr)($($argname),*) + #[allow(dead_code)] + pub fn is_available() -> bool { + addr() != fallback as usize + } + + pub unsafe fn call($($argname: $argtype),*) -> $rettype { + type F = unsafe extern "system" fn($($argtype),*) -> $rettype; + mem::transmute::(addr())($($argname),*) + } } + + pub use $symbol::call as $symbol; )*) } From 93310efdbe80d01e287b935e0f86a834bc6c4574 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 20 Sep 2020 14:49:04 +0200 Subject: [PATCH 53/60] Use AcquireSRWLockExclusive::is_available() instead of an extra lookup. --- library/std/src/sys/windows/mutex.rs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs index 1e09b95c87285..1028dc9ff50c4 100644 --- a/library/std/src/sys/windows/mutex.rs +++ b/library/std/src/sys/windows/mutex.rs @@ -23,7 +23,6 @@ use crate::cell::{Cell, UnsafeCell}; use crate::mem::{self, MaybeUninit}; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::c; -use crate::sys::compat; pub struct Mutex { // This is either directly an SRWLOCK (if supported), or a Box otherwise. @@ -40,8 +39,8 @@ struct Inner { #[derive(Clone, Copy)] enum Kind { - SRWLock = 1, - CriticalSection = 2, + SRWLock, + CriticalSection, } #[inline] @@ -130,21 +129,11 @@ impl Mutex { } fn kind() -> Kind { - static KIND: AtomicUsize = AtomicUsize::new(0); - - let val = KIND.load(Ordering::SeqCst); - if val == Kind::SRWLock as usize { - return Kind::SRWLock; - } else if val == Kind::CriticalSection as usize { - return Kind::CriticalSection; + if c::AcquireSRWLockExclusive::is_available() { + Kind::SRWLock + } else { + Kind::CriticalSection } - - let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") { - None => Kind::CriticalSection, - Some(..) => Kind::SRWLock, - }; - KIND.store(ret as usize, Ordering::SeqCst); - ret } pub struct ReentrantMutex { From 09cbaf436713ddb864725a50ccdff67e2ab9bc77 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 20 Sep 2020 16:30:11 +0200 Subject: [PATCH 54/60] Formatting. --- library/std/src/sys/windows/mutex.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs index 1028dc9ff50c4..e2aaca59fe2f3 100644 --- a/library/std/src/sys/windows/mutex.rs +++ b/library/std/src/sys/windows/mutex.rs @@ -129,11 +129,7 @@ impl Mutex { } fn kind() -> Kind { - if c::AcquireSRWLockExclusive::is_available() { - Kind::SRWLock - } else { - Kind::CriticalSection - } + if c::AcquireSRWLockExclusive::is_available() { Kind::SRWLock } else { Kind::CriticalSection } } pub struct ReentrantMutex { From 63b6007d5b68023e02a43c2f9c2ed21762cd8011 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 Oct 2020 16:49:55 +0200 Subject: [PATCH 55/60] Work around potential merging/duplication issues in sys/windows/compat. --- library/std/src/sys/windows/compat.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs index 897f49445eefb..3f25f05e1b9a7 100644 --- a/library/std/src/sys/windows/compat.rs +++ b/library/std/src/sys/windows/compat.rs @@ -38,11 +38,28 @@ macro_rules! compat_fn { use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::mem; + type F = unsafe extern "system" fn($($argtype),*) -> $rettype; + static PTR: AtomicUsize = AtomicUsize::new(0); #[allow(unused_variables)] unsafe extern "system" fn fallback($($argname: $argtype),*) -> $rettype $body + /// This address is stored in `PTR` to incidate an unavailable API. + /// + /// This way, call() will end up calling fallback() if it is unavailable. + /// + /// This is a `static` to avoid rustc duplicating `fn fallback()` + /// into both load() and is_available(), which would break + /// is_available()'s comparison. By using the same static variable + /// in both places, they'll refer to the same (copy of the) + /// function. + /// + /// LLVM merging the address of fallback with other functions + /// (because of unnamed_addr) is fine, since it's only compared to + /// an address from GetProcAddress from an external dll. + static FALLBACK: F = fallback; + #[cold] fn load() -> usize { // There is no locking here. It's okay if this is executed by multiple threads in @@ -51,7 +68,7 @@ macro_rules! compat_fn { // about memory ordering, as this involves just a single atomic variable which is // not used to protect or order anything else. let addr = crate::sys::compat::lookup($module, stringify!($symbol)) - .unwrap_or(fallback as usize); + .unwrap_or(FALLBACK as usize); PTR.store(addr, Ordering::Relaxed); addr } @@ -65,11 +82,10 @@ macro_rules! compat_fn { #[allow(dead_code)] pub fn is_available() -> bool { - addr() != fallback as usize + addr() != FALLBACK as usize } pub unsafe fn call($($argname: $argtype),*) -> $rettype { - type F = unsafe extern "system" fn($($argtype),*) -> $rettype; mem::transmute::(addr())($($argname),*) } } From 2140d80a9d69cce7a9fb2c90051af4328737a446 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 Oct 2020 17:32:23 +0200 Subject: [PATCH 56/60] Add note about possible future improvement Co-authored-by: David Tolnay --- compiler/rustc_feature/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index c70f3c3cd402f..68ac2841fed70 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -113,6 +113,8 @@ fn find_lang_feature_issue(feature: Symbol) -> Option { } const fn to_nonzero(n: Option) -> Option { + // Can be replaced with `n.and_then(NonZeroU32::new)` if that is ever usable + // in const context. Requires https://github.com/rust-lang/rfcs/pull/2632. match n { None => None, Some(n) => NonZeroU32::new(n), From ca987789ea2da972dee6e84e7aa8017840553bf9 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 30 Sep 2020 21:25:31 -0400 Subject: [PATCH 57/60] Update stdarch submodule The primary purpose is to get the fixes from https://github.com/rust-lang/stdarch/pull/920 and https://github.com/rust-lang/stdarch/pull/922. The other changes included are https://github.com/rust-lang/stdarch/pull/917 and https://github.com/rust-lang/stdarch/pull/919. --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index b422b0180f7c3..3c3664355ef46 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit b422b0180f7c3327375a63a3e6660e432b9ec75d +Subproject commit 3c3664355ef46e788b53080e521d6542fbddfd84 From cd159fd7f9f8eec5792e6fd7f1b347ea3e028301 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 19 Aug 2020 03:05:44 -0700 Subject: [PATCH 58/60] Uplift drop-bounds lint from clippy --- compiler/rustc_lint/src/lib.rs | 3 + compiler/rustc_lint/src/traits.rs | 79 +++++++++++++++++++ library/core/src/mem/mod.rs | 1 + .../ui/drop-bounds/drop-bounds-impl-drop.rs | 14 ++++ src/test/ui/drop-bounds/drop-bounds.rs | 19 +++++ src/test/ui/drop-bounds/drop-bounds.stderr | 50 ++++++++++++ 6 files changed, 166 insertions(+) create mode 100644 compiler/rustc_lint/src/traits.rs create mode 100644 src/test/ui/drop-bounds/drop-bounds-impl-drop.rs create mode 100644 src/test/ui/drop-bounds/drop-bounds.rs create mode 100644 src/test/ui/drop-bounds/drop-bounds.stderr diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 33caedfc19826..49e80f9d8a531 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -53,6 +53,7 @@ mod non_ascii_idents; mod nonstandard_style; mod passes; mod redundant_semicolon; +mod traits; mod types; mod unused; @@ -75,6 +76,7 @@ use internal::*; use non_ascii_idents::*; use nonstandard_style::*; use redundant_semicolon::*; +use traits::*; use types::*; use unused::*; @@ -157,6 +159,7 @@ macro_rules! late_lint_passes { MissingDebugImplementations: MissingDebugImplementations::default(), ArrayIntoIter: ArrayIntoIter, ClashingExternDeclarations: ClashingExternDeclarations::new(), + DropTraitConstraints: DropTraitConstraints, ] ); }; diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs new file mode 100644 index 0000000000000..d4f79036e5a18 --- /dev/null +++ b/compiler/rustc_lint/src/traits.rs @@ -0,0 +1,79 @@ +use crate::LateContext; +use crate::LateLintPass; +use crate::LintContext; +use rustc_hir as hir; +use rustc_span::symbol::sym; + +declare_lint! { + /// The `drop_bounds` lint checks for generics with `std::ops::Drop` as + /// bounds. + /// + /// ### Example + /// + /// ```rust + /// fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `Drop` bounds do not really accomplish anything. A type may have + /// compiler-generated drop glue without implementing the `Drop` trait + /// itself. The `Drop` trait also only has one method, `Drop::drop`, and + /// that function is by fiat not callable in user code. So there is really + /// no use case for using `Drop` in trait bounds. + /// + /// The most likely use case of a drop bound is to distinguish between + /// types that have destructors and types that don't. Combined with + /// specialization, a naive coder would write an implementation that + /// assumed a type could be trivially dropped, then write a specialization + /// for `T: Drop` that actually calls the destructor. Except that doing so + /// is not correct; String, for example, doesn't actually implement Drop, + /// but because String contains a Vec, assuming it can be trivially dropped + /// will leak memory. + pub DROP_BOUNDS, + Warn, + "bounds of the form `T: Drop` are useless" +} + +declare_lint_pass!( + /// Lint for bounds of the form `T: Drop`, which usually + /// indicate an attempt to emulate `std::mem::needs_drop`. + DropTraitConstraints => [DROP_BOUNDS] +); + +impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { + use rustc_middle::ty::PredicateAtom::*; + + let def_id = cx.tcx.hir().local_def_id(item.hir_id); + let predicates = cx.tcx.explicit_predicates_of(def_id); + for &(predicate, span) in predicates.predicates { + let trait_predicate = match predicate.skip_binders() { + Trait(trait_predicate, _constness) => trait_predicate, + _ => continue, + }; + let def_id = trait_predicate.trait_ref.def_id; + if cx.tcx.lang_items().drop_trait() == Some(def_id) { + // Explicitly allow `impl Drop`, a drop-guards-as-Voldemort-type pattern. + if trait_predicate.trait_ref.self_ty().is_impl_trait() { + continue; + } + cx.struct_span_lint(DROP_BOUNDS, span, |lint| { + let needs_drop = match cx.tcx.get_diagnostic_item(sym::needs_drop) { + Some(needs_drop) => needs_drop, + None => return, + }; + let msg = format!( + "bounds on `{}` are useless, consider instead \ + using `{}` to detect if a type has a destructor", + predicate, + cx.tcx.def_path_str(needs_drop) + ); + lint.build(&msg).emit() + }); + } + } + } +} diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index aa1b5529df222..a2c7da6e6958e 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -568,6 +568,7 @@ pub unsafe fn align_of_val_raw(val: *const T) -> usize { #[inline] #[stable(feature = "needs_drop", since = "1.21.0")] #[rustc_const_stable(feature = "const_needs_drop", since = "1.36.0")] +#[rustc_diagnostic_item = "needs_drop"] pub const fn needs_drop() -> bool { intrinsics::needs_drop::() } diff --git a/src/test/ui/drop-bounds/drop-bounds-impl-drop.rs b/src/test/ui/drop-bounds/drop-bounds-impl-drop.rs new file mode 100644 index 0000000000000..063efc7b31abd --- /dev/null +++ b/src/test/ui/drop-bounds/drop-bounds-impl-drop.rs @@ -0,0 +1,14 @@ +// run-pass +#![deny(drop_bounds)] +// As a special exemption, `impl Drop` in the return position raises no error. +// This allows a convenient way to return an unnamed drop guard. +fn voldemort_type() -> impl Drop { + struct Voldemort; + impl Drop for Voldemort { + fn drop(&mut self) {} + } + Voldemort +} +fn main() { + let _ = voldemort_type(); +} diff --git a/src/test/ui/drop-bounds/drop-bounds.rs b/src/test/ui/drop-bounds/drop-bounds.rs new file mode 100644 index 0000000000000..c73538278d3be --- /dev/null +++ b/src/test/ui/drop-bounds/drop-bounds.rs @@ -0,0 +1,19 @@ +#![deny(drop_bounds)] +fn foo() {} //~ ERROR +fn bar() +where + U: Drop, //~ ERROR +{ +} +fn baz(_x: impl Drop) {} //~ ERROR +struct Foo { //~ ERROR + _x: T +} +struct Bar where U: Drop { //~ ERROR + _x: U +} +trait Baz: Drop { //~ ERROR +} +impl Baz for T { //~ ERROR +} +fn main() {} diff --git a/src/test/ui/drop-bounds/drop-bounds.stderr b/src/test/ui/drop-bounds/drop-bounds.stderr new file mode 100644 index 0000000000000..15ba4c9a64989 --- /dev/null +++ b/src/test/ui/drop-bounds/drop-bounds.stderr @@ -0,0 +1,50 @@ +error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor + --> $DIR/drop-bounds.rs:2:11 + | +LL | fn foo() {} + | ^^^^ + | +note: the lint level is defined here + --> $DIR/drop-bounds.rs:1:9 + | +LL | #![deny(drop_bounds)] + | ^^^^^^^^^^^ + +error: bounds on `U: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor + --> $DIR/drop-bounds.rs:5:8 + | +LL | U: Drop, + | ^^^^ + +error: bounds on `impl Drop: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor + --> $DIR/drop-bounds.rs:8:17 + | +LL | fn baz(_x: impl Drop) {} + | ^^^^ + +error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor + --> $DIR/drop-bounds.rs:9:15 + | +LL | struct Foo { + | ^^^^ + +error: bounds on `U: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor + --> $DIR/drop-bounds.rs:12:24 + | +LL | struct Bar where U: Drop { + | ^^^^ + +error: bounds on `Self: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor + --> $DIR/drop-bounds.rs:15:12 + | +LL | trait Baz: Drop { + | ^^^^ + +error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor + --> $DIR/drop-bounds.rs:17:9 + | +LL | impl Baz for T { + | ^^^^ + +error: aborting due to 7 previous errors + From 4bf5c45865b86d8f95fb3f435aeecb229b9ef705 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Mon, 28 Sep 2020 22:28:47 +0200 Subject: [PATCH 59/60] Remove outdated line from `publish_toolstate` hook --- src/tools/publish_toolstate.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 9cfde0c232b33..33613e2dc107b 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -157,9 +157,6 @@ def issue( cc @{}, do you think you would have time to do the follow-up work? If so, that would be great! - - And nominating for compiler team prioritization. - ''').format( relevant_pr_number, tool, status_description, REPOS.get(tool), relevant_pr_user From 1c2c336dbc3c78efe8f28e9149020aa151b24361 Mon Sep 17 00:00:00 2001 From: Waffle Date: Fri, 2 Oct 2020 00:30:19 +0300 Subject: [PATCH 60/60] Link `new` method in `DefautHasher`s doc --- library/std/src/collections/hash/map.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 1bb835e1eada1..4424a4c199226 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -2836,11 +2836,10 @@ impl DefaultHasher { #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] impl Default for DefaultHasher { - // FIXME: here should link `new` to [DefaultHasher::new], but it occurs intra-doc link - // resolution failure when re-exporting libstd items. When #56922 fixed, - // link `new` to [DefaultHasher::new] again. - /// Creates a new `DefaultHasher` using `new`. + /// Creates a new `DefaultHasher` using [`new`]. /// See its documentation for more. + /// + /// [`new`]: DefaultHasher::new fn default() -> DefaultHasher { DefaultHasher::new() }