]> git.proxmox.com Git - rustc.git/blob - library/std/src/sys/unix/ext/net/addr.rs
New upstream version 1.53.0+dfsg1
[rustc.git] / library / std / src / sys / unix / ext / 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 may 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 addr: libc::sockaddr_un,
96 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 #[stable(feature = "unix_socket", since = "1.10.0")]
160 pub fn is_unnamed(&self) -> bool {
161 if let AddressKind::Unnamed = self.address() { true } else { false }
162 }
163
164 /// Returns the contents of this address if it is a `pathname` address.
165 ///
166 /// # Examples
167 ///
168 /// With a pathname:
169 ///
170 /// ```no_run
171 /// use std::os::unix::net::UnixListener;
172 /// use std::path::Path;
173 ///
174 /// fn main() -> std::io::Result<()> {
175 /// let socket = UnixListener::bind("/tmp/sock")?;
176 /// let addr = socket.local_addr().expect("Couldn't get local address");
177 /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
178 /// Ok(())
179 /// }
180 /// ```
181 ///
182 /// Without a pathname:
183 ///
184 /// ```
185 /// use std::os::unix::net::UnixDatagram;
186 ///
187 /// fn main() -> std::io::Result<()> {
188 /// let socket = UnixDatagram::unbound()?;
189 /// let addr = socket.local_addr().expect("Couldn't get local address");
190 /// assert_eq!(addr.as_pathname(), None);
191 /// Ok(())
192 /// }
193 /// ```
194 #[stable(feature = "unix_socket", since = "1.10.0")]
195 pub fn as_pathname(&self) -> Option<&Path> {
196 if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None }
197 }
198
199 fn address(&self) -> AddressKind<'_> {
200 let len = self.len as usize - sun_path_offset(&self.addr);
201 let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
202
203 // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
204 if len == 0
205 || (cfg!(not(any(target_os = "linux", target_os = "android")))
206 && self.addr.sun_path[0] == 0)
207 {
208 AddressKind::Unnamed
209 } else if self.addr.sun_path[0] == 0 {
210 AddressKind::Abstract(&path[1..len])
211 } else {
212 AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
213 }
214 }
215 }
216
217 #[stable(feature = "unix_socket", since = "1.10.0")]
218 impl fmt::Debug for SocketAddr {
219 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
220 match self.address() {
221 AddressKind::Unnamed => write!(fmt, "(unnamed)"),
222 AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
223 AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
224 }
225 }
226 }