diff options
author | Dan Gohman <dev@sunfishcode.online> | 2021-11-23 15:05:14 -0800 |
---|---|---|
committer | Dan Gohman <dev@sunfishcode.online> | 2021-12-01 15:09:22 -0800 |
commit | 0419855dd4c47f499a029b7f6abb3191e9072bde (patch) | |
tree | 05ceb3dc7463d185099db77b65e23bd8b7f959b4 | |
parent | 3a784ab8171887c83281b514c69d6a773957deb5 (diff) | |
download | rust-0419855dd4c47f499a029b7f6abb3191e9072bde.tar.gz |
Move Unix's `SocketAddr` into core.
Windows' recent addition of Unix-domain sockets [uses UTF-8 path names],
so `SocketAddr` with a byte-oriented path buffer is a reasonably
portable type.
[uses UTF-8 path names]: https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
-rw-r--r-- | library/core/src/lib.rs | 1 | ||||
-rw-r--r-- | library/core/src/net/c/bsd.rs | 28 | ||||
-rw-r--r-- | library/core/src/net/c/linux_like.rs | 30 | ||||
-rw-r--r-- | library/core/src/net/c/mod.rs | 4 | ||||
-rw-r--r-- | library/core/src/net/mod.rs | 2 | ||||
-rw-r--r-- | library/core/src/os/mod.rs | 11 | ||||
-rw-r--r-- | library/core/src/os/unix/mod.rs | 34 | ||||
-rw-r--r-- | library/core/src/os/unix/net/addr.rs | 317 | ||||
-rw-r--r-- | library/core/src/os/unix/net/mod.rs | 8 | ||||
-rw-r--r-- | library/std/src/lib.rs | 3 | ||||
-rw-r--r-- | library/std/src/os/unix/net/addr.rs | 93 | ||||
-rw-r--r-- | library/std/src/os/unix/net/datagram.rs | 20 | ||||
-rw-r--r-- | library/std/src/os/unix/net/listener.rs | 8 | ||||
-rw-r--r-- | library/std/src/os/unix/net/stream.rs | 8 | ||||
m--------- | src/tools/cargo | 0 | ||||
m--------- | src/tools/rust-analyzer | 45 |
16 files changed, 502 insertions, 110 deletions
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index f050505b8f3..e016e882f63 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -315,6 +315,7 @@ pub mod iter; pub mod lazy; pub mod net; pub mod option; +pub mod os; pub mod panic; pub mod panicking; pub mod pin; diff --git a/library/core/src/net/c/bsd.rs b/library/core/src/net/c/bsd.rs index dde2176cc2f..bfb281a97d7 100644 --- a/library/core/src/net/c/bsd.rs +++ b/library/core/src/net/c/bsd.rs @@ -6,6 +6,26 @@ pub struct sockaddr { pub sa_data: [u8; 14], } +#[cfg(any(target_os = "ios", target_os = "macos"))] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +struct sockaddr_in { + pub sin_len: u8, + pub sin_family: sa_family_t, + pub sin_port: u16, + pub sin_addr: super::in_addr, + pub sin_zero: [c_char; 8], +} + +#[cfg(any(target_os = "netbsd", target_os = "openbsd"))] +pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: sa_family_t, + pub sin_port: u16, + pub sin_addr: super::in_addr, + pub sin_zero: [i8; 8], +} + #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct sockaddr_in6 { @@ -17,6 +37,14 @@ pub struct sockaddr_in6 { pub sin6_scope_id: u32, } +#[repr(C)] +pub struct sockaddr_un { + pub sun_len: u8, + pub sun_family: sa_family_t, + pub sun_path: [c_char; 104], +} + +pub type socklen_t = u32; pub type sa_family_t = u8; pub const AF_INET: sa_family_t = 2; diff --git a/library/core/src/net/c/linux_like.rs b/library/core/src/net/c/linux_like.rs index 0d7d96bf5c1..fb16323e8af 100644 --- a/library/core/src/net/c/linux_like.rs +++ b/library/core/src/net/c/linux_like.rs @@ -1,5 +1,12 @@ #[repr(C)] #[derive(Debug, Copy, Clone)] +pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [u8; 14], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] pub struct sockaddr_in { pub sin_family: sa_family_t, pub sin_port: u16, @@ -17,7 +24,30 @@ pub struct sockaddr_in6 { pub sin6_scope_id: u32, } +#[repr(C)] +#[derive(Clone, Debug)] +pub struct sockaddr_un { + pub sun_family: sa_family_t, + pub sun_path: [u8; 108], +} + +#[repr(C)] +#[derive(Debug)] +pub struct sockaddr_storage { + pub ss_family: sa_family_t, + __ss_align: usize, + #[cfg(target_pointer_width = "32")] + __ss_pad2: [u8; 128 - 2 * 4], + #[cfg(target_pointer_width = "64")] + __ss_pad2: [u8; 128 - 2 * 8], +} + +#[cfg(not(all(target_os = "android", target_pointer_width = "32")))] +pub type socklen_t = u32; +#[cfg(all(target_os = "android", target_pointer_width = "32"))] +pub type socklen_t = i32; pub type sa_family_t = u16; +pub const AF_UNIX: sa_family_t = 1; pub const AF_INET: sa_family_t = 2; pub const AF_INET6: sa_family_t = 10; diff --git a/library/core/src/net/c/mod.rs b/library/core/src/net/c/mod.rs index aba944bb392..9d20e138bf2 100644 --- a/library/core/src/net/c/mod.rs +++ b/library/core/src/net/c/mod.rs @@ -1,5 +1,5 @@ #![allow(non_camel_case_types)] -#![unstable(feature = "none", issue = "none")] +#![unstable(feature = "rustix", issue = "none")] #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -61,4 +61,4 @@ pub struct in6_addr { path = "unsupported.rs" )] mod os; -pub(super) use os::*; +pub(crate) use os::*; diff --git a/library/core/src/net/mod.rs b/library/core/src/net/mod.rs index 7cc9c6f8e1b..5778811671a 100644 --- a/library/core/src/net/mod.rs +++ b/library/core/src/net/mod.rs @@ -54,4 +54,4 @@ const fn ntohs(i: u16) -> u16 { } /* Types with platform-specific representations. */ -mod c; +pub(crate) mod c; diff --git a/library/core/src/os/mod.rs b/library/core/src/os/mod.rs new file mode 100644 index 00000000000..bc51231d053 --- /dev/null +++ b/library/core/src/os/mod.rs @@ -0,0 +1,11 @@ +//! Types with platform-specific representations. +//! +//! This module is for defining types, like `Ipv6Addr`, which have OS-specific +//! representations. It does not do any allocation, as that would belong in the +//! alloc library, and it does not perform any actual I/O, as that would belong +//! in the std library. + +#![stable(feature = "rust1", since = "1.0.0")] + +#[cfg(all(unix, not(target_os = "hermit")))] +pub mod unix; diff --git a/library/core/src/os/unix/mod.rs b/library/core/src/os/unix/mod.rs new file mode 100644 index 00000000000..7b4acf375a9 --- /dev/null +++ b/library/core/src/os/unix/mod.rs @@ -0,0 +1,34 @@ +//! Platform-specific extensions to `std` for Unix platforms. +//! +//! Provides access to platform-level information on Unix platforms, and +//! exposes Unix-specific functions that would otherwise be inappropriate as +//! part of the core `std` library. +//! +//! It exposes more ways to deal with platform-specific strings ([`OsStr`], +//! [`OsString`]), allows to set permissions more granularly, extract low-level +//! file descriptors from files and sockets, and has platform-specific helpers +//! for spawning processes. +//! +//! # Examples +//! +//! ```no_run +//! use std::fs::File; +//! use std::os::unix::prelude::*; +//! +//! fn main() -> std::io::Result<()> { +//! let f = File::create("foo.txt")?; +//! let fd = f.as_raw_fd(); +//! +//! // use fd with native unix bindings +//! +//! Ok(()) +//! } +//! ``` +//! +//! [`OsStr`]: crate::ffi::OsStr +//! [`OsString`]: crate::ffi::OsString + +#![stable(feature = "rust1", since = "1.0.0")] +#![doc(cfg(unix))] + +pub mod net; diff --git a/library/core/src/os/unix/net/addr.rs b/library/core/src/os/unix/net/addr.rs new file mode 100644 index 00000000000..5277967140b --- /dev/null +++ b/library/core/src/os/unix/net/addr.rs @@ -0,0 +1,317 @@ +use crate::ffi::{c_void, ZStr}; +use crate::{ascii, fmt, iter, mem}; + +use crate::net::c as libc; + +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) fn sockaddr_un(path: &ZStr) -> Result<SocketAddr, &'static &'static str> { + let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() }; + addr.sun_family = libc::AF_UNIX as libc::sa_family_t; + + let bytes = path.to_bytes(); + + if bytes.contains(&0) { + return Err(&"paths must not contain interior null bytes"); + } + + if bytes.len() >= addr.sun_path.len() { + return Err(&"path must be shorter than SUN_LEN"); + } + for (dst, src) in iter::zip(&mut addr.sun_path, bytes) { + *dst = *src as u8; + } + // 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, + } + SocketAddr::from_parts(addr, len as libc::socklen_t) +} + +enum AddressKind<'a> { + Unnamed, + Pathname(&'a ZStr), + 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 { + pub(super) addr: libc::sockaddr_un, + pub(super) len: libc::socklen_t, +} + +impl SocketAddr { + /// Constructs a `SocketAddr` representing the given path. + #[unstable(feature = "rustix", issue = "none")] + #[inline] + pub fn from_path(path: &ZStr) -> Result<Self, &'static &'static str> { + sockaddr_un(path) + } + + pub(super) fn from_parts( + addr: libc::sockaddr_un, + mut len: libc::socklen_t, + ) -> Result<SocketAddr, &'static &'static str> { + 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(&"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(()) + /// } + /// ``` + #[must_use] + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn is_unnamed(&self) -> bool { + matches!(self.address(), AddressKind::Unnamed) + } + + /// 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 core::ffi::ZStr; + /// + /// 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(ZStr::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")] + #[must_use] + pub fn as_pathname(&self) -> Option<&ZStr> { + if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } + } + + /// Returns the contents of this address if it is an abstract namespace + /// without the leading null byte. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixListener, SocketAddr}; + /// + /// fn main() -> std::io::Result<()> { + /// let namespace = b"hidden"; + /// let namespace_addr = SocketAddr::from_abstract_namespace(&namespace[..])?; + /// let socket = UnixListener::bind_addr(&namespace_addr)?; + /// let local_addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(local_addr.as_abstract_namespace(), Some(&namespace[..])); + /// Ok(()) + /// } + /// ``` + #[doc(cfg(any(target_os = "android", target_os = "linux")))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn as_abstract_namespace(&self) -> Option<&[u8]> { + if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None } + } + + fn address(&self) -> AddressKind<'_> { + let len = self.len as usize - sun_path_offset(&self.addr); + let path = unsafe { mem::transmute::<&[_], &[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(unsafe { ZStr::from_bytes_with_nul_unchecked(&path[..len]) }) + } + } + + /// Creates an abstract domain socket address from a namespace + /// + /// An abstract address does not create a file unlike traditional path-based + /// Unix sockets. The advantage of this is that the address will disappear when + /// the socket bound to it is closed, so no filesystem clean up is required. + /// + /// The leading null byte for the abstract namespace is automatically added. + /// + /// This is a Linux-specific extension. See more at [`unix(7)`]. + /// + /// [`unix(7)`]: https://man7.org/linux/man-pages/man7/unix.7.html + /// + /// # Errors + /// + /// This will return an error if the given namespace is too long + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// use std::os::unix::net::{UnixListener, SocketAddr}; + /// + /// fn main() -> std::io::Result<()> { + /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?; + /// let listener = match UnixListener::bind_addr(&addr) { + /// Ok(sock) => sock, + /// Err(err) => { + /// println!("Couldn't bind: {:?}", err); + /// return Err(err); + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[doc(cfg(any(target_os = "android", target_os = "linux")))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_abstract", issue = "85410")] + pub fn from_abstract_namespace(namespace: &[u8]) -> Result<SocketAddr, &'static &'static str> { + unsafe { + let mut addr: libc::sockaddr_un = mem::zeroed(); + addr.sun_family = libc::AF_UNIX as libc::sa_family_t; + + if namespace.len() + 1 > addr.sun_path.len() { + return Err(&"namespace must be shorter than SUN_LEN"); + } + + crate::ptr::copy_nonoverlapping( + namespace.as_ptr(), + addr.sun_path.as_mut_ptr().offset(1) as *mut u8, + namespace.len(), + ); + let len = (sun_path_offset(&addr) + 1 + namespace.len()) as libc::socklen_t; + SocketAddr::from_parts(addr, len) + } + } +} + +#[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), + } + } +} + +/// Access to the platform-specific parts of of `SocketAddr`. +#[unstable(feature = "rustix", issue = "none")] +pub trait SocketAddrExt { + /// Construct a `SocketAddr` from raw parts. + #[unstable(feature = "rustix", issue = "none")] + unsafe fn from_raw( + raw: *const c_void, + len: libc::socklen_t, + ) -> Result<Self, &'static &'static str> + where + Self: Sized; + + /// View the raw parts of a `SocketAddr`. + #[unstable(feature = "rustix", issue = "none")] + fn as_raw(&self) -> (*const c_void, libc::socklen_t); +} + +#[unstable(feature = "rustix", issue = "none")] +impl SocketAddrExt for SocketAddr { + #[inline] + unsafe fn from_raw( + raw: *const c_void, + len: libc::socklen_t, + ) -> Result<Self, &'static &'static str> { + SocketAddr::from_parts(unsafe { raw.cast::<libc::sockaddr_un>().read() }, len) + } + + #[inline] + fn as_raw(&self) -> (*const c_void, libc::socklen_t) { + let ptr: *const _ = &self.addr; + (ptr.cast(), self.len) + } +} diff --git a/library/core/src/os/unix/net/mod.rs b/library/core/src/os/unix/net/mod.rs new file mode 100644 index 00000000000..27810dd5eb0 --- /dev/null +++ b/library/core/src/os/unix/net/mod.rs @@ -0,0 +1,8 @@ +//! Unix-specific networking functionality. + +#![stable(feature = "unix_socket", since = "1.10.0")] + +mod addr; + +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::addr::*; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 504c3b7e9f9..8da88b60e94 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -300,6 +300,7 @@ #![feature(int_log)] #![feature(into_future)] #![feature(intra_doc_pointers)] +#![feature(io_safety)] #![feature(iter_zip)] #![feature(lang_items)] #![feature(linkage)] @@ -328,6 +329,7 @@ #![feature(ptr_internals)] #![feature(rustc_attrs)] #![feature(rustc_private)] +#![feature(rustix)] #![feature(saturating_int_impl)] #![feature(slice_concat_ext)] #![feature(slice_internals)] @@ -347,6 +349,7 @@ #![feature(try_blocks)] #![feature(try_reserve_kind)] #![feature(unboxed_closures)] +#![feature(unix_socket_abstract)] #![feature(unwrap_infallible)] #![feature(vec_into_raw_parts)] #![feature(vec_spare_capacity)] diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index f450e41bfea..2f3fe33e965 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -3,6 +3,7 @@ use crate::os::unix::ffi::OsStrExt; use crate::path::Path; use crate::sys::cvt; use crate::{ascii, fmt, io, iter, mem}; +use core::os::unix::net::SocketAddrExt; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? #[cfg(not(unix))] @@ -55,12 +56,6 @@ pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, 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> { @@ -92,8 +87,7 @@ impl<'a> fmt::Display for AsciiEscaped<'a> { #[derive(Clone)] #[stable(feature = "unix_socket", since = "1.10.0")] pub struct SocketAddr { - pub(super) addr: libc::sockaddr_un, - pub(super) len: libc::socklen_t, + pub(super) inner: core::os::unix::net::SocketAddr, } impl SocketAddr { @@ -101,30 +95,27 @@ impl SocketAddr { where F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int, { + let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() }; + let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t; + let ptr: *mut libc::sockaddr_un = &mut addr; unsafe { - let mut addr: libc::sockaddr_un = mem::zeroed(); - let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t; - cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; - SocketAddr::from_parts(addr, len) + cvt(f(ptr.cast(), &mut len))?; + core::os::unix::net::SocketAddr::from_raw(ptr.cast(), len) + .map(|inner| Self { inner }) + .map_err(|err| io::Error::new_const(io::ErrorKind::InvalidInput, err)) } } pub(super) fn from_parts( addr: libc::sockaddr_un, - mut len: libc::socklen_t, + len: libc::socklen_t, ) -> io::Result<SocketAddr> { - 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_const( - io::ErrorKind::InvalidInput, - &"file descriptor did not correspond to a Unix socket", - )); + let ptr: *const libc::sockaddr_un = &addr; + unsafe { + core::os::unix::net::SocketAddr::from_raw(ptr.cast(), len) + .map(|inner| Self { inner }) + .map_err(|err| io::Error::new_const(io::ErrorKind::InvalidInput, err)) } - - Ok(SocketAddr { addr, len }) } /// Returns `true` if the address is unnamed. @@ -159,7 +150,7 @@ impl SocketAddr { #[must_use] #[stable(feature = "unix_socket", since = "1.10.0")] pub fn is_unnamed(&self) -> bool { - matches!(self.address(), AddressKind::Unnamed) + self.inner.is_unnamed() } /// Returns the contents of this address if it is a `pathname` address. @@ -195,7 +186,10 @@ impl SocketAddr { #[stable(feature = "unix_socket", since = "1.10.0")] #[must_use] pub fn as_pathname(&self) -> Option<&Path> { - if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } + self.inner.as_pathname().map(|path| { + let bytes = path.to_bytes_with_nul(); + OsStr::from_bytes(&bytes[..bytes.len() - 1]).as_ref() + }) } /// Returns the contents of this address if it is an abstract namespace @@ -220,24 +214,7 @@ impl SocketAddr { #[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_abstract", issue = "85410")] pub fn as_abstract_namespace(&self) -> Option<&[u8]> { - if let AddressKind::Abstract(name) = self.address() { Some(name) } 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()) - } + self.inner.as_abstract_namespace() } /// Creates an abstract domain socket address from a namespace @@ -278,35 +255,15 @@ impl SocketAddr { #[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_abstract", issue = "85410")] pub fn from_abstract_namespace(namespace: &[u8]) -> io::Result<SocketAddr> { - unsafe { - let mut addr: libc::sockaddr_un = mem::zeroed(); - addr.sun_family = libc::AF_UNIX as libc::sa_family_t; - - if namespace.len() + 1 > addr.sun_path.len() { - return Err(io::Error::new_const( - io::ErrorKind::InvalidInput, - &"namespace must be shorter than SUN_LEN", - )); - } - - crate::ptr::copy_nonoverlapping( - namespace.as_ptr(), - addr.sun_path.as_mut_ptr().offset(1) as *mut u8, - namespace.len(), - ); - let len = (sun_path_offset(&addr) + 1 + namespace.len()) as libc::socklen_t; - SocketAddr::from_parts(addr, len) - } + core::os::unix::net::SocketAddr::from_abstract_namespace(namespace) + .map(|inner| Self { inner }) + .map_err(|err| io::Error::new_const(io::ErrorKind::InvalidInput, err)) } } #[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), - } + self.inner.fmt(fmt) } } diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index a2caccc7849..7ffdaf0ceef 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -28,6 +28,7 @@ use crate::sys::net::Socket; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; use crate::{fmt, io}; +use core::os::unix::net::SocketAddrExt; #[cfg(any( target_os = "linux", @@ -138,11 +139,8 @@ impl UnixDatagram { pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixDatagram> { unsafe { let socket = UnixDatagram::unbound()?; - cvt(libc::bind( - socket.as_raw_fd(), - &socket_addr.addr as *const _ as *const _, - socket_addr.len as _, - ))?; + let (addr, len) = socket_addr.inner.as_raw(); + cvt(libc::bind(socket.as_raw_fd(), addr as *const _ as *const _, len as _))?; Ok(socket) } } @@ -253,11 +251,8 @@ impl UnixDatagram { #[unstable(feature = "unix_socket_abstract", issue = "85410")] pub fn connect_addr(&self, socket_addr: &SocketAddr) -> io::Result<()> { unsafe { - cvt(libc::connect( - self.as_raw_fd(), - &socket_addr.addr as *const _ as *const _, - socket_addr.len, - ))?; + let (addr, len) = socket_addr.inner.as_raw(); + cvt(libc::connect(self.as_raw_fd(), addr as *const _ as *const _, len))?; } Ok(()) } @@ -566,14 +561,15 @@ impl UnixDatagram { /// ``` #[unstable(feature = "unix_socket_abstract", issue = "85410")] pub fn send_to_addr(&self, buf: &[u8], socket_addr: &SocketAddr) -> io::Result<usize> { + let (addr, len) = socket_addr.inner.as_raw(); unsafe { let count = cvt(libc::sendto( self.as_raw_fd(), buf.as_ptr() as *const _, buf.len(), MSG_NOSIGNAL, - &socket_addr.addr as *const _ as *const _, - socket_addr.len, + addr as *const _ as *const _, + len, ))?; Ok(count as usize) } diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index b23dd6062f6..e5f1d756d92 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -5,6 +5,7 @@ use crate::sys::cvt; use crate::sys::net::Socket; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, io, mem}; +use core::os::unix::net::SocketAddrExt; /// A structure representing a Unix domain socket server. /// @@ -109,11 +110,8 @@ impl UnixListener { pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixListener> { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - cvt(libc::bind( - inner.as_raw_fd(), - &socket_addr.addr as *const _ as *const _, - socket_addr.len as _, - ))?; + let (addr, len) = socket_addr.inner.as_raw(); + cvt(libc::bind(inner.as_raw_fd(), addr as *const _ as *const _, len as _))?; cvt(libc::listen(inner.as_raw_fd(), 128))?; Ok(UnixListener(inner)) } diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 6120d557227..e27f24b1669 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -30,6 +30,7 @@ use crate::sys::cvt; use crate::sys::net::Socket; use crate::sys_common::{AsInner, FromInner}; use crate::time::Duration; +use core::os::unix::net::SocketAddrExt; #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] #[cfg(any( @@ -134,11 +135,8 @@ impl UnixStream { pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result<UnixStream> { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - cvt(libc::connect( - inner.as_raw_fd(), - &socket_addr.addr as *const _ as *const _, - socket_addr.len, - ))?; + let (addr, len) = socket_addr.inner.as_raw(); + cvt(libc::connect(inner.as_raw_fd(), addr as *const _ as *const _, len))?; Ok(UnixStream(inner)) } } diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 294967c53f0c70d598fc54ca189313c86c576ea +Subproject 7f08ace4f1305de7f3b1b0e2f765911957226bd diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer -Subproject d9b2291f546abc77d24499339a72a89127464b9 +Subproject 183ef048f61ae36aa389d1d0345cde940fe788e |