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