#![allow(unsafe_code)]
use crate::backend::c;
use crate::ffi::CStr;
use crate::net::addr::SocketAddrLen;
use crate::net::AddressFamily;
use crate::{io, path};
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::{fmt, slice};
#[cfg(feature = "alloc")]
use {crate::ffi::CString, alloc::borrow::Cow, alloc::vec::Vec};
#[derive(Clone)]
#[doc(alias = "sockaddr_un")]
pub struct SocketAddrUnix {
pub(crate) unix: c::sockaddr_un,
len: c::socklen_t,
}
impl SocketAddrUnix {
#[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 mut bytes = path.to_bytes_with_nul();
if bytes.len() > unix.sun_path.len() {
bytes = path.to_bytes(); if bytes.len() > unix.sun_path.len() {
return Err(io::Errno::NAMETOOLONG);
}
}
for (i, b) in bytes.iter().enumerate() {
unix.sun_path[i] = bitcast!(*b);
}
let len = offsetof_sun_path() + bytes.len();
let len = len.try_into().unwrap();
Ok(Self { unix, len })
}
#[inline]
pub fn new_abstract_name(name: &[u8]) -> io::Result<Self> {
let mut unix = Self::init();
let id = &mut unix.sun_path[1..];
let id = unsafe { slice::from_raw_parts_mut(id.as_mut_ptr().cast::<u8>(), id.len()) };
if let Some(id) = id.get_mut(..name.len()) {
id.copy_from_slice(name);
let len = offsetof_sun_path() + 1 + name.len();
let len = len.try_into().unwrap();
Ok(Self { unix, len })
} else {
Err(io::Errno::NAMETOOLONG)
}
}
#[inline]
pub fn new_unnamed() -> Self {
Self {
unix: Self::init(),
len: offsetof_sun_path() as SocketAddrLen,
}
}
const fn init() -> c::sockaddr_un {
c::sockaddr_un {
sun_family: c::AF_UNIX as _,
sun_path: [0; 108],
}
}
#[inline]
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn path(&self) -> Option<Cow<'_, CStr>> {
let bytes = self.bytes()?;
if !bytes.is_empty() && bytes[0] != 0 {
if self.unix.sun_path.len() == bytes.len() {
unsafe { Self::path_with_termination(bytes) }
} else {
Some(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }.into())
}
} else {
None
}
}
#[cfg(feature = "alloc")]
#[cold]
unsafe fn path_with_termination(bytes: &[u8]) -> Option<Cow<'_, CStr>> {
let mut owned = Vec::with_capacity(bytes.len() + 1);
owned.extend_from_slice(bytes);
owned.push(b'\0');
Some(Cow::Owned(
CString::from_vec_with_nul_unchecked(owned).into(),
))
}
#[inline]
pub fn path_bytes(&self) -> Option<&[u8]> {
let bytes = self.bytes()?;
if !bytes.is_empty() && bytes[0] != 0 {
if self.unix.sun_path.len() == self.len() - offsetof_sun_path() {
Some(bytes)
} else {
Some(&bytes[..bytes.len() - 1])
}
} else {
None
}
}
#[inline]
pub fn abstract_name(&self) -> Option<&[u8]> {
if let [0, bytes @ ..] = self.bytes()? {
Some(bytes)
} else {
None
}
}
#[inline]
pub fn is_unnamed(&self) -> bool {
self.bytes() == Some(&[])
}
#[inline]
pub(crate) fn addr_len(&self) -> SocketAddrLen {
bitcast!(self.len)
}
#[inline]
pub(crate) fn len(&self) -> usize {
self.addr_len() as usize
}
#[inline]
fn bytes(&self) -> Option<&[u8]> {
let len = self.len();
if len != 0 {
let bytes = &self.unix.sun_path[..len - offsetof_sun_path()];
Some(unsafe { slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len()) })
} else {
None
}
}
}
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])
}
}
impl Eq for SocketAddrUnix {}
impl PartialOrd for SocketAddrUnix {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
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])
}
}
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)
}
}
impl fmt::Debug for SocketAddrUnix {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(feature = "alloc")]
if let Some(path) = self.path() {
return path.fmt(f);
}
if let Some(bytes) = self.path_bytes() {
if let Ok(s) = core::str::from_utf8(bytes) {
return s.fmt(f);
}
return bytes.fmt(f);
}
if let Some(name) = self.abstract_name() {
return name.fmt(f);
}
"(unnamed)".fmt(f)
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
#[doc(alias = "sockaddr_storage")]
pub struct SocketAddrStorage(c::sockaddr_storage);
unsafe impl Send for SocketAddrStorage {}
unsafe impl Sync for SocketAddrStorage {}
impl SocketAddrStorage {
pub fn zeroed() -> Self {
assert_eq!(c::AF_UNSPEC, 0);
unsafe { core::mem::zeroed() }
}
pub fn family(&self) -> AddressFamily {
unsafe {
AddressFamily::from_raw(crate::backend::net::read_sockaddr::read_sa_family(
crate::utils::as_ptr(&self.0).cast::<c::sockaddr>(),
))
}
}
pub fn clear_family(&mut self) {
unsafe {
crate::backend::net::read_sockaddr::initialize_family_to_unspec(
crate::utils::as_mut_ptr(&mut self.0).cast::<c::sockaddr>(),
)
}
}
}
#[inline]
pub(crate) fn offsetof_sun_path() -> usize {
let z = c::sockaddr_un {
sun_family: 0_u16,
sun_path: [0; 108],
};
(crate::utils::as_ptr(&z.sun_path) as usize) - (crate::utils::as_ptr(&z) as usize)
}