From 633f90b5f2b8419724af12ce9eec11cf487c21c9 Mon Sep 17 00:00:00 2001 From: t4lz Date: Sat, 25 Feb 2023 03:12:45 +0100 Subject: [PATCH 01/17] Add unix socket methods to SockAddr, to enable determining what type of AF_UNIX address it is, if any. Enable retrieving the pathname or abstract address of the socket, if applicable. Also, fix some typos in CONTRIBUTING. --- CONTRIBUTING.md | 4 ++-- src/sockaddr.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ src/sys/unix.rs | 12 ++++++++--- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a6e40972..97c87acc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,7 +39,7 @@ platforms the `all` feature is used, to indicate to the user that they're using API that might is not available on all platforms. The main `Socket` type is defined in `src/socket.rs` with additional methods -defined on in the the `src/sys/*.rs` files, as per above. The methods on +defined in the `src/sys/*.rs` files, as per above. The methods on `Socket` are split into multiple `impl` blocks. The first `impl` block contains a collection of system calls for creating and using the socket, e.g. `socket(2)`, `bind(2)`, `listen(2)`, etc. The other implementation blocks are @@ -51,7 +51,7 @@ such as `Socket::freebind` which is (at the time of writing) only available on Android, Linux and Fuchsia, which is defined in the `src/sys/*.rs` files. Other types are mostly defined in `src/lib.rs`, except for `SockAddr` and -`SockRef` which have there own file. These types follow the same structure as +`SockRef` which have their own file. These types follow the same structure as `Socket`, where OS specific methods are defined in `src/sys/*.rs`, e.g. `Type::cloexec`. diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 0c9c2a52..97d47b4e 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -3,6 +3,7 @@ use std::mem::{self, size_of, MaybeUninit}; use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; use std::path::Path; use std::{fmt, io, ptr}; +use libc::{AF_LOCAL, AF_UNIX, sockaddr_un}; #[cfg(windows)] use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0; @@ -184,12 +185,64 @@ impl SockAddr { self.storage.ss_family == AF_INET6 as sa_family_t } + /// Returns true if this address is for local interprocess communication, i.e. it is from the + /// `AF_UNIX` (AKA `AF_LOCAL`) family, false otherwise. + pub fn is_local(&self) -> bool { + self.storage.ss_family == AF_UNIX as sa_family_t + } + + /// Returns true if this address is an unnamed address from the `AF_UNIX` (AKA `AF_LOCAL`) + /// family (for local interprocess communication), false otherwise. + pub fn is_unnamed(&self) -> bool { + self.as_sockaddr_un() + .map(|storage| { + self.len == crate::sys::offset_of_path(storage) as u32 + }).unwrap_or_default() + } + /// Returns a raw pointer to the address storage. #[cfg(all(unix, not(target_os = "redox")))] pub(crate) const fn as_storage_ptr(&self) -> *const sockaddr_storage { &self.storage } + + /// Returns the underlying `sockaddr_un` object if this addres is from the `AF_UNIX` family, + /// otherwise returns `None`. + fn as_sockaddr_un(&self) -> Option<&mut sockaddr_un> { + self.is_local() + .then(|| { + // SAFETY: if local, i.e. the `ss_family` field is `AF_UNIX` then storage must be a + // `sockaddr_un`. + unsafe { &mut *ptr::addr_of_mut!(storage).cast::() } + }) + } + + /// Returns this address as a `Path` if it is an `AF_UNIX` pathname address, otherwise returns + /// `None`. + pub fn as_pathname(&self) -> Option<&Path> { + self.as_sockaddr_un() + .and_then(|storage| { + (storage.sun_path[0] != 0).then(|| { + // The -1 is for the terminating null. + let path_len = self.len - crate::sys::offset_of_path(storage) - 1; + Path::new(&storage.sun_path[..path_len]) + }) + }) + } + + /// Returns this address as a slice of bytes representing an abstract address if it is an + /// `AF_UNIX` abstracT address, otherwise returns `None`. + pub fn as_abstract_namespace(&self) -> Option<&[u8]> { + self.as_sockaddr_un() + .and_then(|storage| { + (storage.sun_path[0] == 0).then(|| { + let path_len = self.len - crate::sys::offset_of_path(storage); + &storage.sun_path[..path_len] + }) + }) + } + /// Returns this address as a `SocketAddr` if it is in the `AF_INET` (IPv4) /// or `AF_INET6` (IPv6) family, otherwise returns `None`. pub fn as_socket(&self) -> Option { diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 6c4dd363..ef4eaab9 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -569,6 +569,14 @@ impl<'a> MaybeUninitSlice<'a> { } } +/// Returns the offset of the `sun_path` member of the passed unix socket address. +pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize { + let base = storage as *const _ as usize; + let path = ptr::addr_of!(storage.sun_path) as usize; + path - base +} + + #[allow(unsafe_op_in_unsafe_fn)] pub(crate) fn unix_sockaddr(path: &Path) -> io::Result { // SAFETY: a `sockaddr_storage` of all zeros is valid. @@ -603,9 +611,7 @@ pub(crate) fn unix_sockaddr(path: &Path) -> io::Result { ); } - let base = storage as *const _ as usize; - let path = ptr::addr_of!(storage.sun_path) as usize; - let sun_path_offset = path - base; + let sun_path_offset = offset_of_path(storage); sun_path_offset + bytes.len() + match bytes.first() { From 9bfd501ea941332c06ac6e9bb8a956d0bb121f7c Mon Sep 17 00:00:00 2001 From: t4lz Date: Mon, 27 Feb 2023 16:23:35 +0100 Subject: [PATCH 02/17] works on unix. --- src/sockaddr.rs | 105 ++++++++++++++++++++++++++++++++++++++---------- src/sys/unix.rs | 6 +-- 2 files changed, 86 insertions(+), 25 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 97d47b4e..8d63cd3b 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -2,16 +2,18 @@ use std::hash::Hash; use std::mem::{self, size_of, MaybeUninit}; use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; use std::path::Path; -use std::{fmt, io, ptr}; -use libc::{AF_LOCAL, AF_UNIX, sockaddr_un}; +use std::{fmt, io, ptr, slice}; +use std::ffi::OsStr; + +#[cfg(unix)] +use std::os::unix::ffi::OsStrExt; +#[cfg(unix)] +use crate::sys::{sockaddr_un, offset_of_path}; #[cfg(windows)] use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0; -use crate::sys::{ - c_int, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET, - AF_INET6, -}; +use crate::sys::{c_int, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET, AF_INET6, AF_UNIX}; use crate::Domain; /// The address of a socket. @@ -187,7 +189,7 @@ impl SockAddr { /// Returns true if this address is for local interprocess communication, i.e. it is from the /// `AF_UNIX` (AKA `AF_LOCAL`) family, false otherwise. - pub fn is_local(&self) -> bool { + pub fn is_unix(&self) -> bool { self.storage.ss_family == AF_UNIX as sa_family_t } @@ -196,7 +198,11 @@ impl SockAddr { pub fn is_unnamed(&self) -> bool { self.as_sockaddr_un() .map(|storage| { - self.len == crate::sys::offset_of_path(storage) as u32 + self.len == offset_of_path(storage) as u32 + // On some non-linux platforms a zeroed path is returned for unnamed. + // Abstract addresses only exist on Linux. + || (cfg!(not(any(target_os = "linux", target_os = "android"))) + && storage.sun_path[0] == 0) }).unwrap_or_default() } @@ -209,38 +215,63 @@ impl SockAddr { /// Returns the underlying `sockaddr_un` object if this addres is from the `AF_UNIX` family, /// otherwise returns `None`. - fn as_sockaddr_un(&self) -> Option<&mut sockaddr_un> { - self.is_local() + fn as_sockaddr_un(&self) -> Option<&sockaddr_un> { + self.is_unix() .then(|| { // SAFETY: if local, i.e. the `ss_family` field is `AF_UNIX` then storage must be a // `sockaddr_un`. - unsafe { &mut *ptr::addr_of_mut!(storage).cast::() } + unsafe { &*ptr::addr_of!(self.storage).cast::() } }) } + /// Get the length of the path bytes of the address, not including any terminating null. + fn path_len(&self, storage: &sockaddr_un, null_terminated: bool) -> usize { + self.len as usize - offset_of_path(storage) - if null_terminated { 1 } else { 0 } + } + + /// Get a u8 slice for the bytes of the pathname or abstract name. + fn path_bytes(&self, storage: &sockaddr_un, null_terminated: bool) -> &[u8]{ + let path_len = self.path_len(storage, null_terminated); + // SAFETY: the pointed objects of type `i8` have the same memory layout as `u8`. The path is + // the last field in the storage and so it length is equal to + // TOTAL_LENGTH - OFFSET_OF_PATH -1 if the path is null-terminated. + // TOTAL_LENGTH - OFFSET_OF_PATH if the path is not null-terminated. + // There is no safe way to convert a `&[i8]` ot `&[u8]` + unsafe{ slice::from_raw_parts(storage.sun_path.as_ptr() as *const u8, path_len) } + } + /// Returns this address as a `Path` if it is an `AF_UNIX` pathname address, otherwise returns /// `None`. + #[cfg(unix)] pub fn as_pathname(&self) -> Option<&Path> { self.as_sockaddr_un() .and_then(|storage| { - (storage.sun_path[0] != 0).then(|| { + (self.len > offset_of_path(storage) as u32 && storage.sun_path[0] != 0).then(|| { // The -1 is for the terminating null. - let path_len = self.len - crate::sys::offset_of_path(storage) - 1; - Path::new(&storage.sun_path[..path_len]) + let path_slice = self.path_bytes(storage, true); + Path::new::(OsStrExt::from_bytes(path_slice)) }) }) } /// Returns this address as a slice of bytes representing an abstract address if it is an - /// `AF_UNIX` abstracT address, otherwise returns `None`. + /// `AF_UNIX` abstract address, otherwise returns `None`. + /// + /// Abstract addresses are a Linux extension, so this method returns None on all non-Linux + /// platforms. pub fn as_abstract_namespace(&self) -> Option<&[u8]> { - self.as_sockaddr_un() - .and_then(|storage| { - (storage.sun_path[0] == 0).then(|| { - let path_len = self.len - crate::sys::offset_of_path(storage); - &storage.sun_path[..path_len] - }) - }) + #[cfg(any(target_os = "linux", target_os = "android"))] + { + self.as_sockaddr_un() + .and_then(|storage| { + (storage.sun_path[0] == 0).then(|| { + self.path_bytes(storage, false) + }) + }) + + } + #[cfg(not(any(target_os = "linux", target_os = "android")))] + None } /// Returns this address as a `SocketAddr` if it is in the `AF_INET` (IPv4) @@ -396,6 +427,8 @@ unsafe fn any_as_u8_slice(p: &T, size: usize) -> &[u8] { #[cfg(test)] mod tests { + #[cfg(unix)] + use crate::sys::offset_of_path; use super::*; #[test] @@ -404,6 +437,8 @@ mod tests { let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876); let addr = SockAddr::from(std); assert!(addr.is_ipv4()); + assert!(!addr.is_ipv6()); + assert!(!addr.is_unix()); assert_eq!(addr.family(), AF_INET as sa_family_t); assert_eq!(addr.domain(), Domain::IPV4); assert_eq!(addr.len(), size_of::() as socklen_t); @@ -417,6 +452,8 @@ mod tests { assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std))); assert_eq!(addr.as_socket_ipv4(), Some(std)); assert!(addr.as_socket_ipv6().is_none()); + assert!(addr.as_pathname().is_none()); + assert!(addr.as_abstract_namespace().is_none()); } #[test] @@ -425,6 +462,8 @@ mod tests { let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12); let addr = SockAddr::from(std); assert!(addr.is_ipv6()); + assert!(!addr.is_ipv4()); + assert!(!addr.is_unix()); assert_eq!(addr.family(), AF_INET6 as sa_family_t); assert_eq!(addr.domain(), Domain::IPV6); assert_eq!(addr.len(), size_of::() as socklen_t); @@ -438,6 +477,28 @@ mod tests { assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std))); assert!(addr.as_socket_ipv4().is_none()); assert_eq!(addr.as_socket_ipv6(), Some(std)); + assert!(addr.as_pathname().is_none()); + assert!(addr.as_abstract_namespace().is_none()); + } + + #[cfg(unix)] + #[test] + fn unix_pathname() { + let path_str = "/whatever/path"; + let path = Path::new(path_str); + let addr = SockAddr::unix(path).unwrap(); + assert!(addr.is_unix()); + assert!(!addr.is_unnamed()); + assert!(!addr.is_ipv4()); + assert!(!addr.is_ipv6()); + assert_eq!(addr.family(), AF_UNIX as sa_family_t); + assert_eq!(addr.domain(), Domain::UNIX); + let storage = addr.as_sockaddr_un().unwrap(); + // The + 1 is the terminating null. + assert_eq!(addr.len() as usize, offset_of_path(storage) + path_str.len() + 1); + assert_eq!(addr.as_pathname(), Some(path)); + assert!(addr.as_socket_ipv4().is_none()); + assert!(addr.as_socket_ipv6().is_none()); } #[test] diff --git a/src/sys/unix.rs b/src/sys/unix.rs index ef4eaab9..b486c329 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -95,7 +95,7 @@ pub(crate) use libc::IPPROTO_SCTP; pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP}; // Used in `SockAddr`. pub(crate) use libc::{ - sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, + sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_un, sockaddr_storage, socklen_t, }; // Used in `RecvFlags`. #[cfg(not(target_os = "redox"))] @@ -570,7 +570,7 @@ impl<'a> MaybeUninitSlice<'a> { } /// Returns the offset of the `sun_path` member of the passed unix socket address. -pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize { +pub(crate) fn offset_of_path(storage: &sockaddr_un) -> usize { let base = storage as *const _ as usize; let path = ptr::addr_of!(storage.sun_path) as usize; path - base @@ -582,7 +582,7 @@ pub(crate) fn unix_sockaddr(path: &Path) -> io::Result { // SAFETY: a `sockaddr_storage` of all zeros is valid. let mut storage = unsafe { mem::zeroed::() }; let len = { - let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::() }; + let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::() }; let bytes = path.as_os_str().as_bytes(); let too_long = match bytes.first() { From 982417d6361e5da6211dc65423a778393da4bc3a Mon Sep 17 00:00:00 2001 From: t4lz Date: Mon, 27 Feb 2023 18:04:11 +0100 Subject: [PATCH 03/17] unix only. --- src/sockaddr.rs | 99 ++++++------------------------------------------- src/sys/unix.rs | 79 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 88 insertions(+), 90 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 8d63cd3b..c15b999e 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -2,13 +2,7 @@ use std::hash::Hash; use std::mem::{self, size_of, MaybeUninit}; use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; use std::path::Path; -use std::{fmt, io, ptr, slice}; -use std::ffi::OsStr; - -#[cfg(unix)] -use std::os::unix::ffi::OsStrExt; -#[cfg(unix)] -use crate::sys::{sockaddr_un, offset_of_path}; +use std::{fmt, io, ptr}; #[cfg(windows)] use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0; @@ -22,7 +16,7 @@ use crate::Domain; /// [`SocketAddr`], [`SocketAddrV4`], and [`SocketAddrV6`] types. #[derive(Clone)] pub struct SockAddr { - storage: sockaddr_storage, + pub(crate) storage: sockaddr_storage, len: socklen_t, } @@ -193,87 +187,12 @@ impl SockAddr { self.storage.ss_family == AF_UNIX as sa_family_t } - /// Returns true if this address is an unnamed address from the `AF_UNIX` (AKA `AF_LOCAL`) - /// family (for local interprocess communication), false otherwise. - pub fn is_unnamed(&self) -> bool { - self.as_sockaddr_un() - .map(|storage| { - self.len == offset_of_path(storage) as u32 - // On some non-linux platforms a zeroed path is returned for unnamed. - // Abstract addresses only exist on Linux. - || (cfg!(not(any(target_os = "linux", target_os = "android"))) - && storage.sun_path[0] == 0) - }).unwrap_or_default() - } - /// Returns a raw pointer to the address storage. #[cfg(all(unix, not(target_os = "redox")))] pub(crate) const fn as_storage_ptr(&self) -> *const sockaddr_storage { &self.storage } - - /// Returns the underlying `sockaddr_un` object if this addres is from the `AF_UNIX` family, - /// otherwise returns `None`. - fn as_sockaddr_un(&self) -> Option<&sockaddr_un> { - self.is_unix() - .then(|| { - // SAFETY: if local, i.e. the `ss_family` field is `AF_UNIX` then storage must be a - // `sockaddr_un`. - unsafe { &*ptr::addr_of!(self.storage).cast::() } - }) - } - - /// Get the length of the path bytes of the address, not including any terminating null. - fn path_len(&self, storage: &sockaddr_un, null_terminated: bool) -> usize { - self.len as usize - offset_of_path(storage) - if null_terminated { 1 } else { 0 } - } - - /// Get a u8 slice for the bytes of the pathname or abstract name. - fn path_bytes(&self, storage: &sockaddr_un, null_terminated: bool) -> &[u8]{ - let path_len = self.path_len(storage, null_terminated); - // SAFETY: the pointed objects of type `i8` have the same memory layout as `u8`. The path is - // the last field in the storage and so it length is equal to - // TOTAL_LENGTH - OFFSET_OF_PATH -1 if the path is null-terminated. - // TOTAL_LENGTH - OFFSET_OF_PATH if the path is not null-terminated. - // There is no safe way to convert a `&[i8]` ot `&[u8]` - unsafe{ slice::from_raw_parts(storage.sun_path.as_ptr() as *const u8, path_len) } - } - - /// Returns this address as a `Path` if it is an `AF_UNIX` pathname address, otherwise returns - /// `None`. - #[cfg(unix)] - pub fn as_pathname(&self) -> Option<&Path> { - self.as_sockaddr_un() - .and_then(|storage| { - (self.len > offset_of_path(storage) as u32 && storage.sun_path[0] != 0).then(|| { - // The -1 is for the terminating null. - let path_slice = self.path_bytes(storage, true); - Path::new::(OsStrExt::from_bytes(path_slice)) - }) - }) - } - - /// Returns this address as a slice of bytes representing an abstract address if it is an - /// `AF_UNIX` abstract address, otherwise returns `None`. - /// - /// Abstract addresses are a Linux extension, so this method returns None on all non-Linux - /// platforms. - pub fn as_abstract_namespace(&self) -> Option<&[u8]> { - #[cfg(any(target_os = "linux", target_os = "android"))] - { - self.as_sockaddr_un() - .and_then(|storage| { - (storage.sun_path[0] == 0).then(|| { - self.path_bytes(storage, false) - }) - }) - - } - #[cfg(not(any(target_os = "linux", target_os = "android")))] - None - } - /// Returns this address as a `SocketAddr` if it is in the `AF_INET` (IPv4) /// or `AF_INET6` (IPv6) family, otherwise returns `None`. pub fn as_socket(&self) -> Option { @@ -452,8 +371,11 @@ mod tests { assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std))); assert_eq!(addr.as_socket_ipv4(), Some(std)); assert!(addr.as_socket_ipv6().is_none()); - assert!(addr.as_pathname().is_none()); - assert!(addr.as_abstract_namespace().is_none()); + #[cfg(unix)] + { + assert!(addr.as_pathname().is_none()); + assert!(addr.as_abstract_namespace().is_none()); + } } #[test] @@ -477,8 +399,11 @@ mod tests { assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std))); assert!(addr.as_socket_ipv4().is_none()); assert_eq!(addr.as_socket_ipv6(), Some(std)); - assert!(addr.as_pathname().is_none()); - assert!(addr.as_abstract_namespace().is_none()); + #[cfg(unix)] + { + assert!(addr.as_pathname().is_none()); + assert!(addr.as_abstract_namespace().is_none()); + } } #[cfg(unix)] diff --git a/src/sys/unix.rs b/src/sys/unix.rs index b486c329..0ac41f30 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -59,6 +59,7 @@ use std::path::Path; use std::ptr; use std::time::{Duration, Instant}; use std::{io, slice}; +use std::ffi::OsStr; #[cfg(not(any( target_os = "ios", @@ -95,7 +96,7 @@ pub(crate) use libc::IPPROTO_SCTP; pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP}; // Used in `SockAddr`. pub(crate) use libc::{ - sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_un, sockaddr_storage, socklen_t, + sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, }; // Used in `RecvFlags`. #[cfg(not(target_os = "redox"))] @@ -570,7 +571,7 @@ impl<'a> MaybeUninitSlice<'a> { } /// Returns the offset of the `sun_path` member of the passed unix socket address. -pub(crate) fn offset_of_path(storage: &sockaddr_un) -> usize { +pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize { let base = storage as *const _ as usize; let path = ptr::addr_of!(storage.sun_path) as usize; path - base @@ -582,7 +583,7 @@ pub(crate) fn unix_sockaddr(path: &Path) -> io::Result { // SAFETY: a `sockaddr_storage` of all zeros is valid. let mut storage = unsafe { mem::zeroed::() }; let len = { - let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::() }; + let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::() }; let bytes = path.as_os_str().as_bytes(); let too_long = match bytes.first() { @@ -665,6 +666,78 @@ impl SockAddr { None } } + + /// Returns true if this address is an unnamed address from the `AF_UNIX` (AKA `AF_LOCAL`) + /// family (for local interprocess communication), false otherwise. + pub fn is_unnamed(&self) -> bool { + self.as_sockaddr_un() + .map(|storage| { + self.len() == offset_of_path(storage) as u32 + // On some non-linux platforms a zeroed path is returned for unnamed. + // Abstract addresses only exist on Linux. + || (cfg!(not(any(target_os = "linux", target_os = "android"))) + && storage.sun_path[0] == 0) + }).unwrap_or_default() + } + + /// Returns the underlying `sockaddr_un` object if this addres is from the `AF_UNIX` family, + /// otherwise returns `None`. + pub(crate) fn as_sockaddr_un(&self) -> Option<&libc::sockaddr_un> { + self.is_unix() + .then(|| { + // SAFETY: if local, i.e. the `ss_family` field is `AF_UNIX` then storage must be a + // `sockaddr_un`. + unsafe { &*ptr::addr_of!(self.storage).cast::() } + }) + } + + /// Get the length of the path bytes of the address, not including any terminating null. + fn path_len(&self, storage: &libc::sockaddr_un, null_terminated: bool) -> usize { + self.len() as usize - offset_of_path(storage) - if null_terminated { 1 } else { 0 } + } + + /// Get a u8 slice for the bytes of the pathname or abstract name. + fn path_bytes(&self, storage: &libc::sockaddr_un, null_terminated: bool) -> &[u8]{ + let path_len = self.path_len(storage, null_terminated); + // SAFETY: the pointed objects of type `i8` have the same memory layout as `u8`. The path is + // the last field in the storage and so it length is equal to + // TOTAL_LENGTH - OFFSET_OF_PATH -1 if the path is null-terminated. + // TOTAL_LENGTH - OFFSET_OF_PATH if the path is not null-terminated. + // There is no safe way to convert a `&[i8]` ot `&[u8]` + unsafe{ slice::from_raw_parts(storage.sun_path.as_ptr() as *const u8, path_len) } + } + + /// Returns this address as a `Path` if it is an `AF_UNIX` pathname address, otherwise returns + /// `None`. + pub fn as_pathname(&self) -> Option<&Path> { + self.as_sockaddr_un() + .and_then(|storage| { + (self.len() > offset_of_path(storage) as u32 && storage.sun_path[0] != 0).then(|| { + // The -1 is for the terminating null. + let path_slice = self.path_bytes(storage, true); + Path::new::(OsStrExt::from_bytes(path_slice)) + }) + }) + } + + /// Returns this address as a slice of bytes representing an abstract address if it is an + /// `AF_UNIX` abstract address, otherwise returns `None`. + /// + /// Abstract addresses are a Linux extension, so this method returns None on all non-Linux + /// platforms. + pub fn as_abstract_namespace(&self) -> Option<&[u8]> { + #[cfg(any(target_os = "linux", target_os = "android"))] + { + self.as_sockaddr_un() + .and_then(|storage| { + (storage.sun_path[0] == 0).then(|| { + self.path_bytes(storage, false) + }) + }) + } + #[cfg(not(any(target_os = "linux", target_os = "android")))] + None + } } pub(crate) type Socket = c_int; From 30ddffe2d9809fd9ed3ecd32d5f1a901cca0a721 Mon Sep 17 00:00:00 2001 From: t4lz Date: Mon, 27 Feb 2023 18:29:03 +0100 Subject: [PATCH 04/17] tests --- src/sockaddr.rs | 22 ---------------------- tests/socket.rs | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index c15b999e..f908baa8 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -346,8 +346,6 @@ unsafe fn any_as_u8_slice(p: &T, size: usize) -> &[u8] { #[cfg(test)] mod tests { - #[cfg(unix)] - use crate::sys::offset_of_path; use super::*; #[test] @@ -406,26 +404,6 @@ mod tests { } } - #[cfg(unix)] - #[test] - fn unix_pathname() { - let path_str = "/whatever/path"; - let path = Path::new(path_str); - let addr = SockAddr::unix(path).unwrap(); - assert!(addr.is_unix()); - assert!(!addr.is_unnamed()); - assert!(!addr.is_ipv4()); - assert!(!addr.is_ipv6()); - assert_eq!(addr.family(), AF_UNIX as sa_family_t); - assert_eq!(addr.domain(), Domain::UNIX); - let storage = addr.as_sockaddr_un().unwrap(); - // The + 1 is the terminating null. - assert_eq!(addr.len() as usize, offset_of_path(storage) + path_str.len() + 1); - assert_eq!(addr.as_pathname(), Some(path)); - assert!(addr.as_socket_ipv4().is_none()); - assert!(addr.as_socket_ipv6().is_none()); - } - #[test] fn ipv4_eq() { use std::net::Ipv4Addr; diff --git a/tests/socket.rs b/tests/socket.rs index 35b90a52..f1bb5182 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -42,6 +42,7 @@ use std::str; use std::thread; use std::time::Duration; use std::{env, fs}; +use std::path::Path; #[cfg(windows)] use windows_sys::Win32::Foundation::{GetHandleInformation, HANDLE_FLAG_INHERIT}; @@ -144,17 +145,51 @@ fn socket_address_unix() { let addr = SockAddr::unix(string).unwrap(); assert!(addr.as_socket_ipv4().is_none()); assert!(addr.as_socket_ipv6().is_none()); + assert!(!addr.is_ipv4()); + assert!(!addr.is_ipv6()); + assert!(addr.is_unix()); + assert_eq!(addr.domain(), Domain::UNIX); + #[cfg(unix)] + { + assert!(!addr.is_unnamed()); + assert_eq!(addr.as_pathname(), Some(Path::new(string))); + assert_eq!(addr.as_abstract_namespace(), None); + } +} + +#[test] +fn socket_address_unix_unnamed() { + let addr = SockAddr::unix("").unwrap(); + assert!(addr.as_socket_ipv4().is_none()); + assert!(addr.as_socket_ipv6().is_none()); + assert!(!addr.is_ipv4()); + assert!(!addr.is_ipv6()); + assert!(addr.is_unix()); + assert_eq!(addr.domain(), Domain::UNIX); + #[cfg(unix)] + { + assert!(addr.is_unnamed()); + assert_eq!(addr.as_pathname(), None); + assert_eq!(addr.as_abstract_namespace(), None); + } } #[test] #[cfg(all(any(target_os = "linux", target_os = "android"), feature = "all"))] fn socket_address_unix_abstract_namespace() { let path = "\0h".repeat(108 / 2); - let addr = SockAddr::unix(path).unwrap(); + let addr = SockAddr::unix(&path).unwrap(); assert_eq!( addr.len() as usize, std::mem::size_of::() ); + assert!(addr.is_unnamed()); + assert_eq!( + addr.as_abstract_namespace(), + Some(path.as_bytes()) + ); + assert!(addr.as_pathname().is_none()); + assert!(!addr.is_unnamed()); } #[test] From 7c10f96700df50a2a8e8e19407e3ec220cd34a7e Mon Sep 17 00:00:00 2001 From: t4lz Date: Mon, 27 Feb 2023 19:12:39 +0100 Subject: [PATCH 05/17] fix abstract. --- src/sys/unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 0ac41f30..d5ded750 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -730,7 +730,7 @@ impl SockAddr { { self.as_sockaddr_un() .and_then(|storage| { - (storage.sun_path[0] == 0).then(|| { + (self.len() > offset_of_path(storage) as u32 && storage.sun_path[0] == 0).then(|| { self.path_bytes(storage, false) }) }) From d0161dde7ae438e484a269f8de7fc18989296607 Mon Sep 17 00:00:00 2001 From: t4lz Date: Mon, 27 Feb 2023 19:14:06 +0100 Subject: [PATCH 06/17] fmt --- src/sockaddr.rs | 5 ++++- src/sys/unix.rs | 44 ++++++++++++++++++++------------------------ tests/socket.rs | 7 ++----- 3 files changed, 26 insertions(+), 30 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index f908baa8..8407beb9 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -7,7 +7,10 @@ use std::{fmt, io, ptr}; #[cfg(windows)] use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0; -use crate::sys::{c_int, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET, AF_INET6, AF_UNIX}; +use crate::sys::{ + c_int, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET, + AF_INET6, AF_UNIX, +}; use crate::Domain; /// The address of a socket. diff --git a/src/sys/unix.rs b/src/sys/unix.rs index d5ded750..74be1b2c 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -7,6 +7,7 @@ // except according to those terms. use std::cmp::min; +use std::ffi::OsStr; #[cfg(not(target_os = "redox"))] use std::io::IoSlice; use std::marker::PhantomData; @@ -59,7 +60,6 @@ use std::path::Path; use std::ptr; use std::time::{Duration, Instant}; use std::{io, slice}; -use std::ffi::OsStr; #[cfg(not(any( target_os = "ios", @@ -577,7 +577,6 @@ pub(crate) fn offset_of_path(storage: &libc::sockaddr_un) -> usize { path - base } - #[allow(unsafe_op_in_unsafe_fn)] pub(crate) fn unix_sockaddr(path: &Path) -> io::Result { // SAFETY: a `sockaddr_storage` of all zeros is valid. @@ -677,18 +676,18 @@ impl SockAddr { // Abstract addresses only exist on Linux. || (cfg!(not(any(target_os = "linux", target_os = "android"))) && storage.sun_path[0] == 0) - }).unwrap_or_default() + }) + .unwrap_or_default() } /// Returns the underlying `sockaddr_un` object if this addres is from the `AF_UNIX` family, /// otherwise returns `None`. pub(crate) fn as_sockaddr_un(&self) -> Option<&libc::sockaddr_un> { - self.is_unix() - .then(|| { - // SAFETY: if local, i.e. the `ss_family` field is `AF_UNIX` then storage must be a - // `sockaddr_un`. - unsafe { &*ptr::addr_of!(self.storage).cast::() } - }) + self.is_unix().then(|| { + // SAFETY: if local, i.e. the `ss_family` field is `AF_UNIX` then storage must be a + // `sockaddr_un`. + unsafe { &*ptr::addr_of!(self.storage).cast::() } + }) } /// Get the length of the path bytes of the address, not including any terminating null. @@ -697,27 +696,26 @@ impl SockAddr { } /// Get a u8 slice for the bytes of the pathname or abstract name. - fn path_bytes(&self, storage: &libc::sockaddr_un, null_terminated: bool) -> &[u8]{ + fn path_bytes(&self, storage: &libc::sockaddr_un, null_terminated: bool) -> &[u8] { let path_len = self.path_len(storage, null_terminated); // SAFETY: the pointed objects of type `i8` have the same memory layout as `u8`. The path is // the last field in the storage and so it length is equal to // TOTAL_LENGTH - OFFSET_OF_PATH -1 if the path is null-terminated. // TOTAL_LENGTH - OFFSET_OF_PATH if the path is not null-terminated. // There is no safe way to convert a `&[i8]` ot `&[u8]` - unsafe{ slice::from_raw_parts(storage.sun_path.as_ptr() as *const u8, path_len) } + unsafe { slice::from_raw_parts(storage.sun_path.as_ptr() as *const u8, path_len) } } /// Returns this address as a `Path` if it is an `AF_UNIX` pathname address, otherwise returns /// `None`. pub fn as_pathname(&self) -> Option<&Path> { - self.as_sockaddr_un() - .and_then(|storage| { - (self.len() > offset_of_path(storage) as u32 && storage.sun_path[0] != 0).then(|| { - // The -1 is for the terminating null. - let path_slice = self.path_bytes(storage, true); - Path::new::(OsStrExt::from_bytes(path_slice)) - }) + self.as_sockaddr_un().and_then(|storage| { + (self.len() > offset_of_path(storage) as u32 && storage.sun_path[0] != 0).then(|| { + // The -1 is for the terminating null. + let path_slice = self.path_bytes(storage, true); + Path::new::(OsStrExt::from_bytes(path_slice)) }) + }) } /// Returns this address as a slice of bytes representing an abstract address if it is an @@ -728,12 +726,10 @@ impl SockAddr { pub fn as_abstract_namespace(&self) -> Option<&[u8]> { #[cfg(any(target_os = "linux", target_os = "android"))] { - self.as_sockaddr_un() - .and_then(|storage| { - (self.len() > offset_of_path(storage) as u32 && storage.sun_path[0] == 0).then(|| { - self.path_bytes(storage, false) - }) - }) + self.as_sockaddr_un().and_then(|storage| { + (self.len() > offset_of_path(storage) as u32 && storage.sun_path[0] == 0) + .then(|| self.path_bytes(storage, false)) + }) } #[cfg(not(any(target_os = "linux", target_os = "android")))] None diff --git a/tests/socket.rs b/tests/socket.rs index f1bb5182..8185ff06 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -38,11 +38,11 @@ use std::num::NonZeroUsize; use std::os::unix::io::AsRawFd; #[cfg(windows)] use std::os::windows::io::AsRawSocket; +use std::path::Path; use std::str; use std::thread; use std::time::Duration; use std::{env, fs}; -use std::path::Path; #[cfg(windows)] use windows_sys::Win32::Foundation::{GetHandleInformation, HANDLE_FLAG_INHERIT}; @@ -184,10 +184,7 @@ fn socket_address_unix_abstract_namespace() { std::mem::size_of::() ); assert!(addr.is_unnamed()); - assert_eq!( - addr.as_abstract_namespace(), - Some(path.as_bytes()) - ); + assert_eq!(addr.as_abstract_namespace(), Some(path.as_bytes())); assert!(addr.as_pathname().is_none()); assert!(!addr.is_unnamed()); } From 531fb675e27dde32ee755693758cac590dbfe4e8 Mon Sep 17 00:00:00 2001 From: t4lz Date: Mon, 27 Feb 2023 19:18:04 +0100 Subject: [PATCH 07/17] fix tests. --- tests/socket.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/socket.rs b/tests/socket.rs index 8185ff06..49104a0c 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -183,7 +183,7 @@ fn socket_address_unix_abstract_namespace() { addr.len() as usize, std::mem::size_of::() ); - assert!(addr.is_unnamed()); + assert!(!addr.is_unnamed()); assert_eq!(addr.as_abstract_namespace(), Some(path.as_bytes())); assert!(addr.as_pathname().is_none()); assert!(!addr.is_unnamed()); From 0285cdc8a9f3cbedfd02ad560faad380bca51ec4 Mon Sep 17 00:00:00 2001 From: t4lz Date: Mon, 27 Feb 2023 19:19:52 +0100 Subject: [PATCH 08/17] unused import in tests. --- tests/socket.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/socket.rs b/tests/socket.rs index 49104a0c..8bafa8a9 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -38,6 +38,7 @@ use std::num::NonZeroUsize; use std::os::unix::io::AsRawFd; #[cfg(windows)] use std::os::windows::io::AsRawSocket; +#[cfg(unix)] use std::path::Path; use std::str; use std::thread; From 52c581482f3645095904c2a0cf41e9882b3537bb Mon Sep 17 00:00:00 2001 From: t4lz Date: Tue, 28 Feb 2023 09:11:33 +0100 Subject: [PATCH 09/17] CR: as_ptr instead of addr_of directly. --- src/sockaddr.rs | 2 +- src/sys/unix.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 8407beb9..d0c23184 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -19,7 +19,7 @@ use crate::Domain; /// [`SocketAddr`], [`SocketAddrV4`], and [`SocketAddrV6`] types. #[derive(Clone)] pub struct SockAddr { - pub(crate) storage: sockaddr_storage, + storage: sockaddr_storage, len: socklen_t, } diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 74be1b2c..5b4ad9b7 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -686,7 +686,7 @@ impl SockAddr { self.is_unix().then(|| { // SAFETY: if local, i.e. the `ss_family` field is `AF_UNIX` then storage must be a // `sockaddr_un`. - unsafe { &*ptr::addr_of!(self.storage).cast::() } + unsafe { &*self.as_ptr().cast::() } }) } From 968aaf558a12b176e3582776cb5751aacaee52a8 Mon Sep 17 00:00:00 2001 From: t4lz Date: Wed, 1 Mar 2023 11:12:46 +0100 Subject: [PATCH 10/17] CR: don't mention AF_LOCAL. --- src/sockaddr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index d0c23184..fbedfe99 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -184,8 +184,8 @@ impl SockAddr { self.storage.ss_family == AF_INET6 as sa_family_t } - /// Returns true if this address is for local interprocess communication, i.e. it is from the - /// `AF_UNIX` (AKA `AF_LOCAL`) family, false otherwise. + /// Returns true if this address is of a unix socket (for local interprocess communication), + /// i.e. it is from the `AF_UNIX` family, false otherwise. pub fn is_unix(&self) -> bool { self.storage.ss_family == AF_UNIX as sa_family_t } From 8375cea06dc3ca108bda593ff6b8d87a82666d8c Mon Sep 17 00:00:00 2001 From: t4lz Date: Wed, 1 Mar 2023 11:38:10 +0100 Subject: [PATCH 11/17] CR: abstract unix docket addresses on Fuchsia --- src/sys/unix.rs | 6 +++--- tests/socket.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 5b4ad9b7..6b956f96 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -674,7 +674,7 @@ impl SockAddr { self.len() == offset_of_path(storage) as u32 // On some non-linux platforms a zeroed path is returned for unnamed. // Abstract addresses only exist on Linux. - || (cfg!(not(any(target_os = "linux", target_os = "android"))) + || (cfg!(not(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))) && storage.sun_path[0] == 0) }) .unwrap_or_default() @@ -724,14 +724,14 @@ impl SockAddr { /// Abstract addresses are a Linux extension, so this method returns None on all non-Linux /// platforms. pub fn as_abstract_namespace(&self) -> Option<&[u8]> { - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))] { self.as_sockaddr_un().and_then(|storage| { (self.len() > offset_of_path(storage) as u32 && storage.sun_path[0] == 0) .then(|| self.path_bytes(storage, false)) }) } - #[cfg(not(any(target_os = "linux", target_os = "android")))] + #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "fuchsia")))] None } } diff --git a/tests/socket.rs b/tests/socket.rs index 8bafa8a9..dfd3fee8 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -176,7 +176,7 @@ fn socket_address_unix_unnamed() { } #[test] -#[cfg(all(any(target_os = "linux", target_os = "android"), feature = "all"))] +#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "fuchsia"), feature = "all"))] fn socket_address_unix_abstract_namespace() { let path = "\0h".repeat(108 / 2); let addr = SockAddr::unix(&path).unwrap(); From 0c4e1be5d00ede38c5c4808959908ee999e9814b Mon Sep 17 00:00:00 2001 From: t4lz Date: Wed, 1 Mar 2023 12:31:26 +0100 Subject: [PATCH 12/17] CR: Don't return initial null of abstract address. --- src/sys/unix.rs | 42 +++++++++++++++++++++++++++--------------- tests/socket.rs | 8 ++++++-- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 6b956f96..4e8090c0 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -690,29 +690,41 @@ impl SockAddr { }) } - /// Get the length of the path bytes of the address, not including any terminating null. - fn path_len(&self, storage: &libc::sockaddr_un, null_terminated: bool) -> usize { - self.len() as usize - offset_of_path(storage) - if null_terminated { 1 } else { 0 } + /// Get the length of the path bytes of the address, not including the terminating or initial + /// (for abstract names) null byte. + /// + /// Should not be called on unnamed addresses. + fn path_len(&self, storage: &libc::sockaddr_un) -> usize { + debug_assert!(!self.is_unnamed()); + self.len() as usize - offset_of_path(storage) - 1 } /// Get a u8 slice for the bytes of the pathname or abstract name. - fn path_bytes(&self, storage: &libc::sockaddr_un, null_terminated: bool) -> &[u8] { - let path_len = self.path_len(storage, null_terminated); + /// + /// Should not be called on unnamed addresses. + fn path_bytes(&self, storage: &libc::sockaddr_un, abstract_name: bool) -> &[u8] { + debug_assert!(!self.is_unnamed()); // SAFETY: the pointed objects of type `i8` have the same memory layout as `u8`. The path is - // the last field in the storage and so it length is equal to - // TOTAL_LENGTH - OFFSET_OF_PATH -1 if the path is null-terminated. - // TOTAL_LENGTH - OFFSET_OF_PATH if the path is not null-terminated. + // the last field in the storage and so its length is equal to + // TOTAL_LENGTH - OFFSET_OF_PATH -1 + // Where the 1 is either a terminating null if we have a pathname address, or the initial + // null byte, if it's an abstract name address. In the latter case, the path bytes start + // after the initial null byte, hence the `offset`. // There is no safe way to convert a `&[i8]` ot `&[u8]` - unsafe { slice::from_raw_parts(storage.sun_path.as_ptr() as *const u8, path_len) } + unsafe { + slice::from_raw_parts( + (storage.sun_path.as_ptr() as *const u8).offset(abstract_name as isize), + self.path_len(storage), + ) + } } - /// Returns this address as a `Path` if it is an `AF_UNIX` pathname address, otherwise returns - /// `None`. + /// Returns this address as a `Path` reference if it is an `AF_UNIX` pathname address, otherwise + /// returns `None`. pub fn as_pathname(&self) -> Option<&Path> { self.as_sockaddr_un().and_then(|storage| { (self.len() > offset_of_path(storage) as u32 && storage.sun_path[0] != 0).then(|| { - // The -1 is for the terminating null. - let path_slice = self.path_bytes(storage, true); + let path_slice = self.path_bytes(storage, false); Path::new::(OsStrExt::from_bytes(path_slice)) }) }) @@ -721,14 +733,14 @@ impl SockAddr { /// Returns this address as a slice of bytes representing an abstract address if it is an /// `AF_UNIX` abstract address, otherwise returns `None`. /// - /// Abstract addresses are a Linux extension, so this method returns None on all non-Linux + /// Abstract addresses are a Linux extension, so this method returns `None` on all non-Linux /// platforms. pub fn as_abstract_namespace(&self) -> Option<&[u8]> { #[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))] { self.as_sockaddr_un().and_then(|storage| { (self.len() > offset_of_path(storage) as u32 && storage.sun_path[0] == 0) - .then(|| self.path_bytes(storage, false)) + .then(|| self.path_bytes(storage, true)) }) } #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "fuchsia")))] diff --git a/tests/socket.rs b/tests/socket.rs index dfd3fee8..4d4bb4f5 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -176,7 +176,10 @@ fn socket_address_unix_unnamed() { } #[test] -#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "fuchsia"), feature = "all"))] +#[cfg(all( + any(target_os = "linux", target_os = "android", target_os = "fuchsia"), + feature = "all" +))] fn socket_address_unix_abstract_namespace() { let path = "\0h".repeat(108 / 2); let addr = SockAddr::unix(&path).unwrap(); @@ -185,7 +188,8 @@ fn socket_address_unix_abstract_namespace() { std::mem::size_of::() ); assert!(!addr.is_unnamed()); - assert_eq!(addr.as_abstract_namespace(), Some(path.as_bytes())); + // The first byte is the opening null bytes of an abstract address, should not be included. + assert_eq!(addr.as_abstract_namespace(), Some(&path.as_bytes()[1..])); assert!(addr.as_pathname().is_none()); assert!(!addr.is_unnamed()); } From d936f1306ac2e275b92fbcc7874c89de34ed459f Mon Sep 17 00:00:00 2001 From: t4lz Date: Wed, 1 Mar 2023 17:35:37 +0100 Subject: [PATCH 13/17] CR: typo Co-authored-by: Thomas de Zeeuw --- src/sys/unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 4e8090c0..9d8ff819 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -710,7 +710,7 @@ impl SockAddr { // Where the 1 is either a terminating null if we have a pathname address, or the initial // null byte, if it's an abstract name address. In the latter case, the path bytes start // after the initial null byte, hence the `offset`. - // There is no safe way to convert a `&[i8]` ot `&[u8]` + // There is no safe way to convert a `&[i8]` to `&[u8]` unsafe { slice::from_raw_parts( (storage.sun_path.as_ptr() as *const u8).offset(abstract_name as isize), From b4ac3070142f2448b23c84b00d16882630d82a62 Mon Sep 17 00:00:00 2001 From: t4lz Date: Wed, 1 Mar 2023 17:42:31 +0100 Subject: [PATCH 14/17] CR: don't mention AF_LOCAL --- src/sys/unix.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 9d8ff819..4f44865e 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -666,8 +666,8 @@ impl SockAddr { } } - /// Returns true if this address is an unnamed address from the `AF_UNIX` (AKA `AF_LOCAL`) - /// family (for local interprocess communication), false otherwise. + /// Returns true if this address is an unnamed address from the `AF_UNIX` family (for local + /// interprocess communication), false otherwise. pub fn is_unnamed(&self) -> bool { self.as_sockaddr_un() .map(|storage| { @@ -684,8 +684,8 @@ impl SockAddr { /// otherwise returns `None`. pub(crate) fn as_sockaddr_un(&self) -> Option<&libc::sockaddr_un> { self.is_unix().then(|| { - // SAFETY: if local, i.e. the `ss_family` field is `AF_UNIX` then storage must be a - // `sockaddr_un`. + // SAFETY: if unix socket, i.e. the `ss_family` field is `AF_UNIX` then storage must be + // a `sockaddr_un`. unsafe { &*self.as_ptr().cast::() } }) } From e78bbd942af997b813ea6a860fa86993f13d05f1 Mon Sep 17 00:00:00 2001 From: t4lz Date: Fri, 3 Mar 2023 18:10:04 +0100 Subject: [PATCH 15/17] No unix sockets on Fuchsia. Co-authored-by: Thomas de Zeeuw --- src/sys/unix.rs | 8 +++++--- tests/socket.rs | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 4f44865e..c9a5b211 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -674,7 +674,8 @@ impl SockAddr { self.len() == offset_of_path(storage) as u32 // On some non-linux platforms a zeroed path is returned for unnamed. // Abstract addresses only exist on Linux. - || (cfg!(not(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))) + // NOTE: although Fuchsia does define `AF_UNIX` it's not actually implemented. + || (cfg!(not(any(target_os = "linux", target_os = "android"))) && storage.sun_path[0] == 0) }) .unwrap_or_default() @@ -736,14 +737,15 @@ impl SockAddr { /// Abstract addresses are a Linux extension, so this method returns `None` on all non-Linux /// platforms. pub fn as_abstract_namespace(&self) -> Option<&[u8]> { - #[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))] + // NOTE: although Fuchsia does define `AF_UNIX` it's not actually implemented. + #[cfg(any(target_os = "linux", target_os = "android"))] { self.as_sockaddr_un().and_then(|storage| { (self.len() > offset_of_path(storage) as u32 && storage.sun_path[0] == 0) .then(|| self.path_bytes(storage, true)) }) } - #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "fuchsia")))] + #[cfg(not(any(target_os = "linux", target_os = "android")))] None } } diff --git a/tests/socket.rs b/tests/socket.rs index 4d4bb4f5..db9f3e21 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -177,7 +177,7 @@ fn socket_address_unix_unnamed() { #[test] #[cfg(all( - any(target_os = "linux", target_os = "android", target_os = "fuchsia"), + any(target_os = "linux", target_os = "android"), feature = "all" ))] fn socket_address_unix_abstract_namespace() { From c8bbb9531a38d350877ec0fb3999919bd979ab85 Mon Sep 17 00:00:00 2001 From: t4lz Date: Fri, 3 Mar 2023 18:16:00 +0100 Subject: [PATCH 16/17] fmt --- tests/socket.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/socket.rs b/tests/socket.rs index db9f3e21..33b92f84 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -176,10 +176,7 @@ fn socket_address_unix_unnamed() { } #[test] -#[cfg(all( - any(target_os = "linux", target_os = "android"), - feature = "all" -))] +#[cfg(all(any(target_os = "linux", target_os = "android"), feature = "all"))] fn socket_address_unix_abstract_namespace() { let path = "\0h".repeat(108 / 2); let addr = SockAddr::unix(&path).unwrap(); From 040f8c0c8861b2aaff53d9d1af63ca35b1b69fab Mon Sep 17 00:00:00 2001 From: t4lz Date: Sat, 4 Mar 2023 06:23:56 +0100 Subject: [PATCH 17/17] Link discussion in Fuchsia comment. --- src/sys/unix.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index c9a5b211..102676ea 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -675,6 +675,7 @@ impl SockAddr { // On some non-linux platforms a zeroed path is returned for unnamed. // Abstract addresses only exist on Linux. // NOTE: although Fuchsia does define `AF_UNIX` it's not actually implemented. + // See https://github.com/rust-lang/socket2/pull/403#discussion_r1123557978 || (cfg!(not(any(target_os = "linux", target_os = "android"))) && storage.sun_path[0] == 0) }) @@ -738,6 +739,7 @@ impl SockAddr { /// platforms. pub fn as_abstract_namespace(&self) -> Option<&[u8]> { // NOTE: although Fuchsia does define `AF_UNIX` it's not actually implemented. + // See https://github.com/rust-lang/socket2/pull/403#discussion_r1123557978 #[cfg(any(target_os = "linux", target_os = "android"))] { self.as_sockaddr_un().and_then(|storage| {