summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Gohman <dev@sunfishcode.online>2021-11-23 15:05:14 -0800
committerDan Gohman <dev@sunfishcode.online>2021-12-01 15:09:22 -0800
commit0419855dd4c47f499a029b7f6abb3191e9072bde (patch)
tree05ceb3dc7463d185099db77b65e23bd8b7f959b4
parent3a784ab8171887c83281b514c69d6a773957deb5 (diff)
downloadrust-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.rs1
-rw-r--r--library/core/src/net/c/bsd.rs28
-rw-r--r--library/core/src/net/c/linux_like.rs30
-rw-r--r--library/core/src/net/c/mod.rs4
-rw-r--r--library/core/src/net/mod.rs2
-rw-r--r--library/core/src/os/mod.rs11
-rw-r--r--library/core/src/os/unix/mod.rs34
-rw-r--r--library/core/src/os/unix/net/addr.rs317
-rw-r--r--library/core/src/os/unix/net/mod.rs8
-rw-r--r--library/std/src/lib.rs3
-rw-r--r--library/std/src/os/unix/net/addr.rs93
-rw-r--r--library/std/src/os/unix/net/datagram.rs20
-rw-r--r--library/std/src/os/unix/net/listener.rs8
-rw-r--r--library/std/src/os/unix/net/stream.rs8
m---------src/tools/cargo0
m---------src/tools/rust-analyzer45
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