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