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 len = len.min(size_of::<libc::sockaddr_un>() as libc::socklen_t);
127
128 if len == 0 {
129 len = SUN_PATH_OFFSET as libc::socklen_t; } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
133 return Err(io::const_error!(
134 io::ErrorKind::InvalidInput,
135 "file descriptor did not correspond to a Unix socket",
136 ));
137 }
138
139 Ok(SocketAddr { addr, len })
140 }
141
142 #[cfg_attr(target_family = "unix", doc = "```")]
152 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
153 #[cfg_attr(target_family = "unix", doc = "```")]
166 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
167 #[stable(feature = "unix_socket_creation", since = "1.61.0")]
172 pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr>
173 where
174 P: AsRef<Path>,
175 {
176 sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len })
177 }
178
179 #[cfg_attr(target_family = "unix", doc = "```no_run")]
186 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
187 #[cfg_attr(target_family = "unix", doc = "```")]
200 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
201 #[must_use]
211 #[stable(feature = "unix_socket", since = "1.10.0")]
212 pub fn is_unnamed(&self) -> bool {
213 matches!(self.address(), AddressKind::Unnamed)
214 }
215
216 #[cfg_attr(target_family = "unix", doc = "```no_run")]
223 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
224 #[cfg_attr(target_family = "unix", doc = "```")]
238 #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
239 #[stable(feature = "unix_socket", since = "1.10.0")]
249 #[must_use]
250 pub fn as_pathname(&self) -> Option<&Path> {
251 if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None }
252 }
253
254 fn address(&self) -> AddressKind<'_> {
255 let len = self.len as usize - SUN_PATH_OFFSET;
256 let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
257
258 if len == 0
260 || (cfg!(not(any(target_os = "linux", target_os = "android", target_os = "cygwin")))
261 && self.addr.sun_path[0] == 0)
262 {
263 AddressKind::Unnamed
264 } else if self.addr.sun_path[0] == 0 {
265 AddressKind::Abstract(ByteStr::from_bytes(&path[1..len]))
266 } else {
267 let end = core::slice::memchr::memchr(0, &path[..len]).unwrap_or(len);
271 AddressKind::Pathname(OsStr::from_bytes(&path[..end]).as_ref())
272 }
273 }
274}
275
276#[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin")))]
277#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "cygwin"))]
278#[stable(feature = "unix_socket_abstract", since = "1.70.0")]
279impl linux_ext::addr::SocketAddrExt for SocketAddr {
280 fn as_abstract_name(&self) -> Option<&[u8]> {
281 if let AddressKind::Abstract(name) = self.address() { Some(name.as_bytes()) } else { None }
282 }
283
284 fn from_abstract_name<N>(name: N) -> io::Result<Self>
285 where
286 N: AsRef<[u8]>,
287 {
288 let name = name.as_ref();
289 unsafe {
290 let mut addr: libc::sockaddr_un = mem::zeroed();
291 addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
292
293 if name.len() + 1 > addr.sun_path.len() {
294 return Err(io::const_error!(
295 io::ErrorKind::InvalidInput,
296 "abstract socket name must be shorter than SUN_LEN",
297 ));
298 }
299
300 crate::ptr::copy_nonoverlapping(
301 name.as_ptr(),
302 addr.sun_path.as_mut_ptr().add(1) as *mut u8,
303 name.len(),
304 );
305 let len = (SUN_PATH_OFFSET + 1 + name.len()) as libc::socklen_t;
306 SocketAddr::from_parts(addr, len)
307 }
308 }
309}
310
311#[stable(feature = "unix_socket", since = "1.10.0")]
312impl fmt::Debug for SocketAddr {
313 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
314 match self.address() {
315 AddressKind::Unnamed => write!(fmt, "(unnamed)"),
316 AddressKind::Abstract(name) => write!(fmt, "{name:?} (abstract)"),
317 AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"),
318 }
319 }
320}