1 use super::path_offset; 2 use std::ffi::OsStr; 3 use std::os::unix::ffi::OsStrExt; 4 use std::path::Path; 5 use std::{ascii, fmt}; 6 7 /// An address associated with a `mio` specific Unix socket. 8 /// 9 /// This is implemented instead of imported from [`net::SocketAddr`] because 10 /// there is no way to create a [`net::SocketAddr`]. One must be returned by 11 /// [`accept`], so this is returned instead. 12 /// 13 /// [`net::SocketAddr`]: std::os::unix::net::SocketAddr 14 /// [`accept`]: #method.accept 15 pub struct SocketAddr { 16 sockaddr: libc::sockaddr_un, 17 socklen: libc::socklen_t, 18 } 19 20 struct AsciiEscaped<'a>(&'a [u8]); 21 22 enum AddressKind<'a> { 23 Unnamed, 24 Pathname(&'a Path), 25 Abstract(&'a [u8]), 26 } 27 28 impl SocketAddr { address(&self) -> AddressKind<'_>29 fn address(&self) -> AddressKind<'_> { 30 let offset = path_offset(&self.sockaddr); 31 // Don't underflow in `len` below. 32 if (self.socklen as usize) < offset { 33 return AddressKind::Unnamed; 34 } 35 let len = self.socklen as usize - offset; 36 let path = unsafe { &*(&self.sockaddr.sun_path as *const [libc::c_char] as *const [u8]) }; 37 38 // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses 39 if len == 0 40 || (cfg!(not(any(target_os = "linux", target_os = "android"))) 41 && self.sockaddr.sun_path[0] == 0) 42 { 43 AddressKind::Unnamed 44 } else if self.sockaddr.sun_path[0] == 0 { 45 AddressKind::Abstract(&path[1..len]) 46 } else { 47 AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) 48 } 49 } 50 } 51 52 cfg_os_poll! { 53 use std::{io, mem}; 54 55 impl SocketAddr { 56 pub(crate) fn new<F>(f: F) -> io::Result<SocketAddr> 57 where 58 F: FnOnce(*mut libc::sockaddr, &mut libc::socklen_t) -> io::Result<libc::c_int>, 59 { 60 let mut sockaddr = { 61 let sockaddr = mem::MaybeUninit::<libc::sockaddr_un>::zeroed(); 62 unsafe { sockaddr.assume_init() } 63 }; 64 65 let raw_sockaddr = &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr; 66 let mut socklen = mem::size_of_val(&sockaddr) as libc::socklen_t; 67 68 f(raw_sockaddr, &mut socklen)?; 69 Ok(SocketAddr::from_parts(sockaddr, socklen)) 70 } 71 72 pub(crate) fn from_parts(sockaddr: libc::sockaddr_un, socklen: libc::socklen_t) -> SocketAddr { 73 SocketAddr { sockaddr, socklen } 74 } 75 76 /// Returns `true` if the address is unnamed. 77 /// 78 /// Documentation reflected in [`SocketAddr`] 79 /// 80 /// [`SocketAddr`]: std::os::unix::net::SocketAddr 81 pub fn is_unnamed(&self) -> bool { 82 matches!(self.address(), AddressKind::Unnamed) 83 } 84 85 /// Returns the contents of this address if it is a `pathname` address. 86 /// 87 /// Documentation reflected in [`SocketAddr`] 88 /// 89 /// [`SocketAddr`]: std::os::unix::net::SocketAddr 90 pub fn as_pathname(&self) -> Option<&Path> { 91 if let AddressKind::Pathname(path) = self.address() { 92 Some(path) 93 } else { 94 None 95 } 96 } 97 98 /// Returns the contents of this address if it is an abstract namespace 99 /// without the leading null byte. 100 // Link to std::os::unix::net::SocketAddr pending 101 // https://github.com/rust-lang/rust/issues/85410. 102 pub fn as_abstract_namespace(&self) -> Option<&[u8]> { 103 if let AddressKind::Abstract(path) = self.address() { 104 Some(path) 105 } else { 106 None 107 } 108 } 109 } 110 } 111 112 impl fmt::Debug for SocketAddr { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result113 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 114 match self.address() { 115 AddressKind::Unnamed => write!(fmt, "(unnamed)"), 116 AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), 117 AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), 118 } 119 } 120 } 121 122 impl<'a> fmt::Display for AsciiEscaped<'a> { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result123 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 124 write!(fmt, "\"")?; 125 for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { 126 write!(fmt, "{}", byte as char)?; 127 } 128 write!(fmt, "\"") 129 } 130 } 131