1 | use super::path_offset; |
2 | use std::ffi::OsStr; |
3 | use std::os::unix::ffi::OsStrExt; |
4 | use std::path::Path; |
5 | use std::{ascii, fmt}; |
6 | |
7 | /// An address associated with a `mio` specific Unix socket. |
8 | /// |
9 | /// This is implemented instead of imported from [`net::SocketAddr`] because |
10 | /// there is no way to create a [`net::SocketAddr`]. One must be returned by |
11 | /// [`accept`], so this is returned instead. |
12 | /// |
13 | /// [`net::SocketAddr`]: std::os::unix::net::SocketAddr |
14 | /// [`accept`]: #method.accept |
15 | pub struct SocketAddr { |
16 | sockaddr: libc::sockaddr_un, |
17 | socklen: libc::socklen_t, |
18 | } |
19 | |
20 | struct AsciiEscaped<'a>(&'a [u8]); |
21 | |
22 | enum AddressKind<'a> { |
23 | Unnamed, |
24 | Pathname(&'a Path), |
25 | Abstract(&'a [u8]), |
26 | } |
27 | |
28 | impl SocketAddr { |
29 | fn address(&self) -> AddressKind<'_> { |
30 | let offset: usize = path_offset(&self.sockaddr); |
31 | // Don't underflow in `len` below. |
32 | if (self.socklen as usize) < offset { |
33 | return AddressKind::Unnamed; |
34 | } |
35 | let len: usize = self.socklen as usize - offset; |
36 | let path: &[u8] = unsafe { &*(&self.sockaddr.sun_path as *const [libc::c_char] as *const [u8]) }; |
37 | |
38 | // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses |
39 | if len == 0 |
40 | || (cfg!(not(any(target_os = "linux" , target_os = "android" ))) |
41 | && self.sockaddr.sun_path[0] == 0) |
42 | { |
43 | AddressKind::Unnamed |
44 | } else if self.sockaddr.sun_path[0] == 0 { |
45 | AddressKind::Abstract(&path[1..len]) |
46 | } else { |
47 | AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) |
48 | } |
49 | } |
50 | } |
51 | |
52 | cfg_os_poll! { |
53 | use std::{io, mem}; |
54 | |
55 | impl SocketAddr { |
56 | pub(crate) fn new<F>(f: F) -> io::Result<SocketAddr> |
57 | where |
58 | F: FnOnce(*mut libc::sockaddr, &mut libc::socklen_t) -> io::Result<libc::c_int>, |
59 | { |
60 | let mut sockaddr = { |
61 | let sockaddr = mem::MaybeUninit::<libc::sockaddr_un>::zeroed(); |
62 | unsafe { sockaddr.assume_init() } |
63 | }; |
64 | |
65 | let raw_sockaddr = &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr; |
66 | let mut socklen = mem::size_of_val(&sockaddr) as libc::socklen_t; |
67 | |
68 | f(raw_sockaddr, &mut socklen)?; |
69 | Ok(SocketAddr::from_parts(sockaddr, socklen)) |
70 | } |
71 | |
72 | pub(crate) fn from_parts(sockaddr: libc::sockaddr_un, socklen: libc::socklen_t) -> SocketAddr { |
73 | SocketAddr { sockaddr, socklen } |
74 | } |
75 | |
76 | pub(crate) fn raw_sockaddr(&self) -> &libc::sockaddr_un { |
77 | &self.sockaddr |
78 | } |
79 | |
80 | pub(crate) fn raw_socklen(&self) -> &libc::socklen_t { |
81 | &self.socklen |
82 | } |
83 | |
84 | /// Returns `true` if the address is unnamed. |
85 | /// |
86 | /// Documentation reflected in [`SocketAddr`] |
87 | /// |
88 | /// [`SocketAddr`]: std::os::unix::net::SocketAddr |
89 | pub fn is_unnamed(&self) -> bool { |
90 | matches!(self.address(), AddressKind::Unnamed) |
91 | } |
92 | |
93 | /// Returns the contents of this address if it is a `pathname` address. |
94 | /// |
95 | /// Documentation reflected in [`SocketAddr`] |
96 | /// |
97 | /// [`SocketAddr`]: std::os::unix::net::SocketAddr |
98 | pub fn as_pathname(&self) -> Option<&Path> { |
99 | if let AddressKind::Pathname(path) = self.address() { |
100 | Some(path) |
101 | } else { |
102 | None |
103 | } |
104 | } |
105 | |
106 | /// Returns the contents of this address if it is an abstract namespace |
107 | /// without the leading null byte. |
108 | // Link to std::os::unix::net::SocketAddr pending |
109 | // https://github.com/rust-lang/rust/issues/85410. |
110 | pub fn as_abstract_namespace(&self) -> Option<&[u8]> { |
111 | if let AddressKind::Abstract(path) = self.address() { |
112 | Some(path) |
113 | } else { |
114 | None |
115 | } |
116 | } |
117 | } |
118 | } |
119 | |
120 | impl fmt::Debug for SocketAddr { |
121 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
122 | match self.address() { |
123 | AddressKind::Unnamed => write!(fmt, "(unnamed)" ), |
124 | AddressKind::Abstract(name: &[u8]) => write!(fmt, " {} (abstract)" , AsciiEscaped(name)), |
125 | AddressKind::Pathname(path: &Path) => write!(fmt, " {:?} (pathname)" , path), |
126 | } |
127 | } |
128 | } |
129 | |
130 | impl<'a> fmt::Display for AsciiEscaped<'a> { |
131 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
132 | write!(fmt, " \"" )?; |
133 | for byte: u8 in self.0.iter().cloned().flat_map(ascii::escape_default) { |
134 | write!(fmt, " {}" , byte as char)?; |
135 | } |
136 | write!(fmt, " \"" ) |
137 | } |
138 | } |
139 | |