monoio/net/unix/
socket_addr.rs1use std::{
5 ascii,
6 cmp::Ordering,
7 ffi::OsStr,
8 fmt, io, mem,
9 os::unix::prelude::{FromRawFd, OsStrExt, RawFd},
10 path::Path,
11};
12
13use super::path_offset;
14
15#[derive(Clone)]
18pub struct SocketAddr {
19 sockaddr: libc::sockaddr_un,
20 socklen: libc::socklen_t,
21}
22
23struct AsciiEscaped<'a>(&'a [u8]);
24
25enum AddressKind<'a> {
26 Unnamed,
27 Pathname(&'a Path),
28 Abstract(&'a [u8]),
29}
30
31impl SocketAddr {
32 fn address(&self) -> AddressKind<'_> {
33 let offset = path_offset(&self.sockaddr);
34 if (self.socklen as usize) < offset {
36 return AddressKind::Unnamed;
37 }
38 let len = self.socklen as usize - offset;
39 let path = unsafe { &*(&self.sockaddr.sun_path as *const [libc::c_char] as *const [u8]) };
40
41 if len == 0 || (cfg!(not(any(target_os = "linux", target_os = "android"))) && path[0] == 0)
43 {
44 AddressKind::Unnamed
45 } else if self.sockaddr.sun_path[0] == 0 {
46 AddressKind::Abstract(&path[1..len])
47 } else {
48 AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
49 }
50 }
51
52 #[allow(unused)]
53 pub(crate) fn new<F>(f: F) -> io::Result<SocketAddr>
54 where
55 F: FnOnce(*mut libc::sockaddr, &mut libc::socklen_t) -> io::Result<libc::c_int>,
56 {
57 let mut sockaddr = {
58 let sockaddr = mem::MaybeUninit::<libc::sockaddr_un>::zeroed();
59 unsafe { sockaddr.assume_init() }
60 };
61
62 let raw_sockaddr = &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr;
63 let mut socklen = mem::size_of_val(&sockaddr) as libc::socklen_t;
64
65 f(raw_sockaddr, &mut socklen)?;
66 Ok(SocketAddr::from_parts(sockaddr, socklen))
67 }
68
69 pub(crate) fn from_parts(
70 sockaddr: libc::sockaddr_un,
71 mut socklen: libc::socklen_t,
72 ) -> SocketAddr {
73 fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
74 let base: usize = (addr as *const libc::sockaddr_un).cast::<()>() as usize;
75 let path: usize = (&addr.sun_path as *const libc::c_char).cast::<()>() as usize;
76 path - base
77 }
78
79 if socklen == 0 {
80 socklen = sun_path_offset(&sockaddr) as libc::socklen_t; } else if sockaddr.sun_family != libc::AF_UNIX as libc::sa_family_t {
84 panic!("file descriptor did not correspond to a Unix socket");
85 }
86
87 SocketAddr { sockaddr, socklen }
88 }
89
90 pub(crate) fn into_parts(self) -> (libc::sockaddr_un, libc::socklen_t) {
91 (self.sockaddr, self.socklen)
92 }
93
94 #[inline]
100 pub fn is_unnamed(&self) -> bool {
101 matches!(self.address(), AddressKind::Unnamed)
102 }
103
104 #[inline]
110 pub fn as_pathname(&self) -> Option<&Path> {
111 if let AddressKind::Pathname(path) = self.address() {
112 Some(path)
113 } else {
114 None
115 }
116 }
117
118 #[inline]
123 pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
124 if let AddressKind::Abstract(path) = self.address() {
125 Some(path)
126 } else {
127 None
128 }
129 }
130
131 #[inline]
132 pub(crate) fn as_ptr(&self) -> *const libc::sockaddr_un {
133 &self.sockaddr as *const _
134 }
135
136 #[inline]
137 pub(crate) fn len(&self) -> libc::socklen_t {
138 self.socklen
139 }
140}
141
142impl fmt::Debug for SocketAddr {
143 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
144 match self.address() {
145 AddressKind::Unnamed => write!(fmt, "(unnamed)"),
146 AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
147 AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"),
148 }
149 }
150}
151
152impl fmt::Display for AsciiEscaped<'_> {
153 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
154 write!(fmt, "\"")?;
155 for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
156 write!(fmt, "{}", byte as char)?;
157 }
158 write!(fmt, "\"")
159 }
160}
161
162pub(crate) fn socket_addr(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
163 let sockaddr = mem::MaybeUninit::<libc::sockaddr_un>::zeroed();
164
165 let mut sockaddr = unsafe { sockaddr.assume_init() };
174
175 sockaddr.sun_family = libc::AF_UNIX as libc::sa_family_t;
176
177 let bytes = path.as_os_str().as_bytes();
178 match (bytes.first(), bytes.len().cmp(&sockaddr.sun_path.len())) {
179 (Some(&0), Ordering::Greater) => {
181 return Err(io::Error::new(
182 io::ErrorKind::InvalidInput,
183 "path must be no longer than libc::sockaddr_un.sun_path",
184 ));
185 }
186 (_, Ordering::Greater) | (_, Ordering::Equal) => {
187 return Err(io::Error::new(
188 io::ErrorKind::InvalidInput,
189 "path must be shorter than libc::sockaddr_un.sun_path",
190 ));
191 }
192 _ => {}
193 }
194
195 for (dst, src) in sockaddr.sun_path.iter_mut().zip(bytes.iter()) {
196 *dst = *src as libc::c_char;
197 }
198
199 let offset = path_offset(&sockaddr);
200 let mut socklen = offset + bytes.len();
201
202 match bytes.first() {
203 Some(&0) | None => {}
206 Some(_) => socklen += 1,
207 }
208
209 Ok((sockaddr, socklen as libc::socklen_t))
210}
211
212pub(crate) fn pair<T>(flags: libc::c_int) -> io::Result<(T, T)>
213where
214 T: FromRawFd,
215{
216 #[cfg(any(
217 target_os = "android",
218 target_os = "dragonfly",
219 target_os = "freebsd",
220 target_os = "illumos",
221 target_os = "netbsd",
222 target_os = "openbsd"
223 ))]
224 let flags = flags | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC;
225
226 #[cfg(target_os = "linux")]
227 let flags = {
228 if crate::driver::op::is_legacy() {
229 flags | libc::SOCK_CLOEXEC | libc::SOCK_NONBLOCK
230 } else {
231 flags | libc::SOCK_CLOEXEC
232 }
233 };
234
235 let mut fds = [-1; 2];
236 crate::syscall!(socketpair@RAW(libc::AF_UNIX, flags, 0, fds.as_mut_ptr()))?;
237 let pair = unsafe { (T::from_raw_fd(fds[0]), T::from_raw_fd(fds[1])) };
238 Ok(pair)
239}
240
241pub(crate) fn local_addr(socket: RawFd) -> io::Result<SocketAddr> {
242 SocketAddr::new(|sockaddr, socklen| crate::syscall!(getsockname@RAW(socket, sockaddr, socklen)))
243}
244
245pub(crate) fn peer_addr(socket: RawFd) -> io::Result<SocketAddr> {
246 SocketAddr::new(|sockaddr, socklen| crate::syscall!(getpeername@RAW(socket, sockaddr, socklen)))
247}