about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-01-28 15:20:23 +0100
committerGitHub <noreply@github.com>2022-01-28 15:20:23 +0100
commit18c8d0da644682e69268c2247aed1f74b9132018 (patch)
tree68f421e35819c89015e81a334661c95cdc4292c2
parent9f15c4d08b7d5eec77f6a6e4caa2ee720fbc51c2 (diff)
parent35f578fc789a14106b2e32b80846ecd62ccf9672 (diff)
downloadrust-18c8d0da644682e69268c2247aed1f74b9132018.tar.gz
rust-18c8d0da644682e69268c2247aed1f74b9132018.zip
Rollup merge of #93239 - Thomasdezeeuw:socketaddr_creation, r=m-ou-se
Add os::unix::net::SocketAddr::from_path

Creates a new SocketAddr from a path, supports both regular paths and
abstract namespaces.

Note that `SocketAddr::from_abstract_namespace` could be removed after this as `SocketAddr::unix` also supports abstract namespaces.

Updates #65275
Unblocks https://github.com/tokio-rs/mio/issues/1527

r? `@m-ou-se`
-rw-r--r--library/std/src/os/unix/net/addr.rs56
1 files changed, 48 insertions, 8 deletions
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
index f450e41bfea..9dbd4548bc9 100644
--- a/library/std/src/os/unix/net/addr.rs
+++ b/library/std/src/os/unix/net/addr.rs
@@ -2,7 +2,7 @@ use crate::ffi::OsStr;
 use crate::os::unix::ffi::OsStrExt;
 use crate::path::Path;
 use crate::sys::cvt;
-use crate::{ascii, fmt, io, iter, mem};
+use crate::{ascii, fmt, io, mem, ptr};
 
 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
 #[cfg(not(unix))]
@@ -22,8 +22,9 @@ fn sun_path_offset(addr: &libc::sockaddr_un) -> 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();
+pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
+    // SAFETY: All zeros is a valid representation for `sockaddr_un`.
+    let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() };
     addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
 
     let bytes = path.as_os_str().as_bytes();
@@ -41,11 +42,13 @@ pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un,
             &"path must be shorter than SUN_LEN",
         ));
     }
-    for (dst, src) in iter::zip(&mut addr.sun_path, bytes) {
-        *dst = *src as libc::c_char;
-    }
-    // null byte for pathname addresses is already there because we zeroed the
-    // struct
+    // SAFETY: `bytes` and `addr.sun_path` are not overlapping and
+    // both point to valid memory.
+    // NOTE: We zeroed the memory above, so the path is already null
+    // terminated.
+    unsafe {
+        ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len())
+    };
 
     let mut len = sun_path_offset(&addr) + bytes.len();
     match bytes.get(0) {
@@ -127,6 +130,43 @@ impl SocketAddr {
         Ok(SocketAddr { addr, len })
     }
 
+    /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
+    ///
+    /// # Errors
+    ///
+    /// Returns an error if the path is longer than `SUN_LEN` or if it contains
+    /// NULL bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(unix_socket_creation)]
+    /// use std::os::unix::net::SocketAddr;
+    /// use std::path::Path;
+    ///
+    /// # fn main() -> std::io::Result<()> {
+    /// let address = SocketAddr::from_path("/path/to/socket")?;
+    /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// Creating a `SocketAddr` with a NULL byte results in an error.
+    ///
+    /// ```
+    /// #![feature(unix_socket_creation)]
+    /// use std::os::unix::net::SocketAddr;
+    ///
+    /// assert!(SocketAddr::from_path("/path/with/\0/bytes").is_err());
+    /// ```
+    #[unstable(feature = "unix_socket_creation", issue = "93423")]
+    pub fn from_path<P>(path: P) -> io::Result<SocketAddr>
+    where
+        P: AsRef<Path>,
+    {
+        sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len })
+    }
+
     /// Returns `true` if the address is unnamed.
     ///
     /// # Examples