1use crate::bstr::ByteStr;
2use crate::ffi::OsStr;
3#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
4use crate::os::net::linux_ext;
5use crate::os::unix::ffi::OsStrExt;
6use crate::path::Path;
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(_) => {
57 if cfg!(not(any(target_os = "qnx", target_env = "nto71"))) {
62 len += 1
63 }
64 }
65 }
66 Ok((addr, len as libc::socklen_t))
67}
68
69enum AddressKind<'a> {
70 Unnamed,
71 Pathname(&'a Path),
72 Abstract(&'a ByteStr),
73}
74
75#[cfg_attr(target_family = "unix", doc = "```")]
80#[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
81#[derive(Clone)]
93#[stable(feature = "unix_socket", since = "1.10.0")]
94pub struct SocketAddr {
95 pub(super) addr: libc::sockaddr_un,
96 pub(super) len: libc::socklen_t,
97}
98
99impl SocketAddr {
100 pub(super) fn new<F>(f: F) -> io::Result<SocketAddr>
101 where
102 F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int,
103 {
104 unsafe {
105 let mut addr: libc::sockaddr_un = mem::zeroed();
106 let mut len = size_of::<libc::sockaddr_un>() as libc::socklen_t;
107 cvt(f((&raw mut addr) as *mut _, &mut len))?;
108 SocketAddr::from_parts(addr, len)
109 }
110 }
111
112 pub(super) fn from_parts(
113 addr: libc::sockaddr_un,
114 mut len: libc::socklen_t,
115 ) -> io::Result<SocketAddr> {
116 if cfg!(target_os = "openbsd") {
117 let sun_path: &[u8] =
121 unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&addr.sun_path) };
122 len = core::slice::memchr::memchr(0, sun_path)
123 .map_or(len, |new_len| (new_len + SUN_PATH_OFFSET) as libc::socklen_t);
124 }
125
126 if len == 0 {
127 len = SUN_PATH_OFFSET as libc::socklen_t; } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
131 return Err(io::const_error!(
132 io::ErrorKind::InvalidInput,
133 "file descriptor did not correspond to a Unix socket",
134 ));
135 }
136
137 Ok(SocketAddr { addr, len })
138 }
139
140 #[cfg_attr(target_family = "unix", doc = "```")]
150 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
151 #[cfg_attr(target_family = "unix", doc = "```")]
164 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
165 #[stable(feature = "unix_socket_creation", since = "1.61.0")]
170 pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr>
171 where
172 P: AsRef<Path>,
173 {
174 sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len })
175 }
176
177 #[cfg_attr(target_family = "unix", doc = "```no_run")]
184 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
185 #[cfg_attr(target_family = "unix", doc = "```")]
198 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
199 #[must_use]
209 #[stable(feature = "unix_socket", since = "1.10.0")]
210 pub fn is_unnamed(&self) -> bool {
211 matches!(self.address(), AddressKind::Unnamed)
212 }
213
214 #[cfg_attr(target_family = "unix", doc = "```no_run")]
221 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
222 #[cfg_attr(target_family = "unix", doc = "```")]
236 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
237 #[stable(feature = "unix_socket", since = "1.10.0")]
247 #[must_use]
248 pub fn as_pathname(&self) -> Option<&Path> {
249 if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None }
250 }
251
252 fn address(&self) -> AddressKind<'_> {
253 let len = self.len as usize - SUN_PATH_OFFSET;
254 let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
255
256 if len == 0
258 || (cfg!(not(any(target_os = "linux", target_os = "android", target_os = "cygwin")))
259 && self.addr.sun_path[0] == 0)
260 {
261 AddressKind::Unnamed
262 } else if self.addr.sun_path[0] == 0 {
263 AddressKind::Abstract(ByteStr::from_bytes(&path[1..len]))
264 } else {
265 let end = core::slice::memchr::memchr(0, &path[..len]).unwrap_or(len);
269 AddressKind::Pathname(OsStr::from_bytes(&path[..end]).as_ref())
270 }
271 }
272}
273
274#[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin")))]
275#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
276#[stable(feature = "unix_socket_abstract", since = "1.70.0")]
277impl linux_ext::addr::SocketAddrExt for SocketAddr {
278 fn as_abstract_name(&self) -> Option<&[u8]> {
279 if let AddressKind::Abstract(name) = self.address() { Some(name.as_bytes()) } else { None }
280 }
281
282 fn from_abstract_name<N>(name: N) -> io::Result<Self>
283 where
284 N: AsRef<[u8]>,
285 {
286 let name = name.as_ref();
287 unsafe {
288 let mut addr: libc::sockaddr_un = mem::zeroed();
289 addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
290
291 if name.len() + 1 > addr.sun_path.len() {
292 return Err(io::const_error!(
293 io::ErrorKind::InvalidInput,
294 "abstract socket name must be shorter than SUN_LEN",
295 ));
296 }
297
298 crate::ptr::copy_nonoverlapping(
299 name.as_ptr(),
300 addr.sun_path.as_mut_ptr().add(1) as *mut u8,
301 name.len(),
302 );
303 let len = (SUN_PATH_OFFSET + 1 + name.len()) as libc::socklen_t;
304 SocketAddr::from_parts(addr, len)
305 }
306 }
307}
308
309#[stable(feature = "unix_socket", since = "1.10.0")]
310impl fmt::Debug for SocketAddr {
311 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
312 match self.address() {
313 AddressKind::Unnamed => write!(fmt, "(unnamed)"),
314 AddressKind::Abstract(name) => write!(fmt, "{name:?} (abstract)"),
315 AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"),
316 }
317 }
318}