1use crate::backend::c;
4use crate::net::AddressFamily;
5#[cfg(unix)]
6use {
7 crate::ffi::CStr,
8 crate::io,
9 crate::net::addr::SocketAddrLen,
10 crate::path,
11 core::cmp::Ordering,
12 core::fmt,
13 core::hash::{Hash, Hasher},
14 core::slice,
15};
16#[cfg(all(unix, feature = "alloc"))]
17use {crate::ffi::CString, alloc::borrow::Cow, alloc::vec::Vec};
18
19#[cfg(unix)]
21#[derive(Clone)]
22#[doc(alias = "sockaddr_un")]
23pub struct SocketAddrUnix {
24 pub(crate) unix: c::sockaddr_un,
25 #[cfg(not(any(bsd, target_os = "haiku")))]
26 len: c::socklen_t,
27}
28
29#[cfg(unix)]
30impl SocketAddrUnix {
31 #[inline]
33 pub fn new<P: path::Arg>(path: P) -> io::Result<Self> {
34 path.into_with_c_str(Self::_new)
35 }
36
37 #[inline]
38 fn _new(path: &CStr) -> io::Result<Self> {
39 let mut unix = Self::init();
40 let mut bytes = path.to_bytes_with_nul();
41 if bytes.len() > unix.sun_path.len() {
42 bytes = path.to_bytes(); if bytes.len() > unix.sun_path.len() {
44 return Err(io::Errno::NAMETOOLONG);
45 }
46 }
47 for (i, b) in bytes.iter().enumerate() {
48 unix.sun_path[i] = *b as c::c_char;
49 }
50
51 #[cfg(any(bsd, target_os = "haiku"))]
52 {
53 unix.sun_len = (offsetof_sun_path() + bytes.len()).try_into().unwrap();
54 }
55
56 Ok(Self {
57 unix,
58 #[cfg(not(any(bsd, target_os = "haiku")))]
59 len: (offsetof_sun_path() + bytes.len()).try_into().unwrap(),
60 })
61 }
62
63 #[cfg(linux_kernel)]
65 #[inline]
66 pub fn new_abstract_name(name: &[u8]) -> io::Result<Self> {
67 let mut unix = Self::init();
68 if 1 + name.len() > unix.sun_path.len() {
69 return Err(io::Errno::NAMETOOLONG);
70 }
71 unix.sun_path[0] = 0;
72 for (i, b) in name.iter().enumerate() {
73 unix.sun_path[1 + i] = *b as c::c_char;
74 }
75 let len = offsetof_sun_path() + 1 + name.len();
76 let len = len.try_into().unwrap();
77 Ok(Self {
78 unix,
79 #[cfg(not(any(bsd, target_os = "haiku")))]
80 len,
81 })
82 }
83
84 #[cfg(linux_kernel)]
95 #[inline]
96 pub fn new_unnamed() -> Self {
97 Self {
98 unix: Self::init(),
99 #[cfg(not(any(bsd, target_os = "haiku")))]
100 len: offsetof_sun_path() as c::socklen_t,
101 }
102 }
103
104 const fn init() -> c::sockaddr_un {
105 c::sockaddr_un {
106 #[cfg(any(
107 bsd,
108 target_os = "aix",
109 target_os = "haiku",
110 target_os = "horizon",
111 target_os = "nto",
112 target_os = "hurd",
113 ))]
114 sun_len: 0,
115 #[cfg(target_os = "vita")]
116 ss_len: 0,
117 sun_family: c::AF_UNIX as _,
118 #[cfg(any(bsd, target_os = "horizon", target_os = "nto"))]
119 sun_path: [0; 104],
120 #[cfg(not(any(
121 bsd,
122 target_os = "aix",
123 target_os = "haiku",
124 target_os = "horizon",
125 target_os = "nto"
126 )))]
127 sun_path: [0; 108],
128 #[cfg(target_os = "haiku")]
129 sun_path: [0; 126],
130 #[cfg(target_os = "aix")]
131 sun_path: [0; 1023],
132 }
133 }
134
135 #[inline]
137 #[cfg(feature = "alloc")]
138 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
139 pub fn path(&self) -> Option<Cow<'_, CStr>> {
140 let bytes = self.bytes()?;
141 if !bytes.is_empty() && bytes[0] != 0 {
142 if self.unix.sun_path.len() == bytes.len() {
143 unsafe { Self::path_with_termination(bytes) }
145 } else {
146 Some(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }.into())
149 }
150 } else {
151 None
152 }
153 }
154
155 #[cfg(feature = "alloc")]
159 #[cold]
160 unsafe fn path_with_termination(bytes: &[u8]) -> Option<Cow<'_, CStr>> {
161 let mut owned = Vec::with_capacity(bytes.len() + 1);
162 owned.extend_from_slice(bytes);
163 owned.push(b'\0');
164 Some(Cow::Owned(
167 CString::from_vec_with_nul_unchecked(owned).into(),
168 ))
169 }
170
171 #[inline]
174 pub fn path_bytes(&self) -> Option<&[u8]> {
175 let bytes = self.bytes()?;
176 if !bytes.is_empty() && bytes[0] != 0 {
177 if self.unix.sun_path.len() == self.len() - offsetof_sun_path() {
178 Some(bytes)
180 } else {
181 Some(&bytes[..bytes.len() - 1])
183 }
184 } else {
185 None
186 }
187 }
188
189 #[cfg(linux_kernel)]
191 #[inline]
192 pub fn abstract_name(&self) -> Option<&[u8]> {
193 if let [0, bytes @ ..] = self.bytes()? {
194 Some(bytes)
195 } else {
196 None
197 }
198 }
199
200 #[cfg(linux_kernel)]
202 #[inline]
203 pub fn is_unnamed(&self) -> bool {
204 self.bytes() == Some(&[])
205 }
206
207 #[inline]
208 pub(crate) fn addr_len(&self) -> SocketAddrLen {
209 #[cfg(not(any(bsd, target_os = "haiku")))]
210 {
211 bitcast!(self.len)
212 }
213 #[cfg(any(bsd, target_os = "haiku"))]
214 {
215 bitcast!(c::socklen_t::from(self.unix.sun_len))
216 }
217 }
218
219 #[inline]
220 pub(crate) fn len(&self) -> usize {
221 self.addr_len() as usize
222 }
223
224 #[inline]
225 fn bytes(&self) -> Option<&[u8]> {
226 let len = self.len();
227 if len != 0 {
228 let bytes = &self.unix.sun_path[..len - offsetof_sun_path()];
229 Some(unsafe { slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len()) })
231 } else {
232 None
233 }
234 }
235}
236
237#[cfg(unix)]
238impl PartialEq for SocketAddrUnix {
239 #[inline]
240 fn eq(&self, other: &Self) -> bool {
241 let self_len = self.len() - offsetof_sun_path();
242 let other_len = other.len() - offsetof_sun_path();
243 self.unix.sun_path[..self_len].eq(&other.unix.sun_path[..other_len])
244 }
245}
246
247#[cfg(unix)]
248impl Eq for SocketAddrUnix {}
249
250#[cfg(unix)]
251impl PartialOrd for SocketAddrUnix {
252 #[inline]
253 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
254 Some(self.cmp(other))
255 }
256}
257
258#[cfg(unix)]
259impl Ord for SocketAddrUnix {
260 #[inline]
261 fn cmp(&self, other: &Self) -> Ordering {
262 let self_len = self.len() - offsetof_sun_path();
263 let other_len = other.len() - offsetof_sun_path();
264 self.unix.sun_path[..self_len].cmp(&other.unix.sun_path[..other_len])
265 }
266}
267
268#[cfg(unix)]
269impl Hash for SocketAddrUnix {
270 #[inline]
271 fn hash<H: Hasher>(&self, state: &mut H) {
272 let self_len = self.len() - offsetof_sun_path();
273 self.unix.sun_path[..self_len].hash(state)
274 }
275}
276
277#[cfg(unix)]
278impl fmt::Debug for SocketAddrUnix {
279 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280 #[cfg(feature = "alloc")]
281 if let Some(path) = self.path() {
282 return path.fmt(f);
283 }
284 if let Some(bytes) = self.path_bytes() {
285 if let Ok(s) = core::str::from_utf8(bytes) {
286 return s.fmt(f);
287 }
288 return bytes.fmt(f);
289 }
290 #[cfg(linux_kernel)]
291 if let Some(name) = self.abstract_name() {
292 return name.fmt(f);
293 }
294 "(unnamed)".fmt(f)
295 }
296}
297
298#[repr(transparent)]
303#[derive(Copy, Clone)]
304#[doc(alias = "sockaddr_storage")]
305pub struct SocketAddrStorage(c::sockaddr_storage);
306
307impl SocketAddrStorage {
308 pub fn zeroed() -> Self {
311 assert_eq!(c::AF_UNSPEC, 0);
312 unsafe { core::mem::zeroed() }
314 }
315
316 pub fn family(&self) -> AddressFamily {
318 unsafe {
320 AddressFamily::from_raw(crate::backend::net::read_sockaddr::read_sa_family(
321 crate::utils::as_ptr(&self.0).cast::<c::sockaddr>(),
322 ))
323 }
324 }
325
326 pub fn clear_family(&mut self) {
329 unsafe {
331 crate::backend::net::read_sockaddr::initialize_family_to_unspec(
332 crate::utils::as_mut_ptr(&mut self.0).cast::<c::sockaddr>(),
333 )
334 }
335 }
336}
337
338#[cfg(not(windows))]
340#[inline]
341pub(crate) fn offsetof_sun_path() -> usize {
342 let z = c::sockaddr_un {
343 #[cfg(any(
344 bsd,
345 target_os = "aix",
346 target_os = "haiku",
347 target_os = "horizon",
348 target_os = "hurd",
349 target_os = "nto",
350 ))]
351 sun_len: 0_u8,
352 #[cfg(target_os = "vita")]
353 ss_len: 0,
354 #[cfg(any(
355 bsd,
356 target_os = "aix",
357 target_os = "espidf",
358 target_os = "haiku",
359 target_os = "hurd",
360 target_os = "nto",
361 target_os = "vita"
362 ))]
363 sun_family: 0_u8,
364 #[cfg(not(any(
365 bsd,
366 target_os = "aix",
367 target_os = "espidf",
368 target_os = "haiku",
369 target_os = "hurd",
370 target_os = "nto",
371 target_os = "vita"
372 )))]
373 sun_family: 0_u16,
374 #[cfg(any(bsd, target_os = "horizon", target_os = "nto"))]
375 sun_path: [0; 104],
376 #[cfg(not(any(
377 bsd,
378 target_os = "aix",
379 target_os = "haiku",
380 target_os = "horizon",
381 target_os = "nto"
382 )))]
383 sun_path: [0; 108],
384 #[cfg(target_os = "haiku")]
385 sun_path: [0; 126],
386 #[cfg(target_os = "aix")]
387 sun_path: [0; 1023],
388 };
389 (crate::utils::as_ptr(&z.sun_path) as usize) - (crate::utils::as_ptr(&z) as usize)
390}