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