2 use crate::os::unix::ffi::OsStrExt;
5 use crate::{ascii, fmt, io, iter, mem};
7 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
9 #[allow(non_camel_case_types)]
12 pub type socklen_t = u32;
15 pub struct sockaddr_un;
18 fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
19 // Work with an actual instance of the type since using a null pointer is UB
20 let base = addr as *const _ as usize;
21 let path = &addr.sun_path as *const _ as usize;
25 pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
26 let mut addr: libc::sockaddr_un = mem::zeroed();
27 addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
29 let bytes = path.as_os_str().as_bytes();
31 if bytes.contains(&0) {
32 return Err(io::Error::new_const(
33 io::ErrorKind::InvalidInput,
34 &"paths must not contain interior null bytes",
38 if bytes.len() >= addr.sun_path.len() {
39 return Err(io::Error::new_const(
40 io::ErrorKind::InvalidInput,
41 &"path must be shorter than SUN_LEN",
44 for (dst, src) in iter::zip(&mut addr.sun_path, bytes) {
45 *dst = *src as libc::c_char;
47 // null byte for pathname addresses is already there because we zeroed the
50 let mut len = sun_path_offset(&addr) + bytes.len();
55 Ok((addr, len as libc::socklen_t))
58 enum AddressKind<'a> {
64 struct AsciiEscaped<'a>(&'a [u8]);
66 impl<'a> fmt::Display for AsciiEscaped<'a> {
67 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
69 for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
70 write!(fmt, "{}", byte as char)?;
76 /// An address associated with a Unix socket.
81 /// use std::os::unix::net::UnixListener;
83 /// let socket = match UnixListener::bind("/tmp/sock") {
86 /// println!("Couldn't bind: {:?}", e);
90 /// let addr = socket.local_addr().expect("Couldn't get local address");
93 #[stable(feature = "unix_socket", since = "1.10.0")]
94 pub struct SocketAddr {
95 pub(super) addr: libc::sockaddr_un,
96 pub(super) len: libc::socklen_t,
100 pub(super) fn new<F>(f: F) -> io::Result<SocketAddr>
102 F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int,
105 let mut addr: libc::sockaddr_un = mem::zeroed();
106 let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
107 cvt(f(&mut addr as *mut _ as *mut _, &mut len))?;
108 SocketAddr::from_parts(addr, len)
112 pub(super) fn from_parts(
113 addr: libc::sockaddr_un,
114 mut len: libc::socklen_t,
115 ) -> io::Result<SocketAddr> {
117 // When there is a datagram from unnamed unix socket
118 // linux returns zero bytes of address
119 len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address
120 } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
121 return Err(io::Error::new_const(
122 io::ErrorKind::InvalidInput,
123 &"file descriptor did not correspond to a Unix socket",
127 Ok(SocketAddr { addr, len })
130 /// Returns `true` if the address is unnamed.
137 /// use std::os::unix::net::UnixListener;
139 /// fn main() -> std::io::Result<()> {
140 /// let socket = UnixListener::bind("/tmp/sock")?;
141 /// let addr = socket.local_addr().expect("Couldn't get local address");
142 /// assert_eq!(addr.is_unnamed(), false);
147 /// An unnamed address:
150 /// use std::os::unix::net::UnixDatagram;
152 /// fn main() -> std::io::Result<()> {
153 /// let socket = UnixDatagram::unbound()?;
154 /// let addr = socket.local_addr().expect("Couldn't get local address");
155 /// assert_eq!(addr.is_unnamed(), true);
160 #[stable(feature = "unix_socket", since = "1.10.0")]
161 pub fn is_unnamed(&self) -> bool {
162 matches!(self.address(), AddressKind::Unnamed)
165 /// Returns the contents of this address if it is a `pathname` address.
172 /// use std::os::unix::net::UnixListener;
173 /// use std::path::Path;
175 /// fn main() -> std::io::Result<()> {
176 /// let socket = UnixListener::bind("/tmp/sock")?;
177 /// let addr = socket.local_addr().expect("Couldn't get local address");
178 /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
183 /// Without a pathname:
186 /// use std::os::unix::net::UnixDatagram;
188 /// fn main() -> std::io::Result<()> {
189 /// let socket = UnixDatagram::unbound()?;
190 /// let addr = socket.local_addr().expect("Couldn't get local address");
191 /// assert_eq!(addr.as_pathname(), None);
195 #[stable(feature = "unix_socket", since = "1.10.0")]
197 pub fn as_pathname(&self) -> Option<&Path> {
198 if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None }
201 /// Returns the contents of this address if it is an abstract namespace
202 /// without the leading null byte.
207 /// #![feature(unix_socket_abstract)]
208 /// use std::os::unix::net::{UnixListener, SocketAddr};
210 /// fn main() -> std::io::Result<()> {
211 /// let namespace = b"hidden";
212 /// let namespace_addr = SocketAddr::from_abstract_namespace(&namespace[..])?;
213 /// let socket = UnixListener::bind_addr(&namespace_addr)?;
214 /// let local_addr = socket.local_addr().expect("Couldn't get local address");
215 /// assert_eq!(local_addr.as_abstract_namespace(), Some(&namespace[..]));
219 #[doc(cfg(any(target_os = "android", target_os = "linux")))]
220 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
221 #[unstable(feature = "unix_socket_abstract", issue = "85410")]
222 pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
223 if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None }
226 fn address(&self) -> AddressKind<'_> {
227 let len = self.len as usize - sun_path_offset(&self.addr);
228 let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
230 // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
232 || (cfg!(not(any(target_os = "linux", target_os = "android")))
233 && self.addr.sun_path[0] == 0)
236 } else if self.addr.sun_path[0] == 0 {
237 AddressKind::Abstract(&path[1..len])
239 AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
243 /// Creates an abstract domain socket address from a namespace
245 /// An abstract address does not create a file unlike traditional path-based
246 /// Unix sockets. The advantage of this is that the address will disappear when
247 /// the socket bound to it is closed, so no filesystem clean up is required.
249 /// The leading null byte for the abstract namespace is automatically added.
251 /// This is a Linux-specific extension. See more at [`unix(7)`].
253 /// [`unix(7)`]: https://man7.org/linux/man-pages/man7/unix.7.html
257 /// This will return an error if the given namespace is too long
262 /// #![feature(unix_socket_abstract)]
263 /// use std::os::unix::net::{UnixListener, SocketAddr};
265 /// fn main() -> std::io::Result<()> {
266 /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?;
267 /// let listener = match UnixListener::bind_addr(&addr) {
268 /// Ok(sock) => sock,
270 /// println!("Couldn't bind: {:?}", err);
277 #[doc(cfg(any(target_os = "android", target_os = "linux")))]
278 #[cfg(any(doc, target_os = "android", target_os = "linux",))]
279 #[unstable(feature = "unix_socket_abstract", issue = "85410")]
280 pub fn from_abstract_namespace(namespace: &[u8]) -> io::Result<SocketAddr> {
282 let mut addr: libc::sockaddr_un = mem::zeroed();
283 addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
285 if namespace.len() + 1 > addr.sun_path.len() {
286 return Err(io::Error::new_const(
287 io::ErrorKind::InvalidInput,
288 &"namespace must be shorter than SUN_LEN",
292 crate::ptr::copy_nonoverlapping(
294 addr.sun_path.as_mut_ptr().offset(1) as *mut u8,
297 let len = (sun_path_offset(&addr) + 1 + namespace.len()) as libc::socklen_t;
298 SocketAddr::from_parts(addr, len)
303 #[stable(feature = "unix_socket", since = "1.10.0")]
304 impl fmt::Debug for SocketAddr {
305 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
306 match self.address() {
307 AddressKind::Unnamed => write!(fmt, "(unnamed)"),
308 AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
309 AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),