addr.rs - source (original) (raw)
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:🥅: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:🥅: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:🥅: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:🥅: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:🥅: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:🥅: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:🥅: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:🥅: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}