1 //! IPv4, IPv6, and Socket addresses. 2 //! 3 //! # Safety 4 //! 5 //! Linux's IPv6 type contains a union. 6 #![allow(unsafe_code)] 7 8 use super::super::c; 9 use crate::ffi::CStr; 10 use crate::{io, path}; 11 use core::convert::TryInto; 12 use core::{fmt, slice}; 13 14 /// `struct sockaddr_un` 15 #[derive(Clone)] 16 #[doc(alias = "sockaddr_un")] 17 pub struct SocketAddrUnix { 18 pub(crate) unix: c::sockaddr_un, 19 len: c::socklen_t, 20 } 21 22 impl SocketAddrUnix { 23 /// Construct a new Unix-domain address from a filesystem path. 24 #[inline] newnull25 pub fn new<P: path::Arg>(path: P) -> io::Result<Self> { 26 path.into_with_c_str(Self::_new) 27 } 28 29 #[inline] _newnull30 fn _new(path: &CStr) -> io::Result<Self> { 31 let mut unix = Self::init(); 32 let bytes = path.to_bytes_with_nul(); 33 if bytes.len() > unix.sun_path.len() { 34 return Err(io::Errno::NAMETOOLONG); 35 } 36 for (i, b) in bytes.iter().enumerate() { 37 unix.sun_path[i] = *b as c::c_char; 38 } 39 let len = offsetof_sun_path() + bytes.len(); 40 let len = len.try_into().unwrap(); 41 Ok(Self { unix, len }) 42 } 43 44 /// Construct a new abstract Unix-domain address from a byte slice. 45 #[inline] new_abstract_namenull46 pub fn new_abstract_name(name: &[u8]) -> io::Result<Self> { 47 let mut unix = Self::init(); 48 if 1 + name.len() > unix.sun_path.len() { 49 return Err(io::Errno::NAMETOOLONG); 50 } 51 unix.sun_path[0] = b'\0' as c::c_char; 52 for (i, b) in name.iter().enumerate() { 53 unix.sun_path[1 + i] = *b as c::c_char; 54 } 55 let len = offsetof_sun_path() + 1 + name.len(); 56 let len = len.try_into().unwrap(); 57 Ok(Self { unix, len }) 58 } 59 initnull60 fn init() -> c::sockaddr_un { 61 c::sockaddr_un { 62 sun_family: c::AF_UNIX as _, 63 sun_path: [0; 108], 64 } 65 } 66 67 /// For a filesystem path address, return the path. 68 #[inline] pathnull69 pub fn path(&self) -> Option<&CStr> { 70 let len = self.len(); 71 if len != 0 && self.unix.sun_path[0] != b'\0' as c::c_char { 72 let end = len as usize - offsetof_sun_path(); 73 let bytes = &self.unix.sun_path[..end]; 74 // Safety: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. And 75 // `from_bytes_with_nul_unchecked` since the string is NUL-terminated. 76 unsafe { 77 Some(CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts( 78 bytes.as_ptr().cast(), 79 bytes.len(), 80 ))) 81 } 82 } else { 83 None 84 } 85 } 86 87 /// For an abstract address, return the identifier. 88 #[inline] abstract_namenull89 pub fn abstract_name(&self) -> Option<&[u8]> { 90 let len = self.len(); 91 if len != 0 && self.unix.sun_path[0] == b'\0' as c::c_char { 92 let end = len as usize - offsetof_sun_path(); 93 let bytes = &self.unix.sun_path[1..end]; 94 // Safety: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. 95 unsafe { Some(slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len())) } 96 } else { 97 None 98 } 99 } 100 101 #[inline] 102 pub(crate) fn addr_len(&self) -> c::socklen_t { 103 self.len 104 } 105 106 #[inline] 107 pub(crate) fn len(&self) -> usize { 108 self.addr_len() as usize 109 } 110 } 111 112 impl PartialEq for SocketAddrUnix { 113 #[inline] eqnull114 fn eq(&self, other: &Self) -> bool { 115 let self_len = self.len() - offsetof_sun_path(); 116 let other_len = other.len() - offsetof_sun_path(); 117 self.unix.sun_path[..self_len].eq(&other.unix.sun_path[..other_len]) 118 } 119 } 120 121 impl Eq for SocketAddrUnix {} 122 123 impl PartialOrd for SocketAddrUnix { 124 #[inline] partial_cmpnull125 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { 126 let self_len = self.len() - offsetof_sun_path(); 127 let other_len = other.len() - offsetof_sun_path(); 128 self.unix.sun_path[..self_len].partial_cmp(&other.unix.sun_path[..other_len]) 129 } 130 } 131 132 impl Ord for SocketAddrUnix { 133 #[inline] cmpnull134 fn cmp(&self, other: &Self) -> core::cmp::Ordering { 135 let self_len = self.len() - offsetof_sun_path(); 136 let other_len = other.len() - offsetof_sun_path(); 137 self.unix.sun_path[..self_len].cmp(&other.unix.sun_path[..other_len]) 138 } 139 } 140 141 impl core::hash::Hash for SocketAddrUnix { 142 #[inline] hashnull143 fn hash<H: core::hash::Hasher>(&self, state: &mut H) { 144 let self_len = self.len() - offsetof_sun_path(); 145 self.unix.sun_path[..self_len].hash(state) 146 } 147 } 148 149 impl fmt::Debug for SocketAddrUnix { fmtnull150 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 151 if let Some(path) = self.path() { 152 path.fmt(fmt) 153 } else if let Some(name) = self.abstract_name() { 154 name.fmt(fmt) 155 } else { 156 "(unnamed)".fmt(fmt) 157 } 158 } 159 } 160 161 /// `struct sockaddr_storage` as a raw struct. 162 pub type SocketAddrStorage = c::sockaddr; 163 164 /// Return the offset of the `sun_path` field of `sockaddr_un`. 165 #[inline] 166 pub(crate) fn offsetof_sun_path() -> usize { 167 let z = c::sockaddr_un { 168 sun_family: 0_u16, 169 sun_path: [0; 108], 170 }; 171 (crate::utils::as_ptr(&z.sun_path) as usize) - (crate::utils::as_ptr(&z) as usize) 172 } 173