std/os/unix/net/
addr.rs

1use crate::bstr::ByteStr;
2use crate::ffi::OsStr;
3#[cfg(any(doc, target_os = "android", target_os = "linux"))]
4use crate::os::net::linux_ext;
5use crate::os::unix::ffi::OsStrExt;
6use crate::path::Path;
7use crate::sealed::Sealed;
8use crate::sys::cvt;
9use crate::{fmt, io, mem, ptr};
10
11// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
12#[cfg(not(unix))]
13#[allow(non_camel_case_types)]
14mod libc {
15    pub use core::ffi::c_int;
16    pub type socklen_t = u32;
17    pub struct sockaddr;
18    #[derive(Clone)]
19    pub struct sockaddr_un {
20        pub sun_path: [u8; 1],
21    }
22}
23
24const SUN_PATH_OFFSET: usize = mem::offset_of!(libc::sockaddr_un, sun_path);
25
26pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
27    // SAFETY: All zeros is a valid representation for `sockaddr_un`.
28    let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() };
29    addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
30
31    let bytes = path.as_os_str().as_bytes();
32
33    if bytes.contains(&0) {
34        return Err(io::const_error!(
35            io::ErrorKind::InvalidInput,
36            "paths must not contain interior null bytes",
37        ));
38    }
39
40    if bytes.len() >= addr.sun_path.len() {
41        return Err(io::const_error!(
42            io::ErrorKind::InvalidInput,
43            "path must be shorter than SUN_LEN",
44        ));
45    }
46    // SAFETY: `bytes` and `addr.sun_path` are not overlapping and
47    // both point to valid memory.
48    // NOTE: We zeroed the memory above, so the path is already null
49    // terminated.
50    unsafe {
51        ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len())
52    };
53
54    let mut len = SUN_PATH_OFFSET + bytes.len();
55    match bytes.get(0) {
56        Some(&0) | None => {}
57        Some(_) => len += 1,
58    }
59    Ok((addr, len as libc::socklen_t))
60}
61
62enum AddressKind<'a> {
63    Unnamed,
64    Pathname(&'a Path),
65    Abstract(&'a ByteStr),
66}
67
68/// An address associated with a Unix socket.
69///
70/// # Examples
71///
72/// ```
73/// use std::os::unix::net::UnixListener;
74///
75/// let socket = match UnixListener::bind("/tmp/sock") {
76///     Ok(sock) => sock,
77///     Err(e) => {
78///         println!("Couldn't bind: {e:?}");
79///         return
80///     }
81/// };
82/// let addr = socket.local_addr().expect("Couldn't get local address");
83/// ```
84#[derive(Clone)]
85#[stable(feature = "unix_socket", since = "1.10.0")]
86pub struct SocketAddr {
87    pub(super) addr: libc::sockaddr_un,
88    pub(super) len: libc::socklen_t,
89}
90
91impl SocketAddr {
92    pub(super) fn new<F>(f: F) -> io::Result<SocketAddr>
93    where
94        F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int,
95    {
96        unsafe {
97            let mut addr: libc::sockaddr_un = mem::zeroed();
98            let mut len = size_of::<libc::sockaddr_un>() as libc::socklen_t;
99            cvt(f((&raw mut addr) as *mut _, &mut len))?;
100            SocketAddr::from_parts(addr, len)
101        }
102    }
103
104    pub(super) fn from_parts(
105        addr: libc::sockaddr_un,
106        mut len: libc::socklen_t,
107    ) -> io::Result<SocketAddr> {
108        if cfg!(target_os = "openbsd") {
109            // on OpenBSD, getsockname(2) returns the actual size of the socket address,
110            // and not the len of the content. Figure out the length for ourselves.
111            // https://marc.info/?l=openbsd-bugs&m=170105481926736&w=2
112            let sun_path: &[u8] =
113                unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&addr.sun_path) };
114            len = core::slice::memchr::memchr(0, sun_path)
115                .map_or(len, |new_len| (new_len + SUN_PATH_OFFSET) as libc::socklen_t);
116        }
117
118        if len == 0 {
119            // When there is a datagram from unnamed unix socket
120            // linux returns zero bytes of address
121            len = SUN_PATH_OFFSET as libc::socklen_t; // i.e., zero-length address
122        } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
123            return Err(io::const_error!(
124                io::ErrorKind::InvalidInput,
125                "file descriptor did not correspond to a Unix socket",
126            ));
127        }
128
129        Ok(SocketAddr { addr, len })
130    }
131
132    /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
133    ///
134    /// # Errors
135    ///
136    /// Returns an error if the path is longer than `SUN_LEN` or if it contains
137    /// NULL bytes.
138    ///
139    /// # Examples
140    ///
141    /// ```
142    /// use std::os::unix::net::SocketAddr;
143    /// use std::path::Path;
144    ///
145    /// # fn main() -> std::io::Result<()> {
146    /// let address = SocketAddr::from_pathname("/path/to/socket")?;
147    /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
148    /// # Ok(())
149    /// # }
150    /// ```
151    ///
152    /// Creating a `SocketAddr` with a NULL byte results in an error.
153    ///
154    /// ```
155    /// use std::os::unix::net::SocketAddr;
156    ///
157    /// assert!(SocketAddr::from_pathname("/path/with/\0/bytes").is_err());
158    /// ```
159    #[stable(feature = "unix_socket_creation", since = "1.61.0")]
160    pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr>
161    where
162        P: AsRef<Path>,
163    {
164        sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len })
165    }
166
167    /// Returns `true` if the address is unnamed.
168    ///
169    /// # Examples
170    ///
171    /// A named address:
172    ///
173    /// ```no_run
174    /// use std::os::unix::net::UnixListener;
175    ///
176    /// fn main() -> std::io::Result<()> {
177    ///     let socket = UnixListener::bind("/tmp/sock")?;
178    ///     let addr = socket.local_addr().expect("Couldn't get local address");
179    ///     assert_eq!(addr.is_unnamed(), false);
180    ///     Ok(())
181    /// }
182    /// ```
183    ///
184    /// An unnamed address:
185    ///
186    /// ```
187    /// use std::os::unix::net::UnixDatagram;
188    ///
189    /// fn main() -> std::io::Result<()> {
190    ///     let socket = UnixDatagram::unbound()?;
191    ///     let addr = socket.local_addr().expect("Couldn't get local address");
192    ///     assert_eq!(addr.is_unnamed(), true);
193    ///     Ok(())
194    /// }
195    /// ```
196    #[must_use]
197    #[stable(feature = "unix_socket", since = "1.10.0")]
198    pub fn is_unnamed(&self) -> bool {
199        matches!(self.address(), AddressKind::Unnamed)
200    }
201
202    /// Returns the contents of this address if it is a `pathname` address.
203    ///
204    /// # Examples
205    ///
206    /// With a pathname:
207    ///
208    /// ```no_run
209    /// use std::os::unix::net::UnixListener;
210    /// use std::path::Path;
211    ///
212    /// fn main() -> std::io::Result<()> {
213    ///     let socket = UnixListener::bind("/tmp/sock")?;
214    ///     let addr = socket.local_addr().expect("Couldn't get local address");
215    ///     assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
216    ///     Ok(())
217    /// }
218    /// ```
219    ///
220    /// Without a pathname:
221    ///
222    /// ```
223    /// use std::os::unix::net::UnixDatagram;
224    ///
225    /// fn main() -> std::io::Result<()> {
226    ///     let socket = UnixDatagram::unbound()?;
227    ///     let addr = socket.local_addr().expect("Couldn't get local address");
228    ///     assert_eq!(addr.as_pathname(), None);
229    ///     Ok(())
230    /// }
231    /// ```
232    #[stable(feature = "unix_socket", since = "1.10.0")]
233    #[must_use]
234    pub fn as_pathname(&self) -> Option<&Path> {
235        if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None }
236    }
237
238    fn address(&self) -> AddressKind<'_> {
239        let len = self.len as usize - SUN_PATH_OFFSET;
240        let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
241
242        // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
243        if len == 0
244            || (cfg!(not(any(target_os = "linux", target_os = "android")))
245                && self.addr.sun_path[0] == 0)
246        {
247            AddressKind::Unnamed
248        } else if self.addr.sun_path[0] == 0 {
249            AddressKind::Abstract(ByteStr::from_bytes(&path[1..len]))
250        } else {
251            AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
252        }
253    }
254}
255
256#[stable(feature = "unix_socket_abstract", since = "1.70.0")]
257impl Sealed for SocketAddr {}
258
259#[doc(cfg(any(target_os = "android", target_os = "linux")))]
260#[cfg(any(doc, target_os = "android", target_os = "linux"))]
261#[stable(feature = "unix_socket_abstract", since = "1.70.0")]
262impl linux_ext::addr::SocketAddrExt for SocketAddr {
263    fn as_abstract_name(&self) -> Option<&[u8]> {
264        if let AddressKind::Abstract(name) = self.address() { Some(name.as_bytes()) } else { None }
265    }
266
267    fn from_abstract_name<N>(name: N) -> crate::io::Result<Self>
268    where
269        N: AsRef<[u8]>,
270    {
271        let name = name.as_ref();
272        unsafe {
273            let mut addr: libc::sockaddr_un = mem::zeroed();
274            addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
275
276            if name.len() + 1 > addr.sun_path.len() {
277                return Err(io::const_error!(
278                    io::ErrorKind::InvalidInput,
279                    "abstract socket name must be shorter than SUN_LEN",
280                ));
281            }
282
283            crate::ptr::copy_nonoverlapping(
284                name.as_ptr(),
285                addr.sun_path.as_mut_ptr().add(1) as *mut u8,
286                name.len(),
287            );
288            let len = (SUN_PATH_OFFSET + 1 + name.len()) as libc::socklen_t;
289            SocketAddr::from_parts(addr, len)
290        }
291    }
292}
293
294#[stable(feature = "unix_socket", since = "1.10.0")]
295impl fmt::Debug for SocketAddr {
296    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
297        match self.address() {
298            AddressKind::Unnamed => write!(fmt, "(unnamed)"),
299            AddressKind::Abstract(name) => write!(fmt, "{name:?} (abstract)"),
300            AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"),
301        }
302    }
303}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy