1 //! Socket address utilities.
2
3 use crate::backend::c;
4 #[cfg(unix)]
5 use {
6 crate::ffi::CStr,
7 crate::io,
8 crate::path,
9 core::cmp::Ordering,
10 core::fmt,
11 core::hash::{Hash, Hasher},
12 core::slice,
13 };
14
15 /// `struct sockaddr_un`
16 #[cfg(unix)]
17 #[derive(Clone)]
18 #[doc(alias = "sockaddr_un")]
19 pub struct SocketAddrUnix {
20 pub(crate) unix: c::sockaddr_un,
21 #[cfg(not(any(bsd, target_os = "haiku")))]
22 len: c::socklen_t,
23 }
24
25 #[cfg(unix)]
26 impl SocketAddrUnix {
27 /// Construct a new Unix-domain address from a filesystem path.
28 #[inline]
new<P: path::Arg>(path: P) -> io::Result<Self>29 pub fn new<P: path::Arg>(path: P) -> io::Result<Self> {
30 path.into_with_c_str(Self::_new)
31 }
32
33 #[inline]
_new(path: &CStr) -> io::Result<Self>34 fn _new(path: &CStr) -> io::Result<Self> {
35 let mut unix = Self::init();
36 let bytes = path.to_bytes_with_nul();
37 if bytes.len() > unix.sun_path.len() {
38 return Err(io::Errno::NAMETOOLONG);
39 }
40 for (i, b) in bytes.iter().enumerate() {
41 unix.sun_path[i] = *b as c::c_char;
42 }
43
44 #[cfg(any(bsd, target_os = "haiku"))]
45 {
46 unix.sun_len = (offsetof_sun_path() + bytes.len()).try_into().unwrap();
47 }
48
49 Ok(Self {
50 unix,
51 #[cfg(not(any(bsd, target_os = "haiku")))]
52 len: (offsetof_sun_path() + bytes.len()).try_into().unwrap(),
53 })
54 }
55
56 /// Construct a new abstract Unix-domain address from a byte slice.
57 #[cfg(linux_kernel)]
58 #[inline]
new_abstract_name(name: &[u8]) -> io::Result<Self>59 pub fn new_abstract_name(name: &[u8]) -> io::Result<Self> {
60 let mut unix = Self::init();
61 if 1 + name.len() > unix.sun_path.len() {
62 return Err(io::Errno::NAMETOOLONG);
63 }
64 unix.sun_path[0] = 0;
65 for (i, b) in name.iter().enumerate() {
66 unix.sun_path[1 + i] = *b as c::c_char;
67 }
68 let len = offsetof_sun_path() + 1 + name.len();
69 let len = len.try_into().unwrap();
70 Ok(Self {
71 unix,
72 #[cfg(not(any(bsd, target_os = "haiku")))]
73 len,
74 })
75 }
76
init() -> c::sockaddr_un77 fn init() -> c::sockaddr_un {
78 c::sockaddr_un {
79 #[cfg(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto"))]
80 sun_len: 0,
81 #[cfg(target_os = "vita")]
82 ss_len: 0,
83 sun_family: c::AF_UNIX as _,
84 #[cfg(any(bsd, target_os = "nto"))]
85 sun_path: [0; 104],
86 #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto")))]
87 sun_path: [0; 108],
88 #[cfg(target_os = "haiku")]
89 sun_path: [0; 126],
90 #[cfg(target_os = "aix")]
91 sun_path: [0; 1023],
92 }
93 }
94
95 /// For a filesystem path address, return the path.
96 #[inline]
path(&self) -> Option<&CStr>97 pub fn path(&self) -> Option<&CStr> {
98 let len = self.len();
99 if len != 0 && self.unix.sun_path[0] != 0 {
100 let end = len as usize - offsetof_sun_path();
101 let bytes = &self.unix.sun_path[..end];
102 // SAFETY: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`.
103 // And `from_bytes_with_nul_unchecked` since the string is
104 // NUL-terminated.
105 unsafe {
106 Some(CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(
107 bytes.as_ptr().cast(),
108 bytes.len(),
109 )))
110 }
111 } else {
112 None
113 }
114 }
115
116 /// For an abstract address, return the identifier.
117 #[cfg(linux_kernel)]
118 #[inline]
abstract_name(&self) -> Option<&[u8]>119 pub fn abstract_name(&self) -> Option<&[u8]> {
120 let len = self.len();
121 if len != 0 && self.unix.sun_path[0] == 0 {
122 let end = len as usize - offsetof_sun_path();
123 let bytes = &self.unix.sun_path[1..end];
124 // SAFETY: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`.
125 unsafe { Some(slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len())) }
126 } else {
127 None
128 }
129 }
130
131 #[inline]
addr_len(&self) -> c::socklen_t132 pub(crate) fn addr_len(&self) -> c::socklen_t {
133 #[cfg(not(any(bsd, target_os = "haiku")))]
134 {
135 self.len
136 }
137 #[cfg(any(bsd, target_os = "haiku"))]
138 {
139 c::socklen_t::from(self.unix.sun_len)
140 }
141 }
142
143 #[inline]
len(&self) -> usize144 pub(crate) fn len(&self) -> usize {
145 self.addr_len() as usize
146 }
147 }
148
149 #[cfg(unix)]
150 impl PartialEq for SocketAddrUnix {
151 #[inline]
eq(&self, other: &Self) -> bool152 fn eq(&self, other: &Self) -> bool {
153 let self_len = self.len() - offsetof_sun_path();
154 let other_len = other.len() - offsetof_sun_path();
155 self.unix.sun_path[..self_len].eq(&other.unix.sun_path[..other_len])
156 }
157 }
158
159 #[cfg(unix)]
160 impl Eq for SocketAddrUnix {}
161
162 #[cfg(unix)]
163 impl PartialOrd for SocketAddrUnix {
164 #[inline]
partial_cmp(&self, other: &Self) -> Option<Ordering>165 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
166 Some(self.cmp(other))
167 }
168 }
169
170 #[cfg(unix)]
171 impl Ord for SocketAddrUnix {
172 #[inline]
cmp(&self, other: &Self) -> Ordering173 fn cmp(&self, other: &Self) -> Ordering {
174 let self_len = self.len() - offsetof_sun_path();
175 let other_len = other.len() - offsetof_sun_path();
176 self.unix.sun_path[..self_len].cmp(&other.unix.sun_path[..other_len])
177 }
178 }
179
180 #[cfg(unix)]
181 impl Hash for SocketAddrUnix {
182 #[inline]
hash<H: Hasher>(&self, state: &mut H)183 fn hash<H: Hasher>(&self, state: &mut H) {
184 let self_len = self.len() - offsetof_sun_path();
185 self.unix.sun_path[..self_len].hash(state)
186 }
187 }
188
189 #[cfg(unix)]
190 impl fmt::Debug for SocketAddrUnix {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result191 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
192 if let Some(path) = self.path() {
193 path.fmt(fmt)
194 } else {
195 #[cfg(linux_kernel)]
196 if let Some(name) = self.abstract_name() {
197 return name.fmt(fmt);
198 }
199
200 "(unnamed)".fmt(fmt)
201 }
202 }
203 }
204
205 /// `struct sockaddr_storage` as a raw struct.
206 pub type SocketAddrStorage = c::sockaddr_storage;
207
208 /// Return the offset of the `sun_path` field of `sockaddr_un`.
209 #[cfg(not(windows))]
210 #[inline]
offsetof_sun_path() -> usize211 pub(crate) fn offsetof_sun_path() -> usize {
212 let z = c::sockaddr_un {
213 #[cfg(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto"))]
214 sun_len: 0_u8,
215 #[cfg(target_os = "vita")]
216 ss_len: 0,
217 #[cfg(any(
218 bsd,
219 target_os = "aix",
220 target_os = "espidf",
221 target_os = "haiku",
222 target_os = "nto",
223 target_os = "vita"
224 ))]
225 sun_family: 0_u8,
226 #[cfg(not(any(
227 bsd,
228 target_os = "aix",
229 target_os = "espidf",
230 target_os = "haiku",
231 target_os = "nto",
232 target_os = "vita"
233 )))]
234 sun_family: 0_u16,
235 #[cfg(any(bsd, target_os = "nto"))]
236 sun_path: [0; 104],
237 #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto")))]
238 sun_path: [0; 108],
239 #[cfg(target_os = "haiku")]
240 sun_path: [0; 126],
241 #[cfg(target_os = "aix")]
242 sun_path: [0; 1023],
243 };
244 (crate::utils::as_ptr(&z.sun_path) as usize) - (crate::utils::as_ptr(&z) as usize)
245 }
246