1//! IPv4, IPv6, and Socket addresses. 2 3use super::super::c; 4#[cfg(unix)] 5use crate::ffi::CStr; 6#[cfg(unix)] 7use crate::io; 8#[cfg(unix)] 9use crate::path; 10#[cfg(not(windows))] 11use core::convert::TryInto; 12#[cfg(unix)] 13use core::fmt; 14#[cfg(unix)] 15use core::slice; 16 17/// `struct sockaddr_un` 18#[cfg(unix)] 19#[derive(Clone)] 20#[doc(alias = "sockaddr_un")] 21pub struct SocketAddrUnix { 22 pub(crate) unix: c::sockaddr_un, 23 #[cfg(not(any( 24 target_os = "dragonfly", 25 target_os = "freebsd", 26 target_os = "ios", 27 target_os = "macos", 28 target_os = "netbsd", 29 target_os = "openbsd", 30 )))] 31 len: c::socklen_t, 32} 33 34#[cfg(unix)] 35impl SocketAddrUnix { 36 /// Construct a new Unix-domain address from a filesystem path. 37 #[inline] 38 pub fn new<P: path::Arg>(path: P) -> io::Result<Self> { 39 path.into_with_c_str(Self::_new) 40 } 41 42 #[inline] 43 fn _new(path: &CStr) -> io::Result<Self> { 44 let mut unix = Self::init(); 45 let bytes = path.to_bytes_with_nul(); 46 if bytes.len() > unix.sun_path.len() { 47 return Err(io::Errno::NAMETOOLONG); 48 } 49 for (i, b) in bytes.iter().enumerate() { 50 unix.sun_path[i] = *b as c::c_char; 51 } 52 53 #[cfg(any( 54 target_os = "dragonfly", 55 target_os = "freebsd", 56 target_os = "ios", 57 target_os = "macos", 58 target_os = "netbsd", 59 target_os = "openbsd", 60 ))] 61 { 62 unix.sun_len = (offsetof_sun_path() + bytes.len()).try_into().unwrap(); 63 } 64 65 Ok(Self { 66 unix, 67 #[cfg(not(any( 68 target_os = "dragonfly", 69 target_os = "freebsd", 70 target_os = "ios", 71 target_os = "macos", 72 target_os = "netbsd", 73 target_os = "openbsd", 74 )))] 75 len: (offsetof_sun_path() + bytes.len()).try_into().unwrap(), 76 }) 77 } 78 79 /// Construct a new abstract Unix-domain address from a byte slice. 80 #[cfg(any(target_os = "android", target_os = "linux"))] 81 #[inline] 82 pub fn new_abstract_name(name: &[u8]) -> io::Result<Self> { 83 let mut unix = Self::init(); 84 if 1 + name.len() > unix.sun_path.len() { 85 return Err(io::Errno::NAMETOOLONG); 86 } 87 unix.sun_path[0] = b'\0' as c::c_char; 88 for (i, b) in name.iter().enumerate() { 89 unix.sun_path[1 + i] = *b as c::c_char; 90 } 91 let len = offsetof_sun_path() + 1 + name.len(); 92 let len = len.try_into().unwrap(); 93 Ok(Self { 94 unix, 95 #[cfg(not(any( 96 target_os = "dragonfly", 97 target_os = "freebsd", 98 target_os = "ios", 99 target_os = "macos", 100 target_os = "netbsd", 101 target_os = "openbsd", 102 )))] 103 len, 104 }) 105 } 106 107 fn init() -> c::sockaddr_un { 108 c::sockaddr_un { 109 #[cfg(any( 110 target_os = "dragonfly", 111 target_os = "freebsd", 112 target_os = "haiku", 113 target_os = "ios", 114 target_os = "macos", 115 target_os = "netbsd", 116 target_os = "openbsd", 117 ))] 118 sun_len: 0, 119 sun_family: c::AF_UNIX as _, 120 #[cfg(any( 121 target_os = "dragonfly", 122 target_os = "freebsd", 123 target_os = "ios", 124 target_os = "macos", 125 target_os = "netbsd", 126 target_os = "openbsd", 127 ))] 128 sun_path: [0; 104], 129 #[cfg(not(any( 130 target_os = "dragonfly", 131 target_os = "freebsd", 132 target_os = "haiku", 133 target_os = "ios", 134 target_os = "macos", 135 target_os = "netbsd", 136 target_os = "openbsd", 137 )))] 138 sun_path: [0; 108], 139 #[cfg(target_os = "haiku")] 140 sun_path: [0; 126], 141 } 142 } 143 144 /// For a filesystem path address, return the path. 145 #[inline] 146 pub fn path(&self) -> Option<&CStr> { 147 let len = self.len(); 148 if len != 0 && self.unix.sun_path[0] != b'\0' as c::c_char { 149 let end = len as usize - offsetof_sun_path(); 150 let bytes = &self.unix.sun_path[..end]; 151 // Safety: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. And 152 // `from_bytes_with_nul_unchecked` since the string is NUL-terminated. 153 unsafe { 154 Some(CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts( 155 bytes.as_ptr().cast(), 156 bytes.len(), 157 ))) 158 } 159 } else { 160 None 161 } 162 } 163 164 /// For an abstract address, return the identifier. 165 #[cfg(any(target_os = "android", target_os = "linux"))] 166 #[inline] 167 pub fn abstract_name(&self) -> Option<&[u8]> { 168 let len = self.len(); 169 if len != 0 && self.unix.sun_path[0] == b'\0' as c::c_char { 170 let end = len as usize - offsetof_sun_path(); 171 let bytes = &self.unix.sun_path[1..end]; 172 // Safety: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. 173 unsafe { Some(slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len())) } 174 } else { 175 None 176 } 177 } 178 179 #[inline] 180 pub(crate) fn addr_len(&self) -> c::socklen_t { 181 #[cfg(not(any( 182 target_os = "dragonfly", 183 target_os = "freebsd", 184 target_os = "ios", 185 target_os = "macos", 186 target_os = "netbsd", 187 target_os = "openbsd", 188 )))] 189 { 190 self.len 191 } 192 #[cfg(any( 193 target_os = "dragonfly", 194 target_os = "freebsd", 195 target_os = "ios", 196 target_os = "macos", 197 target_os = "netbsd", 198 target_os = "openbsd", 199 ))] 200 { 201 c::socklen_t::from(self.unix.sun_len) 202 } 203 } 204 205 #[inline] 206 pub(crate) fn len(&self) -> usize { 207 self.addr_len() as usize 208 } 209} 210 211#[cfg(unix)] 212impl PartialEq for SocketAddrUnix { 213 #[inline] 214 fn eq(&self, other: &Self) -> bool { 215 let self_len = self.len() - offsetof_sun_path(); 216 let other_len = other.len() - offsetof_sun_path(); 217 self.unix.sun_path[..self_len].eq(&other.unix.sun_path[..other_len]) 218 } 219} 220 221#[cfg(unix)] 222impl Eq for SocketAddrUnix {} 223 224#[cfg(unix)] 225impl PartialOrd for SocketAddrUnix { 226 #[inline] 227 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { 228 let self_len = self.len() - offsetof_sun_path(); 229 let other_len = other.len() - offsetof_sun_path(); 230 self.unix.sun_path[..self_len].partial_cmp(&other.unix.sun_path[..other_len]) 231 } 232} 233 234#[cfg(unix)] 235impl Ord for SocketAddrUnix { 236 #[inline] 237 fn cmp(&self, other: &Self) -> core::cmp::Ordering { 238 let self_len = self.len() - offsetof_sun_path(); 239 let other_len = other.len() - offsetof_sun_path(); 240 self.unix.sun_path[..self_len].cmp(&other.unix.sun_path[..other_len]) 241 } 242} 243 244#[cfg(unix)] 245impl core::hash::Hash for SocketAddrUnix { 246 #[inline] 247 fn hash<H: core::hash::Hasher>(&self, state: &mut H) { 248 let self_len = self.len() - offsetof_sun_path(); 249 self.unix.sun_path[..self_len].hash(state) 250 } 251} 252 253#[cfg(unix)] 254impl fmt::Debug for SocketAddrUnix { 255 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 256 if let Some(path) = self.path() { 257 path.fmt(fmt) 258 } else { 259 #[cfg(any(target_os = "android", target_os = "linux"))] 260 if let Some(name) = self.abstract_name() { 261 return name.fmt(fmt); 262 } 263 264 "(unnamed)".fmt(fmt) 265 } 266 } 267} 268 269/// `struct sockaddr_storage` as a raw struct. 270pub type SocketAddrStorage = c::sockaddr_storage; 271 272/// Return the offset of the `sun_path` field of `sockaddr_un`. 273#[cfg(not(windows))] 274#[inline] 275pub(crate) fn offsetof_sun_path() -> usize { 276 let z = c::sockaddr_un { 277 #[cfg(any( 278 target_os = "dragonfly", 279 target_os = "freebsd", 280 target_os = "haiku", 281 target_os = "ios", 282 target_os = "macos", 283 target_os = "netbsd", 284 target_os = "openbsd", 285 ))] 286 sun_len: 0_u8, 287 #[cfg(any( 288 target_os = "dragonfly", 289 target_os = "freebsd", 290 target_os = "haiku", 291 target_os = "ios", 292 target_os = "macos", 293 target_os = "netbsd", 294 target_os = "openbsd", 295 ))] 296 sun_family: 0_u8, 297 #[cfg(not(any( 298 target_os = "dragonfly", 299 target_os = "freebsd", 300 target_os = "haiku", 301 target_os = "ios", 302 target_os = "macos", 303 target_os = "netbsd", 304 target_os = "openbsd", 305 )))] 306 sun_family: 0_u16, 307 #[cfg(any( 308 target_os = "dragonfly", 309 target_os = "freebsd", 310 target_os = "ios", 311 target_os = "macos", 312 target_os = "netbsd", 313 target_os = "openbsd", 314 ))] 315 sun_path: [0; 104], 316 #[cfg(not(any( 317 target_os = "dragonfly", 318 target_os = "freebsd", 319 target_os = "haiku", 320 target_os = "ios", 321 target_os = "macos", 322 target_os = "netbsd", 323 target_os = "openbsd", 324 )))] 325 sun_path: [0; 108], 326 #[cfg(target_os = "haiku")] 327 sun_path: [0; 126], 328 }; 329 (crate::utils::as_ptr(&z.sun_path) as usize) - (crate::utils::as_ptr(&z) as usize) 330} 331