1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use super::path_offset;
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::{ascii, fmt};
pub struct SocketAddr {
sockaddr: libc::sockaddr_un,
socklen: libc::socklen_t,
}
struct AsciiEscaped<'a>(&'a [u8]);
enum AddressKind<'a> {
Unnamed,
Pathname(&'a Path),
Abstract(&'a [u8]),
}
impl SocketAddr {
fn address(&self) -> AddressKind<'_> {
let offset = path_offset(&self.sockaddr);
if (self.socklen as usize) < offset {
return AddressKind::Unnamed;
}
let len = self.socklen as usize - offset;
let path = unsafe { &*(&self.sockaddr.sun_path as *const [libc::c_char] as *const [u8]) };
if len == 0
|| (cfg!(not(any(target_os = "linux", target_os = "android")))
&& self.sockaddr.sun_path[0] == 0)
{
AddressKind::Unnamed
} else if self.sockaddr.sun_path[0] == 0 {
AddressKind::Abstract(&path[1..len])
} else {
AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
}
}
}
cfg_os_poll! {
use std::{io, mem};
impl SocketAddr {
pub(crate) fn new<F>(f: F) -> io::Result<SocketAddr>
where
F: FnOnce(*mut libc::sockaddr, &mut libc::socklen_t) -> io::Result<libc::c_int>,
{
let mut sockaddr = {
let sockaddr = mem::MaybeUninit::<libc::sockaddr_un>::zeroed();
unsafe { sockaddr.assume_init() }
};
let raw_sockaddr = &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr;
let mut socklen = mem::size_of_val(&sockaddr) as libc::socklen_t;
f(raw_sockaddr, &mut socklen)?;
Ok(SocketAddr::from_parts(sockaddr, socklen))
}
pub(crate) fn from_parts(sockaddr: libc::sockaddr_un, socklen: libc::socklen_t) -> SocketAddr {
SocketAddr { sockaddr, socklen }
}
pub fn is_unnamed(&self) -> bool {
matches!(self.address(), AddressKind::Unnamed)
}
pub fn as_pathname(&self) -> Option<&Path> {
if let AddressKind::Pathname(path) = self.address() {
Some(path)
} else {
None
}
}
pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
if let AddressKind::Abstract(path) = self.address() {
Some(path)
} else {
None
}
}
}
}
impl fmt::Debug for SocketAddr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.address() {
AddressKind::Unnamed => write!(fmt, "(unnamed)"),
AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
}
}
}
impl<'a> fmt::Display for AsciiEscaped<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "\"")?;
for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
write!(fmt, "{}", byte as char)?;
}
write!(fmt, "\"")
}
}