2 #[cfg(any(doc, target_os = "android", target_os = "linux"))]
3 use crate::os::net::linux_ext;
4 use crate::os::unix::ffi::OsStrExt;
6 use crate::sealed::Sealed;
8 use crate::{fmt, io, mem, ptr};
10 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
12 #[allow(non_camel_case_types)]
15 pub type socklen_t = u32;
18 pub struct sockaddr_un;
21 fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
22 // Work with an actual instance of the type since using a null pointer is UB
23 let base = (addr as *const libc::sockaddr_un).addr();
24 let path = (&addr.sun_path as *const libc::c_char).addr();
28 pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
29 // SAFETY: All zeros is a valid representation for `sockaddr_un`.
30 let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() };
31 addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
33 let bytes = path.as_os_str().as_bytes();
35 if bytes.contains(&0) {
36 return Err(io::const_io_error!(
37 io::ErrorKind::InvalidInput,
38 "paths must not contain interior null bytes",
42 if bytes.len() >= addr.sun_path.len() {
43 return Err(io::const_io_error!(
44 io::ErrorKind::InvalidInput,
45 "path must be shorter than SUN_LEN",
48 // SAFETY: `bytes` and `addr.sun_path` are not overlapping and
49 // both point to valid memory.
50 // NOTE: We zeroed the memory above, so the path is already null
53 ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len())
56 let mut len = sun_path_offset(&addr) + bytes.len();
61 Ok((addr, len as libc::socklen_t))
64 enum AddressKind<'a> {
70 /// An address associated with a Unix socket.
75 /// use std::os::unix::net::UnixListener;
77 /// let socket = match UnixListener::bind("/tmp/sock") {
80 /// println!("Couldn't bind: {e:?}");
84 /// let addr = socket.local_addr().expect("Couldn't get local address");
87 #[stable(feature = "unix_socket", since = "1.10.0")]
88 pub struct SocketAddr {
89 pub(super) addr: libc::sockaddr_un,
90 pub(super) len: libc::socklen_t,
94 pub(super) fn new<F>(f: F) -> io::Result<SocketAddr>
96 F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int,
99 let mut addr: libc::sockaddr_un = mem::zeroed();
100 let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
101 cvt(f(&mut addr as *mut _ as *mut _, &mut len))?;
102 SocketAddr::from_parts(addr, len)
106 pub(super) fn from_parts(
107 addr: libc::sockaddr_un,
108 mut len: libc::socklen_t,
109 ) -> io::Result<SocketAddr> {
111 // When there is a datagram from unnamed unix socket
112 // linux returns zero bytes of address
113 len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address
114 } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
115 return Err(io::const_io_error!(
116 io::ErrorKind::InvalidInput,
117 "file descriptor did not correspond to a Unix socket",
121 Ok(SocketAddr { addr, len })
124 /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
128 /// Returns an error if the path is longer than `SUN_LEN` or if it contains
134 /// use std::os::unix::net::SocketAddr;
135 /// use std::path::Path;
137 /// # fn main() -> std::io::Result<()> {
138 /// let address = SocketAddr::from_pathname("/path/to/socket")?;
139 /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
144 /// Creating a `SocketAddr` with a NULL byte results in an error.
147 /// use std::os::unix::net::SocketAddr;
149 /// assert!(SocketAddr::from_pathname("/path/with/\0/bytes").is_err());
151 #[stable(feature = "unix_socket_creation", since = "1.61.0")]
152 pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr>
156 sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len })
159 /// Returns `true` if the address is unnamed.
166 /// use std::os::unix::net::UnixListener;
168 /// fn main() -> std::io::Result<()> {
169 /// let socket = UnixListener::bind("/tmp/sock")?;
170 /// let addr = socket.local_addr().expect("Couldn't get local address");
171 /// assert_eq!(addr.is_unnamed(), false);
176 /// An unnamed address:
179 /// use std::os::unix::net::UnixDatagram;
181 /// fn main() -> std::io::Result<()> {
182 /// let socket = UnixDatagram::unbound()?;
183 /// let addr = socket.local_addr().expect("Couldn't get local address");
184 /// assert_eq!(addr.is_unnamed(), true);
189 #[stable(feature = "unix_socket", since = "1.10.0")]
190 pub fn is_unnamed(&self) -> bool {
191 matches!(self.address(), AddressKind::Unnamed)
194 /// Returns the contents of this address if it is a `pathname` address.
201 /// use std::os::unix::net::UnixListener;
202 /// use std::path::Path;
204 /// fn main() -> std::io::Result<()> {
205 /// let socket = UnixListener::bind("/tmp/sock")?;
206 /// let addr = socket.local_addr().expect("Couldn't get local address");
207 /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
212 /// Without a pathname:
215 /// use std::os::unix::net::UnixDatagram;
217 /// fn main() -> std::io::Result<()> {
218 /// let socket = UnixDatagram::unbound()?;
219 /// let addr = socket.local_addr().expect("Couldn't get local address");
220 /// assert_eq!(addr.as_pathname(), None);
224 #[stable(feature = "unix_socket", since = "1.10.0")]
226 pub fn as_pathname(&self) -> Option<&Path> {
227 if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None }
230 fn address(&self) -> AddressKind<'_> {
231 let len = self.len as usize - sun_path_offset(&self.addr);
232 let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
234 // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
236 || (cfg!(not(any(target_os = "linux", target_os = "android")))
237 && self.addr.sun_path[0] == 0)
240 } else if self.addr.sun_path[0] == 0 {
241 AddressKind::Abstract(&path[1..len])
243 AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
248 #[unstable(feature = "unix_socket_abstract", issue = "85410")]
249 impl Sealed for SocketAddr {}
251 #[doc(cfg(any(target_os = "android", target_os = "linux")))]
252 #[cfg(any(doc, target_os = "android", target_os = "linux"))]
253 #[unstable(feature = "unix_socket_abstract", issue = "85410")]
254 impl linux_ext::addr::SocketAddrExt for SocketAddr {
255 fn as_abstract_name(&self) -> Option<&[u8]> {
256 if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None }
259 fn from_abstract_name<N>(name: N) -> crate::io::Result<Self>
263 let name = name.as_ref();
265 let mut addr: libc::sockaddr_un = mem::zeroed();
266 addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
268 if name.len() + 1 > addr.sun_path.len() {
269 return Err(io::const_io_error!(
270 io::ErrorKind::InvalidInput,
271 "abstract socket name must be shorter than SUN_LEN",
275 crate::ptr::copy_nonoverlapping(
277 addr.sun_path.as_mut_ptr().add(1) as *mut u8,
280 let len = (sun_path_offset(&addr) + 1 + name.len()) as libc::socklen_t;
281 SocketAddr::from_parts(addr, len)
286 #[stable(feature = "unix_socket", since = "1.10.0")]
287 impl fmt::Debug for SocketAddr {
288 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
289 match self.address() {
290 AddressKind::Unnamed => write!(fmt, "(unnamed)"),
291 AddressKind::Abstract(name) => write!(fmt, "\"{}\" (abstract)", name.escape_ascii()),
292 AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"),