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