1use std::borrow::Borrow;
2use std::borrow::BorrowMut;
3use std::ffi::CStr;
4use std::mem::MaybeUninit;
5
6use linux_api::socket::AddressFamily;
7use nix::sys::socket::SockaddrLike;
8use static_assertions::{assert_eq_align, assert_eq_size};
9
10#[derive(Clone, Copy)]
12pub struct SockaddrStorage {
13 addr: Addr,
14 len: libc::socklen_t,
15}
16
17#[derive(Clone, Copy)]
18#[repr(C)]
19union Addr {
20 slice: [MaybeUninit<u8>; std::mem::size_of::<libc::sockaddr_storage>()],
21 storage: libc::sockaddr_storage,
22 inet: libc::sockaddr_in,
23 inet6: libc::sockaddr_in6,
24 unix: libc::sockaddr_un,
25 netlink: libc::sockaddr_nl,
26}
27
28assert_eq_size!(libc::sockaddr_storage, Addr);
30
31impl SockaddrStorage {
38 pub unsafe fn from_ptr(
48 addr: *const MaybeUninit<u8>,
49 len: libc::socklen_t,
50 ) -> Option<SockaddrStorage> {
51 if addr.is_null() {
52 return None;
53 }
54
55 const STORAGE_LEN: usize = std::mem::size_of::<libc::sockaddr_storage>();
56
57 if (len as usize) > STORAGE_LEN {
58 return None;
59 }
60
61 let mut new_addr = [MaybeUninit::new(0u8); STORAGE_LEN];
63
64 unsafe { std::ptr::copy_nonoverlapping(addr, new_addr.as_mut_ptr(), len as usize) };
66
67 Some(SockaddrStorage {
68 addr: Addr { slice: new_addr },
69 len,
70 })
71 }
72
73 pub unsafe fn from_bytes(address: &[MaybeUninit<u8>]) -> Option<Self> {
77 unsafe { Self::from_ptr(address.as_ptr(), address.len().try_into().ok()?) }
78 }
79
80 pub fn family(&self) -> Option<AddressFamily> {
83 if (self.len as usize) < memoffset::span_of!(libc::sockaddr_storage, ss_family).end {
84 return None;
85 }
86
87 Some(AddressFamily::from(unsafe { self.addr.storage }.ss_family))
90 }
91
92 pub fn as_inet(&self) -> Option<&nix::sys::socket::SockaddrIn> {
95 if (self.len as usize) < std::mem::size_of::<libc::sockaddr_in>() {
96 return None;
97 }
98 if self.family() != Some(AddressFamily::AF_INET) {
99 return None;
100 }
101
102 assert_eq_size!(libc::sockaddr_in, nix::sys::socket::SockaddrIn);
105 assert_eq_align!(libc::sockaddr_in, nix::sys::socket::SockaddrIn);
106
107 Some(unsafe {
108 &*(std::ptr::from_ref(&self.addr.inet) as *const nix::sys::socket::SockaddrIn)
109 })
110 }
111
112 pub fn from_inet(addr: &nix::sys::socket::SockaddrIn) -> Self {
114 assert_eq_size!(libc::sockaddr_in, nix::sys::socket::SockaddrIn);
117 assert_eq_align!(libc::sockaddr_in, nix::sys::socket::SockaddrIn);
118
119 unsafe { Self::from_ptr(addr.as_ptr() as *const MaybeUninit<u8>, addr.len()) }.unwrap()
120 }
121
122 pub fn as_inet6(&self) -> Option<&nix::sys::socket::SockaddrIn6> {
125 if (self.len as usize) < std::mem::size_of::<libc::sockaddr_in6>() {
126 return None;
127 }
128 if self.family() != Some(AddressFamily::AF_INET6) {
129 return None;
130 }
131
132 assert_eq_size!(libc::sockaddr_in6, nix::sys::socket::SockaddrIn6);
135 assert_eq_align!(libc::sockaddr_in6, nix::sys::socket::SockaddrIn6);
136
137 Some(unsafe {
138 &*(std::ptr::from_ref(&self.addr.inet6) as *const nix::sys::socket::SockaddrIn6)
139 })
140 }
141
142 pub fn from_inet6(addr: &nix::sys::socket::SockaddrIn6) -> Self {
144 assert_eq_size!(libc::sockaddr_in6, nix::sys::socket::SockaddrIn6);
147 assert_eq_align!(libc::sockaddr_in6, nix::sys::socket::SockaddrIn6);
148
149 unsafe { Self::from_ptr(addr.as_ptr() as *const MaybeUninit<u8>, addr.len()) }.unwrap()
150 }
151
152 pub fn as_unix(&self) -> Option<SockaddrUnix<&libc::sockaddr_un>> {
155 if self.family() != Some(AddressFamily::AF_UNIX) {
156 return None;
157 }
158
159 SockaddrUnix::new(unsafe { &self.addr.unix }, self.len)
160 }
161
162 pub fn from_unix(addr: &SockaddrUnix<&libc::sockaddr_un>) -> Self {
164 let (ptr, len) = addr.as_ptr();
165
166 unsafe { Self::from_ptr(ptr as *const MaybeUninit<u8>, len) }.unwrap()
167 }
168
169 pub fn as_netlink(&self) -> Option<&nix::sys::socket::NetlinkAddr> {
172 if (self.len as usize) < std::mem::size_of::<libc::sockaddr_nl>() {
173 return None;
174 }
175 if self.family() != Some(AddressFamily::AF_NETLINK) {
176 return None;
177 }
178
179 assert_eq_size!(libc::sockaddr_nl, nix::sys::socket::NetlinkAddr);
182 assert_eq_align!(libc::sockaddr_nl, nix::sys::socket::NetlinkAddr);
183
184 Some(unsafe { &*(&self.addr.netlink as *const _ as *const nix::sys::socket::NetlinkAddr) })
185 }
186
187 pub fn from_netlink(addr: &nix::sys::socket::NetlinkAddr) -> Self {
189 assert_eq_size!(libc::sockaddr_nl, nix::sys::socket::NetlinkAddr);
192 assert_eq_align!(libc::sockaddr_nl, nix::sys::socket::NetlinkAddr);
193
194 unsafe { Self::from_ptr(addr.as_ptr() as *const MaybeUninit<u8>, addr.len()) }.unwrap()
195 }
196
197 pub fn as_ptr(&self) -> (*const MaybeUninit<u8>, libc::socklen_t) {
199 (unsafe { &self.addr.slice }.as_ptr(), self.len)
200 }
201
202 pub fn as_slice(&self) -> &[MaybeUninit<u8>] {
204 unsafe { &self.addr.slice[..(self.len as usize)] }
205 }
206}
207
208impl std::fmt::Debug for SockaddrStorage {
209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210 let as_inet = self.as_inet();
211 let as_inet6 = self.as_inet6();
212 let as_unix = self.as_unix();
213 let as_netlink = self.as_netlink();
214
215 let as_inet = as_inet.map(|x| x as &dyn std::fmt::Debug);
216 let as_inet6 = as_inet6.map(|x| x as &dyn std::fmt::Debug);
217 let as_unix = as_unix.as_ref().map(|x| x as &dyn std::fmt::Debug);
218 let as_netlink = as_netlink.as_ref().map(|x| x as &dyn std::fmt::Debug);
219
220 let options = [as_inet, as_inet6, as_unix, as_netlink];
222 let addr = options.into_iter().find_map(std::convert::identity);
223
224 if let Some(ref addr) = addr {
225 f.debug_struct("SockaddrStorage")
226 .field("len", &self.len)
227 .field("addr", addr)
228 .finish()
229 } else {
230 f.debug_struct("SockaddrStorage")
231 .field("len", &self.len)
232 .field("family", &self.family())
233 .finish_non_exhaustive()
234 }
235 }
236}
237
238impl std::fmt::Display for SockaddrStorage {
239 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240 let as_inet = self.as_inet();
241 let as_inet6 = self.as_inet6();
242 let as_unix = self.as_unix();
243 let as_netlink = self.as_netlink();
244
245 let as_inet = as_inet.map(|x| x as &dyn std::fmt::Display);
246 let as_inet6 = as_inet6.map(|x| x as &dyn std::fmt::Display);
247 let as_unix = as_unix.as_ref().map(|x| x as &dyn std::fmt::Display);
248 let as_netlink = as_netlink.as_ref().map(|x| x as &dyn std::fmt::Display);
249
250 let options = [as_inet, as_inet6, as_unix, as_netlink];
252 let addr = options.into_iter().find_map(std::convert::identity);
253
254 if let Some(ref addr) = addr {
255 write!(f, "{addr}")
256 } else {
257 f.debug_struct("SockaddrStorage")
258 .field("len", &self.len)
259 .field("family", &self.family())
260 .finish_non_exhaustive()
261 }
262 }
263}
264
265impl<T> From<SockaddrUnix<T>> for SockaddrStorage
266where
267 T: Borrow<libc::sockaddr_un>,
268{
269 fn from(addr: SockaddrUnix<T>) -> Self {
270 SockaddrStorage::from_unix(&addr.as_ref())
271 }
272}
273
274impl From<nix::sys::socket::SockaddrIn> for SockaddrStorage {
275 fn from(addr: nix::sys::socket::SockaddrIn) -> Self {
276 SockaddrStorage::from_inet(&addr)
277 }
278}
279
280impl From<nix::sys::socket::SockaddrIn6> for SockaddrStorage {
281 fn from(addr: nix::sys::socket::SockaddrIn6) -> Self {
282 SockaddrStorage::from_inet6(&addr)
283 }
284}
285
286impl From<std::net::SocketAddrV4> for SockaddrStorage {
287 fn from(addr: std::net::SocketAddrV4) -> Self {
288 nix::sys::socket::SockaddrIn::from(addr).into()
289 }
290}
291
292impl From<std::net::SocketAddrV6> for SockaddrStorage {
293 fn from(addr: std::net::SocketAddrV6) -> Self {
294 nix::sys::socket::SockaddrIn6::from(addr).into()
295 }
296}
297
298impl From<nix::sys::socket::NetlinkAddr> for SockaddrStorage {
299 fn from(addr: nix::sys::socket::NetlinkAddr) -> Self {
300 SockaddrStorage::from_netlink(&addr)
301 }
302}
303
304#[derive(Clone, Copy)]
310pub struct SockaddrUnix<T>
311where
312 T: Borrow<libc::sockaddr_un>,
313{
314 addr: T,
315 len: libc::socklen_t,
316}
317
318impl<T> SockaddrUnix<T>
319where
320 T: Borrow<libc::sockaddr_un>,
321{
322 pub fn new(addr: T, len: libc::socklen_t) -> Option<Self> {
326 if (len as usize) < memoffset::span_of!(libc::sockaddr_un, sun_family).end {
327 return None;
328 }
329
330 if (len as usize) > std::mem::size_of::<libc::sockaddr_un>() {
331 return None;
332 }
333
334 if addr.borrow().sun_family as i32 != libc::AF_UNIX {
335 return None;
336 }
337
338 Some(Self { addr, len })
339 }
340
341 pub fn as_path(&self) -> Option<&CStr> {
344 let path = self.sun_path()?;
345
346 if path.is_empty() || path[0] == 0 {
348 return None;
349 }
350
351 CStr::from_bytes_until_nul(path).ok()
354 }
355
356 pub fn as_abstract(&self) -> Option<&[u8]> {
360 let name = self.sun_path()?;
361
362 if name.is_empty() {
363 return None;
364 }
365
366 if name[0] != 0 {
368 return None;
369 }
370
371 Some(&name[1..])
372 }
373
374 pub fn is_unnamed(&self) -> bool {
377 (self.len as usize) == memoffset::span_of!(libc::sockaddr_un, sun_family).end
378 }
379
380 fn sun_path(&self) -> Option<&[u8]> {
383 let path_offset = memoffset::offset_of!(libc::sockaddr_un, sun_path);
384 let path_len = (self.len as usize).checked_sub(path_offset)?;
385
386 Some(i8_to_u8_slice(&self.addr.borrow().sun_path[..path_len]))
387 }
388
389 pub fn into_owned(self) -> SockaddrUnix<libc::sockaddr_un> {
391 SockaddrUnix {
392 addr: *self.addr.borrow(),
393 len: self.len,
394 }
395 }
396
397 pub fn as_ref(&self) -> SockaddrUnix<&libc::sockaddr_un> {
399 SockaddrUnix {
400 addr: self.addr.borrow(),
401 len: self.len,
402 }
403 }
404
405 pub fn as_ptr(&self) -> (*const libc::sockaddr_un, libc::socklen_t) {
408 (self.addr.borrow(), self.len)
409 }
410}
411
412impl<T> SockaddrUnix<T>
413where
414 T: BorrowMut<libc::sockaddr_un>,
415{
416 pub fn as_mut(&mut self) -> SockaddrUnix<&mut libc::sockaddr_un> {
418 SockaddrUnix {
419 addr: self.addr.borrow_mut(),
420 len: self.len,
421 }
422 }
423}
424
425impl SockaddrUnix<libc::sockaddr_un> {
426 pub fn new_path(path: &CStr) -> Option<Self> {
429 let path = path.to_bytes();
430
431 debug_assert!(!path.contains(&0));
433
434 if path.is_empty() {
435 return None;
437 }
438
439 let mut addr: libc::sockaddr_un = unsafe { std::mem::zeroed() };
440
441 if path.len() >= std::mem::size_of_val(&addr.sun_path) {
442 return None;
444 }
445
446 addr.sun_family = libc::AF_UNIX as u16;
449 addr.sun_path[..path.len()].copy_from_slice(u8_to_i8_slice(path));
450
451 let len = memoffset::offset_of!(libc::sockaddr_un, sun_path) + path.len() + 1;
452 let len = len as libc::socklen_t;
453
454 Some(Self { addr, len })
455 }
456
457 pub fn new_abstract(name: &[u8]) -> Option<Self> {
460 let mut addr: libc::sockaddr_un = unsafe { std::mem::zeroed() };
461
462 if name.len() + 1 > std::mem::size_of_val(&addr.sun_path) {
463 return None;
464 }
465
466 addr.sun_family = libc::AF_UNIX as u16;
467 addr.sun_path[1..][..name.len()].copy_from_slice(u8_to_i8_slice(name));
468
469 let len = memoffset::offset_of!(libc::sockaddr_un, sun_path) + 1 + name.len();
470 let len = len as libc::socklen_t;
471
472 Some(Self { addr, len })
473 }
474
475 pub fn new_unnamed() -> SockaddrUnix<libc::sockaddr_un> {
477 let mut addr: libc::sockaddr_un = unsafe { std::mem::zeroed() };
478 addr.sun_family = libc::AF_UNIX as u16;
479
480 let len = memoffset::span_of!(libc::sockaddr_un, sun_family).end;
481 assert_eq!(len, 2);
482 let len = len as libc::socklen_t;
483
484 Self { addr, len }
485 }
486}
487
488impl<T> std::fmt::Debug for SockaddrUnix<T>
489where
490 T: Borrow<libc::sockaddr_un>,
491{
492 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
493 f.debug_struct("SockaddrUnix")
494 .field("sun_family", &self.addr.borrow().sun_family)
495 .field("sun_path", &self.sun_path())
496 .finish()
497 }
498}
499
500impl<T> std::fmt::Display for SockaddrUnix<T>
501where
502 T: Borrow<libc::sockaddr_un>,
503{
504 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
505 if let Some(path) = self.as_path() {
506 f.debug_struct("sockaddr_un").field("path", &path).finish()
507 } else if let Some(name) = self.as_abstract() {
508 let name: Vec<u8> = name
509 .iter()
510 .flat_map(|x| std::ascii::escape_default(*x))
511 .collect();
512 let name = String::from_utf8(name).unwrap();
513 f.debug_struct("sockaddr_un")
514 .field("abstract", &name)
515 .finish()
516 } else if self.is_unnamed() {
517 write!(f, "sockaddr_un {{ unnamed }}")
518 } else {
519 f.debug_struct("sockaddr_un")
520 .field("sun_path", &self.sun_path())
521 .finish()
522 }
523 }
524}
525
526impl<T> PartialEq for SockaddrUnix<T>
527where
528 T: Borrow<libc::sockaddr_un>,
529{
530 fn eq(&self, other: &Self) -> bool {
531 assert_eq!(
533 self.addr.borrow().sun_family,
534 other.addr.borrow().sun_family,
535 );
536 self.len == other.len && self.sun_path() == other.sun_path()
537 }
538}
539
540impl<T> Eq for SockaddrUnix<T> where T: Borrow<libc::sockaddr_un> {}
541
542fn u8_to_i8_slice(s: &[u8]) -> &[i8] {
544 unsafe { std::slice::from_raw_parts(s.as_ptr() as *const i8, s.len()) }
545}
546
547fn i8_to_u8_slice(s: &[i8]) -> &[u8] {
549 unsafe { std::slice::from_raw_parts(s.as_ptr() as *const u8, s.len()) }
550}
551
552#[cfg(test)]
553mod tests {
554 use super::*;
555
556 use std::net::Ipv4Addr;
557
558 #[test]
560 fn storage_from_inet_ptr() {
561 let mut addr: libc::sockaddr_in = unsafe { std::mem::zeroed() };
562 addr.sin_family = libc::AF_INET as u16;
563 addr.sin_port = 9000u16.to_be();
564 addr.sin_addr = libc::in_addr {
565 s_addr: libc::INADDR_LOOPBACK.to_be(),
566 };
567
568 let ptr = std::ptr::from_ref(&addr) as *const MaybeUninit<u8>;
569 let len = std::mem::size_of_val(&addr).try_into().unwrap();
570
571 let addr = unsafe { SockaddrStorage::from_ptr(ptr, len) }.unwrap();
572
573 assert_eq!(addr.family(), Some(AddressFamily::AF_INET));
574 assert!(addr.as_inet().is_some());
575 assert!(addr.as_inet6().is_none());
576 assert!(addr.as_unix().is_none());
577 assert!(addr.as_netlink().is_none());
578 }
579
580 #[test]
582 fn storage_from_unix_ptr() {
583 let mut addr: libc::sockaddr_un = unsafe { std::mem::zeroed() };
585 addr.sun_family = libc::AF_UNIX as u16;
586 addr.sun_path = [1; 108];
587 addr.sun_path[..4].copy_from_slice(&[1, 2, 3, 0]);
588
589 let ptr = std::ptr::from_ref(&addr) as *const MaybeUninit<u8>;
590 let len = std::mem::size_of_val(&addr).try_into().unwrap();
591
592 let addr = unsafe { SockaddrStorage::from_ptr(ptr, len) }.unwrap();
593
594 assert_eq!(addr.family(), Some(AddressFamily::AF_UNIX));
595 assert!(addr.as_unix().is_some());
596 assert!(addr.as_inet().is_none());
597 assert!(addr.as_inet6().is_none());
598 assert!(addr.as_netlink().is_none());
599 }
600
601 #[test]
603 fn storage_from_netlink_ptr() {
604 let mut addr: libc::sockaddr_nl = unsafe { std::mem::zeroed() };
605 addr.nl_family = libc::AF_NETLINK as u16;
606 addr.nl_pid = 0x38deb915;
608 addr.nl_groups = 0xf229a8ea;
609
610 let ptr = &addr as *const _ as *const MaybeUninit<u8>;
611 let len = std::mem::size_of_val(&addr).try_into().unwrap();
612
613 let addr = unsafe { SockaddrStorage::from_ptr(ptr, len) }.unwrap();
614
615 assert_eq!(addr.family(), Some(AddressFamily::AF_NETLINK));
616 assert!(addr.as_netlink().is_some());
617 assert!(addr.as_inet().is_none());
618 assert!(addr.as_inet6().is_none());
619 assert!(addr.as_unix().is_none());
620 }
621
622 #[test]
624 fn inet_addr_from_libc() {
625 let mut addr_in: libc::sockaddr_in = unsafe { std::mem::zeroed() };
626 addr_in.sin_family = libc::AF_INET as u16;
627 addr_in.sin_port = 9000u16.to_be();
628 addr_in.sin_addr = libc::in_addr {
629 s_addr: libc::INADDR_LOOPBACK.to_be(),
630 };
631
632 let ptr = std::ptr::from_ref(&addr_in) as *const MaybeUninit<u8>;
633 let len = std::mem::size_of_val(&addr_in).try_into().unwrap();
634
635 let addr = unsafe { SockaddrStorage::from_ptr(ptr, len) }.unwrap();
636 let addr = addr.as_inet().unwrap();
637
638 assert_eq!(addr.port(), u16::from_be(addr_in.sin_port));
639 assert_eq!(
640 addr.ip(),
641 Ipv4Addr::from(u32::from_be(addr_in.sin_addr.s_addr)),
642 );
643 }
644
645 #[test]
647 fn inet_addr_to_libc() {
648 let addr_original = nix::sys::socket::SockaddrIn::new(127, 0, 0, 1, 9000);
649 let addr = SockaddrStorage::from_inet(&addr_original);
650
651 let (ptr, len) = addr.as_ptr();
652 let ptr = ptr as *const libc::sockaddr_in;
653 assert_eq!(len as usize, std::mem::size_of::<libc::sockaddr_in>());
654
655 let addr = unsafe { ptr.as_ref() }.unwrap();
656
657 assert_eq!(addr.sin_family, libc::AF_INET as u16);
658 assert_eq!(u16::from_be(addr.sin_port), addr_original.port());
659 assert_eq!(
660 Ipv4Addr::from(u32::from_be(addr.sin_addr.s_addr)),
661 addr_original.ip(),
662 );
663 }
664
665 #[test]
667 fn netlink_addr_from_libc() {
668 let mut addr_nl: libc::sockaddr_nl = unsafe { std::mem::zeroed() };
669 addr_nl.nl_family = libc::AF_NETLINK as u16;
670 addr_nl.nl_pid = 0x38deb915;
672 addr_nl.nl_groups = 0xf229a8ea;
673
674 let ptr = &addr_nl as *const _ as *const MaybeUninit<u8>;
675 let len = std::mem::size_of_val(&addr_nl).try_into().unwrap();
676
677 let addr = unsafe { SockaddrStorage::from_ptr(ptr, len) }.unwrap();
678 let addr = addr.as_netlink().unwrap();
679
680 assert_eq!(addr.pid(), u32::from_le(addr_nl.nl_pid));
681 assert_eq!(addr.groups(), u32::from_le(addr_nl.nl_groups));
682 }
683
684 #[test]
686 fn netlink_addr_to_libc() {
687 let addr_original = nix::sys::socket::NetlinkAddr::new(0x38deb915, 0xf229a8ea);
689 let addr = SockaddrStorage::from_netlink(&addr_original);
690
691 let (ptr, len) = addr.as_ptr();
692 let ptr = ptr as *const libc::sockaddr_nl;
693 assert_eq!(len as usize, std::mem::size_of::<libc::sockaddr_nl>());
694
695 let addr = unsafe { ptr.as_ref() }.unwrap();
696
697 assert_eq!(addr.nl_family, libc::AF_NETLINK as u16);
698 assert_eq!(u32::from_le(addr.nl_pid), addr_original.pid());
699 assert_eq!(u32::from_le(addr.nl_groups), addr_original.groups());
700 }
701
702 #[test]
704 fn unix_addr_from_libc_to_path() {
705 let pathname = [1, 2, 3, 0];
706 let pathname_cstr = CStr::from_bytes_with_nul(i8_to_u8_slice(&pathname)).unwrap();
707
708 let mut addr: libc::sockaddr_un = unsafe { std::mem::zeroed() };
710 addr.sun_family = libc::AF_UNIX as u16;
711 addr.sun_path = [1; 108];
712 addr.sun_path[..pathname.len()].copy_from_slice(&pathname);
713
714 let ptr = std::ptr::from_ref(&addr) as *const MaybeUninit<u8>;
715 let len_useful_info = memoffset::offset_of!(libc::sockaddr_un, sun_path) + pathname.len();
716 let len_useful_info = len_useful_info.try_into().unwrap();
717 let len_struct = std::mem::size_of_val(&addr).try_into().unwrap();
718
719 let addr = unsafe { SockaddrStorage::from_ptr(ptr, len_useful_info) }.unwrap();
720
721 assert!(addr.as_inet().is_none());
722 assert!(addr.as_inet6().is_none());
723
724 let addr = addr.as_unix().unwrap();
725
726 assert!(addr.as_abstract().is_none());
727 assert!(!addr.is_unnamed());
728
729 assert_eq!(addr.as_path().unwrap(), pathname_cstr);
730
731 let addr = unsafe { SockaddrStorage::from_ptr(ptr, len_struct) }.unwrap();
732
733 assert!(addr.as_inet().is_none());
734 assert!(addr.as_inet6().is_none());
735
736 let addr = addr.as_unix().unwrap();
737
738 assert!(addr.as_abstract().is_none());
739 assert!(!addr.is_unnamed());
740
741 assert_eq!(addr.as_path().unwrap(), pathname_cstr);
742 }
743
744 #[test]
746 fn unix_addr_from_path_to_libc() {
747 let pathname = [1, 2, 3, 0];
748 let pathname_cstr = CStr::from_bytes_with_nul(i8_to_u8_slice(&pathname)).unwrap();
749
750 let addr = SockaddrUnix::new_path(pathname_cstr).unwrap();
751 let addr = SockaddrStorage::from_unix(&addr.as_ref());
752
753 let (ptr, len) = addr.as_ptr();
754 let ptr = ptr as *const libc::sockaddr_un;
755 assert_eq!(len as usize, 2 + pathname.len());
756
757 let addr = unsafe { ptr.as_ref() }.unwrap();
758 let path_len = len as usize - memoffset::offset_of!(libc::sockaddr_un, sun_path);
759
760 assert_eq!(addr.sun_family, libc::AF_UNIX as u16);
761 assert_eq!(addr.sun_path[..path_len], pathname);
762 }
763
764 #[test]
766 fn unix_addr_from_libc_to_abstract() {
767 let name = [1, 2, 3, 0, 5, 6];
768
769 let mut addr: libc::sockaddr_un = unsafe { std::mem::zeroed() };
771 addr.sun_family = libc::AF_UNIX as u16;
772 addr.sun_path = [1; 108];
773 addr.sun_path[0] = 0;
774 addr.sun_path[1..][..name.len()].copy_from_slice(u8_to_i8_slice(&name));
775
776 let ptr = std::ptr::from_ref(&addr) as *const MaybeUninit<u8>;
777
778 let len_real = memoffset::offset_of!(libc::sockaddr_un, sun_path) + 1 + name.len();
780 let len_real = len_real.try_into().unwrap();
781
782 let len_struct = std::mem::size_of_val(&addr).try_into().unwrap();
784
785 let addr = unsafe { SockaddrStorage::from_ptr(ptr, len_real) }.unwrap();
786
787 assert!(addr.as_inet().is_none());
788 assert!(addr.as_inet6().is_none());
789
790 let addr = addr.as_unix().unwrap();
791
792 assert!(addr.as_path().is_none());
793 assert!(!addr.is_unnamed());
794
795 assert_eq!(addr.as_abstract().unwrap(), &name);
796
797 let addr = unsafe { SockaddrStorage::from_ptr(ptr, len_struct) }.unwrap();
798
799 assert!(addr.as_inet().is_none());
800 assert!(addr.as_inet6().is_none());
801
802 let addr = addr.as_unix().unwrap();
803
804 assert!(addr.as_path().is_none());
805 assert!(!addr.is_unnamed());
806
807 assert_eq!(addr.as_abstract().unwrap().len(), 107);
808 }
809
810 #[test]
812 fn unix_addr_from_abstract_to_libc() {
813 let name = [1, 2, 3, 0, 5, 6];
814
815 let addr = SockaddrUnix::new_abstract(&name).unwrap();
816 let addr = SockaddrStorage::from_unix(&addr.as_ref());
817
818 let (ptr, len) = addr.as_ptr();
819 let ptr = ptr as *const libc::sockaddr_un;
820 assert_eq!(len as usize, 2 + 1 + name.len());
821
822 let addr = unsafe { ptr.as_ref() }.unwrap();
823 let path_len = len as usize - memoffset::offset_of!(libc::sockaddr_un, sun_path);
824
825 assert_eq!(addr.sun_family, libc::AF_UNIX as u16);
826 assert_eq!(addr.sun_path[0], 0);
827 assert_eq!(&addr.sun_path[1..path_len], u8_to_i8_slice(&name));
828 }
829
830 #[test]
832 fn unix_addr_from_libc_to_unnamed() {
833 let mut addr: libc::sockaddr_un = unsafe { std::mem::zeroed() };
835 addr.sun_family = libc::AF_UNIX as u16;
836 addr.sun_path = [1; 108];
837
838 let ptr = std::ptr::from_ref(&addr) as *const MaybeUninit<u8>;
839
840 let len_real = memoffset::offset_of!(libc::sockaddr_un, sun_path);
842 let len_real = len_real.try_into().unwrap();
843
844 let len_struct = std::mem::size_of_val(&addr).try_into().unwrap();
846
847 let addr = unsafe { SockaddrStorage::from_ptr(ptr, len_real) }.unwrap();
848
849 assert!(addr.as_inet().is_none());
850 assert!(addr.as_inet6().is_none());
851
852 let addr = addr.as_unix().unwrap();
853
854 assert!(addr.is_unnamed());
855 assert!(addr.as_path().is_none());
856 assert!(addr.as_abstract().is_none());
857
858 let addr = unsafe { SockaddrStorage::from_ptr(ptr, len_struct) }.unwrap();
859
860 assert!(addr.as_inet().is_none());
861 assert!(addr.as_inet6().is_none());
862
863 let addr = addr.as_unix().unwrap();
864
865 assert!(!addr.is_unnamed());
868 assert!(addr.as_abstract().is_none());
869 assert!(addr.as_path().is_none());
870 }
871
872 #[test]
874 fn unix_addr_from_unnamed_to_libc() {
875 let addr = SockaddrUnix::new_unnamed();
876 let addr = SockaddrStorage::from_unix(&addr.as_ref());
877
878 let (ptr, len) = addr.as_ptr();
879 let ptr = ptr as *const libc::sockaddr_un;
880 assert_eq!(len, 2);
881
882 let addr = unsafe { ptr.as_ref() }.unwrap();
883
884 assert_eq!(addr.sun_family, libc::AF_UNIX as u16);
885 }
886}