]> git.lizzy.rs Git - rust.git/blob - library/std/src/os/unix/net/addr.rs
Do not store overlap_mode, just pass it down on insert
[rust.git] / library / std / src / os / unix / net / addr.rs
1 use crate::ffi::OsStr;
2 use crate::os::unix::ffi::OsStrExt;
3 use crate::path::Path;
4 use crate::sys::cvt;
5 use crate::{ascii, fmt, io, iter, mem};
6
7 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
8 #[cfg(not(unix))]
9 #[allow(non_camel_case_types)]
10 mod libc {
11     pub use libc::c_int;
12     pub type socklen_t = u32;
13     pub struct sockaddr;
14     #[derive(Clone)]
15     pub struct sockaddr_un;
16 }
17
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;
22     path - base
23 }
24
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;
28
29     let bytes = path.as_os_str().as_bytes();
30
31     if bytes.contains(&0) {
32         return Err(io::Error::new_const(
33             io::ErrorKind::InvalidInput,
34             &"paths must not contain interior null bytes",
35         ));
36     }
37
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",
42         ));
43     }
44     for (dst, src) in iter::zip(&mut addr.sun_path, bytes) {
45         *dst = *src as libc::c_char;
46     }
47     // null byte for pathname addresses is already there because we zeroed the
48     // struct
49
50     let mut len = sun_path_offset(&addr) + bytes.len();
51     match bytes.get(0) {
52         Some(&0) | None => {}
53         Some(_) => len += 1,
54     }
55     Ok((addr, len as libc::socklen_t))
56 }
57
58 enum AddressKind<'a> {
59     Unnamed,
60     Pathname(&'a Path),
61     Abstract(&'a [u8]),
62 }
63
64 struct AsciiEscaped<'a>(&'a [u8]);
65
66 impl<'a> fmt::Display for AsciiEscaped<'a> {
67     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
68         write!(fmt, "\"")?;
69         for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
70             write!(fmt, "{}", byte as char)?;
71         }
72         write!(fmt, "\"")
73     }
74 }
75
76 /// An address associated with a Unix socket.
77 ///
78 /// # Examples
79 ///
80 /// ```
81 /// use std::os::unix::net::UnixListener;
82 ///
83 /// let socket = match UnixListener::bind("/tmp/sock") {
84 ///     Ok(sock) => sock,
85 ///     Err(e) => {
86 ///         println!("Couldn't bind: {:?}", e);
87 ///         return
88 ///     }
89 /// };
90 /// let addr = socket.local_addr().expect("Couldn't get local address");
91 /// ```
92 #[derive(Clone)]
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,
97 }
98
99 impl 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 = 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)
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 len == 0 {
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",
124             ));
125         }
126
127         Ok(SocketAddr { addr, len })
128     }
129
130     /// Returns `true` if the address is unnamed.
131     ///
132     /// # Examples
133     ///
134     /// A named address:
135     ///
136     /// ```no_run
137     /// use std::os::unix::net::UnixListener;
138     ///
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);
143     ///     Ok(())
144     /// }
145     /// ```
146     ///
147     /// An unnamed address:
148     ///
149     /// ```
150     /// use std::os::unix::net::UnixDatagram;
151     ///
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);
156     ///     Ok(())
157     /// }
158     /// ```
159     #[must_use]
160     #[stable(feature = "unix_socket", since = "1.10.0")]
161     pub fn is_unnamed(&self) -> bool {
162         matches!(self.address(), AddressKind::Unnamed)
163     }
164
165     /// Returns the contents of this address if it is a `pathname` address.
166     ///
167     /// # Examples
168     ///
169     /// With a pathname:
170     ///
171     /// ```no_run
172     /// use std::os::unix::net::UnixListener;
173     /// use std::path::Path;
174     ///
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")));
179     ///     Ok(())
180     /// }
181     /// ```
182     ///
183     /// Without a pathname:
184     ///
185     /// ```
186     /// use std::os::unix::net::UnixDatagram;
187     ///
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);
192     ///     Ok(())
193     /// }
194     /// ```
195     #[stable(feature = "unix_socket", since = "1.10.0")]
196     #[must_use]
197     pub fn as_pathname(&self) -> Option<&Path> {
198         if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None }
199     }
200
201     /// Returns the contents of this address if it is an abstract namespace
202     /// without the leading null byte.
203     ///
204     /// # Examples
205     ///
206     /// ```no_run
207     /// #![feature(unix_socket_abstract)]
208     /// use std::os::unix::net::{UnixListener, SocketAddr};
209     ///
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[..]));
216     ///     Ok(())
217     /// }
218     /// ```
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 }
224     }
225
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) };
229
230         // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
231         if len == 0
232             || (cfg!(not(any(target_os = "linux", target_os = "android")))
233                 && self.addr.sun_path[0] == 0)
234         {
235             AddressKind::Unnamed
236         } else if self.addr.sun_path[0] == 0 {
237             AddressKind::Abstract(&path[1..len])
238         } else {
239             AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
240         }
241     }
242
243     /// Creates an abstract domain socket address from a namespace
244     ///
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.
248     ///
249     /// The leading null byte for the abstract namespace is automatically added.
250     ///
251     /// This is a Linux-specific extension. See more at [`unix(7)`].
252     ///
253     /// [`unix(7)`]: https://man7.org/linux/man-pages/man7/unix.7.html
254     ///
255     /// # Errors
256     ///
257     /// This will return an error if the given namespace is too long
258     ///
259     /// # Examples
260     ///
261     /// ```no_run
262     /// #![feature(unix_socket_abstract)]
263     /// use std::os::unix::net::{UnixListener, SocketAddr};
264     ///
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,
269     ///         Err(err) => {
270     ///             println!("Couldn't bind: {:?}", err);
271     ///             return Err(err);
272     ///         }
273     ///     };
274     ///     Ok(())
275     /// }
276     /// ```
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> {
281         unsafe {
282             let mut addr: libc::sockaddr_un = mem::zeroed();
283             addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
284
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",
289                 ));
290             }
291
292             crate::ptr::copy_nonoverlapping(
293                 namespace.as_ptr(),
294                 addr.sun_path.as_mut_ptr().offset(1) as *mut u8,
295                 namespace.len(),
296             );
297             let len = (sun_path_offset(&addr) + 1 + namespace.len()) as libc::socklen_t;
298             SocketAddr::from_parts(addr, len)
299         }
300     }
301 }
302
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),
310         }
311     }
312 }