• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::path_offset;
2 use std::ffi::OsStr;
3 use std::os::unix::ffi::OsStrExt;
4 use std::path::Path;
5 use std::{ascii, fmt};
6 
7 /// An address associated with a `mio` specific Unix socket.
8 ///
9 /// This is implemented instead of imported from [`net::SocketAddr`] because
10 /// there is no way to create a [`net::SocketAddr`]. One must be returned by
11 /// [`accept`], so this is returned instead.
12 ///
13 /// [`net::SocketAddr`]: std::os::unix::net::SocketAddr
14 /// [`accept`]: #method.accept
15 pub struct SocketAddr {
16     sockaddr: libc::sockaddr_un,
17     socklen: libc::socklen_t,
18 }
19 
20 struct AsciiEscaped<'a>(&'a [u8]);
21 
22 enum AddressKind<'a> {
23     Unnamed,
24     Pathname(&'a Path),
25     Abstract(&'a [u8]),
26 }
27 
28 impl SocketAddr {
address(&self) -> AddressKind<'_>29     fn address(&self) -> AddressKind<'_> {
30         let offset = path_offset(&self.sockaddr);
31         // Don't underflow in `len` below.
32         if (self.socklen as usize) < offset {
33             return AddressKind::Unnamed;
34         }
35         let len = self.socklen as usize - offset;
36         let path = unsafe { &*(&self.sockaddr.sun_path as *const [libc::c_char] as *const [u8]) };
37 
38         // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
39         if len == 0
40             || (cfg!(not(any(target_os = "linux", target_os = "android")))
41                 && self.sockaddr.sun_path[0] == 0)
42         {
43             AddressKind::Unnamed
44         } else if self.sockaddr.sun_path[0] == 0 {
45             AddressKind::Abstract(&path[1..len])
46         } else {
47             AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
48         }
49     }
50 }
51 
52 cfg_os_poll! {
53     use std::{io, mem};
54 
55     impl SocketAddr {
56         pub(crate) fn new<F>(f: F) -> io::Result<SocketAddr>
57         where
58             F: FnOnce(*mut libc::sockaddr, &mut libc::socklen_t) -> io::Result<libc::c_int>,
59         {
60             let mut sockaddr = {
61                 let sockaddr = mem::MaybeUninit::<libc::sockaddr_un>::zeroed();
62                 unsafe { sockaddr.assume_init() }
63             };
64 
65             let raw_sockaddr = &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr;
66             let mut socklen = mem::size_of_val(&sockaddr) as libc::socklen_t;
67 
68             f(raw_sockaddr, &mut socklen)?;
69             Ok(SocketAddr::from_parts(sockaddr, socklen))
70         }
71 
72         pub(crate) fn from_parts(sockaddr: libc::sockaddr_un, socklen: libc::socklen_t) -> SocketAddr {
73             SocketAddr { sockaddr, socklen }
74         }
75 
76         /// Returns `true` if the address is unnamed.
77         ///
78         /// Documentation reflected in [`SocketAddr`]
79         ///
80         /// [`SocketAddr`]: std::os::unix::net::SocketAddr
81         pub fn is_unnamed(&self) -> bool {
82             matches!(self.address(), AddressKind::Unnamed)
83         }
84 
85         /// Returns the contents of this address if it is a `pathname` address.
86         ///
87         /// Documentation reflected in [`SocketAddr`]
88         ///
89         /// [`SocketAddr`]: std::os::unix::net::SocketAddr
90         pub fn as_pathname(&self) -> Option<&Path> {
91             if let AddressKind::Pathname(path) = self.address() {
92                 Some(path)
93             } else {
94                 None
95             }
96         }
97 
98         /// Returns the contents of this address if it is an abstract namespace
99         /// without the leading null byte.
100         // Link to std::os::unix::net::SocketAddr pending
101         // https://github.com/rust-lang/rust/issues/85410.
102         pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
103             if let AddressKind::Abstract(path) = self.address() {
104                 Some(path)
105             } else {
106                 None
107             }
108         }
109     }
110 }
111 
112 impl fmt::Debug for SocketAddr {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result113     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
114         match self.address() {
115             AddressKind::Unnamed => write!(fmt, "(unnamed)"),
116             AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
117             AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
118         }
119     }
120 }
121 
122 impl<'a> fmt::Display for AsciiEscaped<'a> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result123     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
124         write!(fmt, "\"")?;
125         for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
126             write!(fmt, "{}", byte as char)?;
127         }
128         write!(fmt, "\"")
129     }
130 }
131