mio/sys/unix/uds/
socketaddr.rs1use super::path_offset;
2use std::ffi::OsStr;
3use std::os::unix::ffi::OsStrExt;
4use std::path::Path;
5use std::{ascii, fmt};
6
7pub struct SocketAddr {
16 sockaddr: libc::sockaddr_un,
17 socklen: libc::socklen_t,
18}
19
20struct AsciiEscaped<'a>(&'a [u8]);
21
22enum AddressKind<'a> {
23 Unnamed,
24 Pathname(&'a Path),
25 Abstract(&'a [u8]),
26}
27
28impl SocketAddr {
29 fn address(&self) -> AddressKind<'_> {
30 let offset = path_offset(&self.sockaddr);
31 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 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
52cfg_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 pub(crate) fn raw_sockaddr(&self) -> &libc::sockaddr_un {
77 &self.sockaddr
78 }
79
80 pub(crate) fn raw_socklen(&self) -> &libc::socklen_t {
81 &self.socklen
82 }
83
84 pub fn is_unnamed(&self) -> bool {
90 matches!(self.address(), AddressKind::Unnamed)
91 }
92
93 pub fn as_pathname(&self) -> Option<&Path> {
99 if let AddressKind::Pathname(path) = self.address() {
100 Some(path)
101 } else {
102 None
103 }
104 }
105
106 pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
111 if let AddressKind::Abstract(path) = self.address() {
112 Some(path)
113 } else {
114 None
115 }
116 }
117 }
118}
119
120impl fmt::Debug for SocketAddr {
121 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
122 match self.address() {
123 AddressKind::Unnamed => write!(fmt, "(unnamed)"),
124 AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
125 AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
126 }
127 }
128}
129
130impl<'a> fmt::Display for AsciiEscaped<'a> {
131 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
132 write!(fmt, "\"")?;
133 for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
134 write!(fmt, "{}", byte as char)?;
135 }
136 write!(fmt, "\"")
137 }
138}