diff options
Diffstat (limited to 'vendor/rustix/src/backend/libc/net/addr.rs')
-rw-r--r-- | vendor/rustix/src/backend/libc/net/addr.rs | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/vendor/rustix/src/backend/libc/net/addr.rs b/vendor/rustix/src/backend/libc/net/addr.rs new file mode 100644 index 0000000..719a549 --- /dev/null +++ b/vendor/rustix/src/backend/libc/net/addr.rs @@ -0,0 +1,245 @@ +//! Socket address utilities. + +use crate::backend::c; +#[cfg(unix)] +use { + crate::ffi::CStr, + crate::io, + crate::path, + core::cmp::Ordering, + core::fmt, + core::hash::{Hash, Hasher}, + core::slice, +}; + +/// `struct sockaddr_un` +#[cfg(unix)] +#[derive(Clone)] +#[doc(alias = "sockaddr_un")] +pub struct SocketAddrUnix { + pub(crate) unix: c::sockaddr_un, + #[cfg(not(any(bsd, target_os = "haiku")))] + len: c::socklen_t, +} + +#[cfg(unix)] +impl SocketAddrUnix { + /// Construct a new Unix-domain address from a filesystem path. + #[inline] + pub fn new<P: path::Arg>(path: P) -> io::Result<Self> { + path.into_with_c_str(Self::_new) + } + + #[inline] + fn _new(path: &CStr) -> io::Result<Self> { + let mut unix = Self::init(); + let bytes = path.to_bytes_with_nul(); + if bytes.len() > unix.sun_path.len() { + return Err(io::Errno::NAMETOOLONG); + } + for (i, b) in bytes.iter().enumerate() { + unix.sun_path[i] = *b as c::c_char; + } + + #[cfg(any(bsd, target_os = "haiku"))] + { + unix.sun_len = (offsetof_sun_path() + bytes.len()).try_into().unwrap(); + } + + Ok(Self { + unix, + #[cfg(not(any(bsd, target_os = "haiku")))] + len: (offsetof_sun_path() + bytes.len()).try_into().unwrap(), + }) + } + + /// Construct a new abstract Unix-domain address from a byte slice. + #[cfg(linux_kernel)] + #[inline] + pub fn new_abstract_name(name: &[u8]) -> io::Result<Self> { + let mut unix = Self::init(); + if 1 + name.len() > unix.sun_path.len() { + return Err(io::Errno::NAMETOOLONG); + } + unix.sun_path[0] = 0; + for (i, b) in name.iter().enumerate() { + unix.sun_path[1 + i] = *b as c::c_char; + } + let len = offsetof_sun_path() + 1 + name.len(); + let len = len.try_into().unwrap(); + Ok(Self { + unix, + #[cfg(not(any(bsd, target_os = "haiku")))] + len, + }) + } + + fn init() -> c::sockaddr_un { + c::sockaddr_un { + #[cfg(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto"))] + sun_len: 0, + #[cfg(target_os = "vita")] + ss_len: 0, + sun_family: c::AF_UNIX as _, + #[cfg(any(bsd, target_os = "nto"))] + sun_path: [0; 104], + #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto")))] + sun_path: [0; 108], + #[cfg(target_os = "haiku")] + sun_path: [0; 126], + #[cfg(target_os = "aix")] + sun_path: [0; 1023], + } + } + + /// For a filesystem path address, return the path. + #[inline] + pub fn path(&self) -> Option<&CStr> { + let len = self.len(); + if len != 0 && self.unix.sun_path[0] != 0 { + let end = len as usize - offsetof_sun_path(); + let bytes = &self.unix.sun_path[..end]; + // SAFETY: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. + // And `from_bytes_with_nul_unchecked` since the string is + // NUL-terminated. + unsafe { + Some(CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts( + bytes.as_ptr().cast(), + bytes.len(), + ))) + } + } else { + None + } + } + + /// For an abstract address, return the identifier. + #[cfg(linux_kernel)] + #[inline] + pub fn abstract_name(&self) -> Option<&[u8]> { + let len = self.len(); + if len != 0 && self.unix.sun_path[0] == 0 { + let end = len as usize - offsetof_sun_path(); + let bytes = &self.unix.sun_path[1..end]; + // SAFETY: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. + unsafe { Some(slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len())) } + } else { + None + } + } + + #[inline] + pub(crate) fn addr_len(&self) -> c::socklen_t { + #[cfg(not(any(bsd, target_os = "haiku")))] + { + self.len + } + #[cfg(any(bsd, target_os = "haiku"))] + { + c::socklen_t::from(self.unix.sun_len) + } + } + + #[inline] + pub(crate) fn len(&self) -> usize { + self.addr_len() as usize + } +} + +#[cfg(unix)] +impl PartialEq for SocketAddrUnix { + #[inline] + fn eq(&self, other: &Self) -> bool { + let self_len = self.len() - offsetof_sun_path(); + let other_len = other.len() - offsetof_sun_path(); + self.unix.sun_path[..self_len].eq(&other.unix.sun_path[..other_len]) + } +} + +#[cfg(unix)] +impl Eq for SocketAddrUnix {} + +#[cfg(unix)] +impl PartialOrd for SocketAddrUnix { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +#[cfg(unix)] +impl Ord for SocketAddrUnix { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + let self_len = self.len() - offsetof_sun_path(); + let other_len = other.len() - offsetof_sun_path(); + self.unix.sun_path[..self_len].cmp(&other.unix.sun_path[..other_len]) + } +} + +#[cfg(unix)] +impl Hash for SocketAddrUnix { + #[inline] + fn hash<H: Hasher>(&self, state: &mut H) { + let self_len = self.len() - offsetof_sun_path(); + self.unix.sun_path[..self_len].hash(state) + } +} + +#[cfg(unix)] +impl fmt::Debug for SocketAddrUnix { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(path) = self.path() { + path.fmt(fmt) + } else { + #[cfg(linux_kernel)] + if let Some(name) = self.abstract_name() { + return name.fmt(fmt); + } + + "(unnamed)".fmt(fmt) + } + } +} + +/// `struct sockaddr_storage` as a raw struct. +pub type SocketAddrStorage = c::sockaddr_storage; + +/// Return the offset of the `sun_path` field of `sockaddr_un`. +#[cfg(not(windows))] +#[inline] +pub(crate) fn offsetof_sun_path() -> usize { + let z = c::sockaddr_un { + #[cfg(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto"))] + sun_len: 0_u8, + #[cfg(target_os = "vita")] + ss_len: 0, + #[cfg(any( + bsd, + target_os = "aix", + target_os = "espidf", + target_os = "haiku", + target_os = "nto", + target_os = "vita" + ))] + sun_family: 0_u8, + #[cfg(not(any( + bsd, + target_os = "aix", + target_os = "espidf", + target_os = "haiku", + target_os = "nto", + target_os = "vita" + )))] + sun_family: 0_u16, + #[cfg(any(bsd, target_os = "nto"))] + sun_path: [0; 104], + #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto")))] + sun_path: [0; 108], + #[cfg(target_os = "haiku")] + sun_path: [0; 126], + #[cfg(target_os = "aix")] + sun_path: [0; 1023], + }; + (crate::utils::as_ptr(&z.sun_path) as usize) - (crate::utils::as_ptr(&z) as usize) +} |