std/os/unix/net/
addr.rs
1use crate::ffi::OsStr;
2#[cfg(any(doc, target_os = "android", target_os = "linux"))]
3use crate::os::net::linux_ext;
4use crate::os::unix::ffi::OsStrExt;
5use crate::path::Path;
6use crate::sealed::Sealed;
7use crate::sys::cvt;
8use crate::{fmt, io, mem, ptr};
9
10#[cfg(not(unix))]
12#[allow(non_camel_case_types)]
13mod libc {
14 pub use core::ffi::c_int;
15 pub type socklen_t = u32;
16 pub struct sockaddr;
17 #[derive(Clone)]
18 pub struct sockaddr_un {
19 pub sun_path: [u8; 1],
20 }
21}
22
23const SUN_PATH_OFFSET: usize = mem::offset_of!(libc::sockaddr_un, sun_path);
24
25pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
26 let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() };
28 addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
29
30 let bytes = path.as_os_str().as_bytes();
31
32 if bytes.contains(&0) {
33 return Err(io::const_error!(
34 io::ErrorKind::InvalidInput,
35 "paths must not contain interior null bytes",
36 ));
37 }
38
39 if bytes.len() >= addr.sun_path.len() {
40 return Err(io::const_error!(
41 io::ErrorKind::InvalidInput,
42 "path must be shorter than SUN_LEN",
43 ));
44 }
45 unsafe {
50 ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len())
51 };
52
53 let mut len = SUN_PATH_OFFSET + bytes.len();
54 match bytes.get(0) {
55 Some(&0) | None => {}
56 Some(_) => len += 1,
57 }
58 Ok((addr, len as libc::socklen_t))
59}
60
61enum AddressKind<'a> {
62 Unnamed,
63 Pathname(&'a Path),
64 Abstract(&'a [u8]),
65}
66
67#[derive(Clone)]
84#[stable(feature = "unix_socket", since = "1.10.0")]
85pub struct SocketAddr {
86 pub(super) addr: libc::sockaddr_un,
87 pub(super) len: libc::socklen_t,
88}
89
90impl SocketAddr {
91 pub(super) fn new<F>(f: F) -> io::Result<SocketAddr>
92 where
93 F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int,
94 {
95 unsafe {
96 let mut addr: libc::sockaddr_un = mem::zeroed();
97 let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
98 cvt(f((&raw mut addr) as *mut _, &mut len))?;
99 SocketAddr::from_parts(addr, len)
100 }
101 }
102
103 pub(super) fn from_parts(
104 addr: libc::sockaddr_un,
105 mut len: libc::socklen_t,
106 ) -> io::Result<SocketAddr> {
107 if cfg!(target_os = "openbsd") {
108 let sun_path: &[u8] =
112 unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&addr.sun_path) };
113 len = core::slice::memchr::memchr(0, sun_path)
114 .map_or(len, |new_len| (new_len + SUN_PATH_OFFSET) as libc::socklen_t);
115 }
116
117 if len == 0 {
118 len = SUN_PATH_OFFSET as libc::socklen_t; } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
122 return Err(io::const_error!(
123 io::ErrorKind::InvalidInput,
124 "file descriptor did not correspond to a Unix socket",
125 ));
126 }
127
128 Ok(SocketAddr { addr, len })
129 }
130
131 #[stable(feature = "unix_socket_creation", since = "1.61.0")]
159 pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr>
160 where
161 P: AsRef<Path>,
162 {
163 sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len })
164 }
165
166 #[must_use]
196 #[stable(feature = "unix_socket", since = "1.10.0")]
197 pub fn is_unnamed(&self) -> bool {
198 matches!(self.address(), AddressKind::Unnamed)
199 }
200
201 #[stable(feature = "unix_socket", since = "1.10.0")]
232 #[must_use]
233 pub fn as_pathname(&self) -> Option<&Path> {
234 if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None }
235 }
236
237 fn address(&self) -> AddressKind<'_> {
238 let len = self.len as usize - SUN_PATH_OFFSET;
239 let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
240
241 if len == 0
243 || (cfg!(not(any(target_os = "linux", target_os = "android")))
244 && self.addr.sun_path[0] == 0)
245 {
246 AddressKind::Unnamed
247 } else if self.addr.sun_path[0] == 0 {
248 AddressKind::Abstract(&path[1..len])
249 } else {
250 AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
251 }
252 }
253}
254
255#[stable(feature = "unix_socket_abstract", since = "1.70.0")]
256impl Sealed for SocketAddr {}
257
258#[doc(cfg(any(target_os = "android", target_os = "linux")))]
259#[cfg(any(doc, target_os = "android", target_os = "linux"))]
260#[stable(feature = "unix_socket_abstract", since = "1.70.0")]
261impl linux_ext::addr::SocketAddrExt for SocketAddr {
262 fn as_abstract_name(&self) -> Option<&[u8]> {
263 if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None }
264 }
265
266 fn from_abstract_name<N>(name: N) -> crate::io::Result<Self>
267 where
268 N: AsRef<[u8]>,
269 {
270 let name = name.as_ref();
271 unsafe {
272 let mut addr: libc::sockaddr_un = mem::zeroed();
273 addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
274
275 if name.len() + 1 > addr.sun_path.len() {
276 return Err(io::const_error!(
277 io::ErrorKind::InvalidInput,
278 "abstract socket name must be shorter than SUN_LEN",
279 ));
280 }
281
282 crate::ptr::copy_nonoverlapping(
283 name.as_ptr(),
284 addr.sun_path.as_mut_ptr().add(1) as *mut u8,
285 name.len(),
286 );
287 let len = (SUN_PATH_OFFSET + 1 + name.len()) as libc::socklen_t;
288 SocketAddr::from_parts(addr, len)
289 }
290 }
291}
292
293#[stable(feature = "unix_socket", since = "1.10.0")]
294impl fmt::Debug for SocketAddr {
295 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
296 match self.address() {
297 AddressKind::Unnamed => write!(fmt, "(unnamed)"),
298 AddressKind::Abstract(name) => write!(fmt, "\"{}\" (abstract)", name.escape_ascii()),
299 AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"),
300 }
301 }
302}