• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! IPv4, IPv6, and Socket addresses.
2 
3 use super::super::c;
4 #[cfg(unix)]
5 use crate::ffi::CStr;
6 #[cfg(unix)]
7 use crate::io;
8 #[cfg(unix)]
9 use crate::path;
10 #[cfg(not(windows))]
11 use core::convert::TryInto;
12 #[cfg(unix)]
13 use core::fmt;
14 #[cfg(unix)]
15 use core::slice;
16 
17 /// `struct sockaddr_un`
18 #[cfg(unix)]
19 #[derive(Clone)]
20 #[doc(alias = "sockaddr_un")]
21 pub 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)]
35 impl SocketAddrUnix {
36     /// Construct a new Unix-domain address from a filesystem path.
37     #[inline]
new<P: path::Arg>(path: P) -> io::Result<Self>38     pub fn new<P: path::Arg>(path: P) -> io::Result<Self> {
39         path.into_with_c_str(Self::_new)
40     }
41 
42     #[inline]
_new(path: &CStr) -> io::Result<Self>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]
new_abstract_name(name: &[u8]) -> io::Result<Self>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 
init() -> c::sockaddr_un107     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]
path(&self) -> Option<&CStr>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]
abstract_name(&self) -> Option<&[u8]>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]
addr_len(&self) -> c::socklen_t180     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]
len(&self) -> usize206     pub(crate) fn len(&self) -> usize {
207         self.addr_len() as usize
208     }
209 }
210 
211 #[cfg(unix)]
212 impl PartialEq for SocketAddrUnix {
213     #[inline]
eq(&self, other: &Self) -> bool214     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)]
222 impl Eq for SocketAddrUnix {}
223 
224 #[cfg(unix)]
225 impl PartialOrd for SocketAddrUnix {
226     #[inline]
partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering>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)]
235 impl Ord for SocketAddrUnix {
236     #[inline]
cmp(&self, other: &Self) -> core::cmp::Ordering237     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)]
245 impl core::hash::Hash for SocketAddrUnix {
246     #[inline]
hash<H: core::hash::Hasher>(&self, state: &mut H)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)]
254 impl fmt::Debug for SocketAddrUnix {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result255     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.
270 pub type SocketAddrStorage = c::sockaddr_storage;
271 
272 /// Return the offset of the `sun_path` field of `sockaddr_un`.
273 #[cfg(not(windows))]
274 #[inline]
offsetof_sun_path() -> usize275 pub(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