]>
Commit | Line | Data |
---|---|---|
fe692bf9 | 1 | //! Socket address utilities. |
064997fb | 2 | |
fe692bf9 | 3 | use crate::backend::c; |
064997fb | 4 | #[cfg(unix)] |
fe692bf9 FG |
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 | }; | |
064997fb FG |
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, | |
353b0b11 | 21 | #[cfg(not(any(bsd, target_os = "haiku")))] |
064997fb FG |
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] | |
29 | pub fn new<P: path::Arg>(path: P) -> io::Result<Self> { | |
30 | path.into_with_c_str(Self::_new) | |
31 | } | |
32 | ||
33 | #[inline] | |
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 | ||
353b0b11 | 44 | #[cfg(any(bsd, target_os = "haiku"))] |
064997fb FG |
45 | { |
46 | unix.sun_len = (offsetof_sun_path() + bytes.len()).try_into().unwrap(); | |
47 | } | |
48 | ||
49 | Ok(Self { | |
50 | unix, | |
353b0b11 | 51 | #[cfg(not(any(bsd, target_os = "haiku")))] |
064997fb FG |
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. | |
fe692bf9 | 57 | #[cfg(linux_kernel)] |
064997fb FG |
58 | #[inline] |
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 | } | |
fe692bf9 | 64 | unix.sun_path[0] = 0; |
064997fb FG |
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, | |
353b0b11 | 72 | #[cfg(not(any(bsd, target_os = "haiku")))] |
064997fb FG |
73 | len, |
74 | }) | |
75 | } | |
76 | ||
77 | fn init() -> c::sockaddr_un { | |
78 | c::sockaddr_un { | |
781aab86 | 79 | #[cfg(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto"))] |
064997fb | 80 | sun_len: 0, |
ed00b5ec FG |
81 | #[cfg(target_os = "vita")] |
82 | ss_len: 0, | |
064997fb | 83 | sun_family: c::AF_UNIX as _, |
add651ee | 84 | #[cfg(any(bsd, target_os = "nto"))] |
064997fb | 85 | sun_path: [0; 104], |
781aab86 | 86 | #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto")))] |
064997fb | 87 | sun_path: [0; 108], |
487cf647 FG |
88 | #[cfg(target_os = "haiku")] |
89 | sun_path: [0; 126], | |
781aab86 FG |
90 | #[cfg(target_os = "aix")] |
91 | sun_path: [0; 1023], | |
064997fb FG |
92 | } |
93 | } | |
94 | ||
95 | /// For a filesystem path address, return the path. | |
96 | #[inline] | |
97 | pub fn path(&self) -> Option<&CStr> { | |
98 | let len = self.len(); | |
fe692bf9 | 99 | if len != 0 && self.unix.sun_path[0] != 0 { |
064997fb FG |
100 | let end = len as usize - offsetof_sun_path(); |
101 | let bytes = &self.unix.sun_path[..end]; | |
fe692bf9 FG |
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. | |
064997fb FG |
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. | |
fe692bf9 | 117 | #[cfg(linux_kernel)] |
064997fb FG |
118 | #[inline] |
119 | pub fn abstract_name(&self) -> Option<&[u8]> { | |
120 | let len = self.len(); | |
fe692bf9 | 121 | if len != 0 && self.unix.sun_path[0] == 0 { |
064997fb FG |
122 | let end = len as usize - offsetof_sun_path(); |
123 | let bytes = &self.unix.sun_path[1..end]; | |
353b0b11 | 124 | // SAFETY: `from_raw_parts` to convert from `&[c_char]` to `&[u8]`. |
064997fb FG |
125 | unsafe { Some(slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len())) } |
126 | } else { | |
127 | None | |
128 | } | |
129 | } | |
130 | ||
131 | #[inline] | |
132 | pub(crate) fn addr_len(&self) -> c::socklen_t { | |
353b0b11 | 133 | #[cfg(not(any(bsd, target_os = "haiku")))] |
064997fb FG |
134 | { |
135 | self.len | |
136 | } | |
353b0b11 | 137 | #[cfg(any(bsd, target_os = "haiku"))] |
064997fb FG |
138 | { |
139 | c::socklen_t::from(self.unix.sun_len) | |
140 | } | |
141 | } | |
142 | ||
143 | #[inline] | |
144 | 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] | |
152 | 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] | |
fe692bf9 | 165 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
781aab86 | 166 | Some(self.cmp(other)) |
064997fb FG |
167 | } |
168 | } | |
169 | ||
170 | #[cfg(unix)] | |
171 | impl Ord for SocketAddrUnix { | |
172 | #[inline] | |
fe692bf9 | 173 | fn cmp(&self, other: &Self) -> Ordering { |
064997fb FG |
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)] | |
fe692bf9 | 181 | impl Hash for SocketAddrUnix { |
064997fb | 182 | #[inline] |
fe692bf9 | 183 | fn hash<H: Hasher>(&self, state: &mut H) { |
064997fb FG |
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 { | |
191 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
192 | if let Some(path) = self.path() { | |
193 | path.fmt(fmt) | |
194 | } else { | |
fe692bf9 | 195 | #[cfg(linux_kernel)] |
064997fb FG |
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] | |
211 | pub(crate) fn offsetof_sun_path() -> usize { | |
212 | let z = c::sockaddr_un { | |
781aab86 | 213 | #[cfg(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto"))] |
064997fb | 214 | sun_len: 0_u8, |
ed00b5ec FG |
215 | #[cfg(target_os = "vita")] |
216 | ss_len: 0, | |
781aab86 FG |
217 | #[cfg(any( |
218 | bsd, | |
219 | target_os = "aix", | |
220 | target_os = "espidf", | |
221 | target_os = "haiku", | |
ed00b5ec FG |
222 | target_os = "nto", |
223 | target_os = "vita" | |
781aab86 | 224 | ))] |
064997fb | 225 | sun_family: 0_u8, |
781aab86 FG |
226 | #[cfg(not(any( |
227 | bsd, | |
228 | target_os = "aix", | |
229 | target_os = "espidf", | |
230 | target_os = "haiku", | |
ed00b5ec FG |
231 | target_os = "nto", |
232 | target_os = "vita" | |
781aab86 | 233 | )))] |
064997fb | 234 | sun_family: 0_u16, |
add651ee | 235 | #[cfg(any(bsd, target_os = "nto"))] |
064997fb | 236 | sun_path: [0; 104], |
781aab86 | 237 | #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "nto")))] |
064997fb | 238 | sun_path: [0; 108], |
487cf647 FG |
239 | #[cfg(target_os = "haiku")] |
240 | sun_path: [0; 126], | |
781aab86 FG |
241 | #[cfg(target_os = "aix")] |
242 | sun_path: [0; 1023], | |
064997fb FG |
243 | }; |
244 | (crate::utils::as_ptr(&z.sun_path) as usize) - (crate::utils::as_ptr(&z) as usize) | |
245 | } |