1use std::{
4 marker, mem, net, num,
5 os::fd::{AsRawFd as _, BorrowedFd},
6 ptr,
7};
8
9use crate::{Errno, io::socket::Domain, kernel};
10
11mod internet;
12pub use internet::Internet;
13
14pub const CAPACITY: usize = mem::size_of::<libc::sockaddr_storage>();
16
17pub const FAMILY_BYTES: usize =
19 mem::offset_of!(libc::sockaddr_storage, ss_family) + mem::size_of::<libc::sa_family_t>();
20
21#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
23#[repr(transparent)]
24pub struct Socklen(num::NonZero<libc::socklen_t>);
25
26impl Socklen {
27 const fn of<T>() -> Self {
29 const {
30 assert!(
31 mem::size_of::<T>() > 0 && mem::size_of::<T>() <= CAPACITY,
32 "address payload does not fit sockaddr_storage",
33 );
34 }
35 Self(
36 num::NonZero::<libc::socklen_t>::MIN
37 .saturating_add(mem::size_of::<T>() as libc::socklen_t - 1),
38 )
39 }
40
41 fn try_from_len(len: usize) -> Option<Self> {
43 if len > CAPACITY {
44 return None;
45 }
46 num::NonZero::new(len as libc::socklen_t).map(Self)
47 }
48
49 pub const fn get(self) -> usize {
50 self.0.get() as usize
51 }
52
53 pub(crate) const fn raw(self) -> libc::socklen_t {
54 self.0.get()
55 }
56}
57
58pub trait Source {
60 const UNIX_TERMINATED: bool;
62 const UNIX_ABSTRACT: bool;
64
65 fn header(domain: Domain, len: Socklen) -> [u8; 2];
66}
67
68#[derive(Clone, Copy)]
70pub struct Unix {
71 raw: libc::sockaddr_un,
72 len: Socklen,
73}
74
75enum Name {
76 Path,
77 Abstract,
78}
79
80impl Unix {
81 pub fn from_path<S: Source>(bytes: &[u8]) -> Result<Self, PathError> {
83 Self::encode::<S>(bytes, Name::Path)
84 }
85
86 pub fn from_name<S: Source>(bytes: &[u8]) -> Result<Self, PathError> {
88 Self::encode::<S>(bytes, Name::Abstract)
89 }
90
91 fn encode<S: Source>(bytes: &[u8], name: Name) -> Result<Self, PathError> {
92 let mut raw: libc::sockaddr_un = unsafe { mem::zeroed() };
94 let capacity = raw.sun_path.len();
95 let (prefix, suffix) = match name {
96 Name::Path => {
97 PathError::check(bytes, capacity - usize::from(S::UNIX_TERMINATED))?;
98 (0, usize::from(bytes.len() < capacity))
99 }
100 Name::Abstract => {
101 if !S::UNIX_ABSTRACT {
102 return Err(PathError::Unsupported);
103 }
104 PathError::length(bytes.len(), capacity - 1)?;
105 (1, 0)
106 }
107 };
108 for (dst, byte) in raw.sun_path.iter_mut().skip(prefix).zip(bytes) {
109 *dst = *byte as libc::c_char;
110 }
111 let len = num::NonZero::<libc::socklen_t>::MIN.saturating_add(
112 (mem::offset_of!(libc::sockaddr_un, sun_path) + prefix + bytes.len() + suffix - 1)
113 as libc::socklen_t,
114 );
115 let len = Socklen(len);
116 unsafe {
118 ptr::from_mut(&mut raw)
119 .cast::<[u8; 2]>()
120 .write(S::header(Domain::Unix, len))
121 };
122 Ok(Self { raw, len })
123 }
124
125 #[must_use]
127 pub fn as_addr(&self) -> Addr<'_> {
128 Addr::new(&self.raw, self.len)
129 }
130}
131
132#[derive(Clone, Copy, Debug)]
134#[repr(transparent)]
135pub struct Length(libc::socklen_t);
136
137#[derive(Clone, Copy)]
139#[repr(C)]
140pub struct Storage<L = Length> {
141 storage: libc::sockaddr_storage,
142 len: L,
143}
144
145impl Storage<Length> {
146 #[must_use]
147 pub fn empty() -> Self {
148 Self {
149 storage: unsafe { mem::zeroed() },
150 len: Length(CAPACITY as libc::socklen_t),
151 }
152 }
153
154 pub fn output_mut(&mut self) -> (&mut libc::sockaddr_storage, &mut libc::socklen_t) {
156 (&mut self.storage, &mut self.len.0)
157 }
158}
159
160impl Storage<Socklen> {
161 #[must_use]
162 pub fn as_addr(&self) -> Addr<'_> {
163 Addr::new(&self.storage, self.len)
164 }
165
166 #[must_use]
168 pub fn from_addr(source: Addr<'_>) -> Self {
169 let (addr, len) = source.parts();
170 let mut out = Self {
171 storage: unsafe { mem::zeroed() },
172 len,
173 };
174 unsafe {
177 ptr::copy_nonoverlapping(
178 addr.cast::<u8>(),
179 ptr::from_mut(&mut out.storage).cast(),
180 len.get(),
181 )
182 };
183 out
184 }
185}
186
187impl<L> Storage<L> {
188 fn decode(&self, actual: usize) -> Result<net::SocketAddr, Error> {
189 unsafe { Internet::decode(ptr::from_ref(&self.storage).cast(), actual) }
192 }
193}
194
195const _: () = {
196 assert!(CAPACITY <= libc::socklen_t::MAX as usize);
197 let fields = CAPACITY + mem::size_of::<libc::socklen_t>();
198 let align = mem::align_of::<Storage<Socklen>>();
199 assert!(mem::size_of::<Storage<Socklen>>() == fields.div_ceil(align) * align);
200};
201
202#[derive(Clone, Copy, Debug, Eq, PartialEq)]
204pub enum Error {
205 Storage {
206 actual: usize,
207 capacity: usize,
208 },
209 Header {
210 actual: usize,
211 required: usize,
212 },
213 Address {
214 family: i32,
215 actual: usize,
216 required: usize,
217 },
218 Unsupported {
219 family: i32,
220 actual: usize,
221 },
222}
223
224impl Storage<Socklen> {
225 pub fn to_std(&self) -> Result<net::SocketAddr, Error> {
226 self.decode(self.len.get())
227 }
228}
229
230impl Storage<Length> {
231 pub fn to_std(&self) -> Result<net::SocketAddr, Error> {
232 let actual = self.len.0 as usize;
233 if actual > CAPACITY {
234 return Err(Error::Storage {
235 actual,
236 capacity: CAPACITY,
237 });
238 }
239 self.decode(actual)
240 }
241}
242
243#[derive(Clone, Copy, Debug, Eq, PartialEq)]
245pub enum PathError {
246 Unsupported,
247 Empty,
248 Length { actual: usize, maximum: usize },
249 Nul { offset: usize },
250}
251
252impl PathError {
253 fn check(bytes: &[u8], maximum: usize) -> Result<(), Self> {
254 if bytes.is_empty() {
255 return Err(Self::Empty);
256 }
257 Self::length(bytes.len(), maximum)?;
258 if let Some(offset) = bytes.iter().position(|byte| *byte == 0) {
259 return Err(Self::Nul { offset });
260 }
261 Ok(())
262 }
263
264 fn length(actual: usize, maximum: usize) -> Result<(), Self> {
265 if actual > maximum {
266 return Err(Self::Length { actual, maximum });
267 }
268 Ok(())
269 }
270}
271
272#[derive(Clone, Copy)]
274#[repr(C)]
275pub struct Addr<'a> {
276 addr: ptr::NonNull<libc::sockaddr>,
277 len: Socklen,
278 owner: marker::PhantomData<&'a libc::sockaddr>,
279}
280
281#[derive(Clone, Copy, Debug, Eq, PartialEq)]
283pub enum Local<E> {
284 Syscall(E),
285 Length { actual: usize, capacity: usize },
286}
287
288impl<'a> Addr<'a> {
289 fn new<T>(storage: &'a T, len: Socklen) -> Self {
290 Self {
291 addr: ptr::NonNull::from(storage).cast(),
292 len,
293 owner: marker::PhantomData,
294 }
295 }
296
297 pub const fn parts(self) -> (*const libc::sockaddr, Socklen) {
298 (self.addr.as_ptr().cast_const(), self.len)
299 }
300
301 pub fn local<S: kernel::raw::Source + ?Sized, E: From<Errno>>(
302 file: BorrowedFd<'_>,
303 storage: &'a mut Storage<Length>,
304 ) -> Result<Self, Local<E>> {
305 let (address, length) = storage.output_mut();
306 *length = CAPACITY as libc::socklen_t;
307 let status =
310 unsafe { libc::getsockname(file.as_raw_fd(), ptr::from_mut(address).cast(), length) };
311 unsafe { kernel::raw::Status::new(status).try_zero::<S, E>() }.map_err(Local::Syscall)?;
313 let actual = *length as usize;
314 let len = Socklen::try_from_len(actual).ok_or(Local::Length {
315 actual,
316 capacity: CAPACITY,
317 })?;
318 Ok(Self::new(&storage.storage, len))
319 }
320
321 pub fn try_bind<S: kernel::raw::Source + ?Sized, E: From<Errno>>(
322 self,
323 file: BorrowedFd<'_>,
324 ) -> Result<(), E> {
325 let status = unsafe { libc::bind(file.as_raw_fd(), self.addr.as_ptr(), self.len.raw()) };
327 unsafe { kernel::raw::Status::new(status).try_zero::<S, E>() }
329 }
330
331 pub fn try_connect<S: kernel::raw::Source + ?Sized, E: From<Errno>>(
332 self,
333 file: BorrowedFd<'_>,
334 ) -> Result<(), E> {
335 let status = unsafe { libc::connect(file.as_raw_fd(), self.addr.as_ptr(), self.len.raw()) };
337 unsafe { kernel::raw::Status::new(status).try_zero::<S, E>() }
339 }
340}