1 //! Socket address utilities.
2 //!
3 //! # Safety
4 //!
5 //! This file uses `CStr::from_bytes_with_nul_unchecked` on a string it knows
6 //! to be NUL-terminated.
7 #![allow(unsafe_code)]
8
9 use crate::backend::c;
10 use crate::ffi::CStr;
11 use crate::{io, path};
12 use core::cmp::Ordering;
13 use core::fmt;
14 use core::hash::{Hash, Hasher};
15 use core::slice;
16
17 /// `struct sockaddr_un`
18 #[derive(Clone)]
19 #[doc(alias = "sockaddr_un")]
20 pub struct SocketAddrUnix {
21 pub(crate) unix: c::sockaddr_un,
22 len: c::socklen_t,
23 }
24
25 impl SocketAddrUnix {
26 /// Construct a new Unix-domain address from a filesystem path.
27 #[inline]
new<P: path::Arg>(path: P) -> io::Result<Self>28 pub fn new<P: path::Arg>(path: P) -> io::Result<Self> {
29 path.into_with_c_str(Self::_new)
30 }
31
32 #[inline]
_new(path: &CStr) -> io::Result<Self>33 fn _new(path: &CStr) -> io::Result<Self> {
34 let mut unix = Self::init();
35 let bytes = path.to_bytes_with_nul();
36 if bytes.len() > unix.sun_path.len() {
37 return Err(io::Errno::NAMETOOLONG);
38 }
39 for (i, b) in bytes.iter().enumerate() {
40 unix.sun_path[i] = *b as _;
41 }
42 let len = offsetof_sun_path() + bytes.len();
43 let len = len.try_into().unwrap();
44 Ok(Self { unix, len })
45 }
46
47 /// Construct a new abstract Unix-domain address from a byte slice.
48 #[inline]
new_abstract_name(name: &[u8]) -> io::Result<Self>49 pub fn new_abstract_name(name: &[u8]) -> io::Result<Self> {
50 let mut unix = Self::init();
51 let id = &mut unix.sun_path[1..];
52
53 // SAFETY: Convert `&mut [c_char]` to `&mut [u8]`.
54 let id = unsafe { slice::from_raw_parts_mut(id.as_mut_ptr().cast::<u8>(), id.len()) };
55
56 if let Some(id) = id.get_mut(..name.len()) {
57 id.copy_from_slice(name);
58 let len = offsetof_sun_path() + 1 + name.len();
59 let len = len.try_into().unwrap();
60 Ok(Self { unix, len })
61 } else {
62 Err(io::Errno::NAMETOOLONG)
63 }
64 }
65
init() -> c::sockaddr_un66 const fn init() -> c::sockaddr_un {
67 c::sockaddr_un {
68 sun_family: c::AF_UNIX as _,
69 sun_path: [0; 108],
70 }
71 }
72
73 /// For a filesystem path address, return the path.
74 #[inline]
path(&self) -> Option<&CStr>75 pub fn path(&self) -> Option<&CStr> {
76 let len = self.len();
77 if len != 0 && self.unix.sun_path[0] as u8 != b'\0' {
78 let end = len as usize - offsetof_sun_path();
79 let bytes = &self.unix.sun_path[..end];
80
81 // SAFETY: Convert `&[c_char]` to `&[u8]`.
82 let bytes = unsafe { slice::from_raw_parts(bytes.as_ptr().cast::<u8>(), bytes.len()) };
83
84 // SAFETY: `from_bytes_with_nul_unchecked` since the string is
85 // NUL-terminated.
86 unsafe { Some(CStr::from_bytes_with_nul_unchecked(bytes)) }
87 } else {
88 None
89 }
90 }
91
92 /// For an abstract address, return the identifier.
93 #[inline]
abstract_name(&self) -> Option<&[u8]>94 pub fn abstract_name(&self) -> Option<&[u8]> {
95 let len = self.len();
96 if len != 0 && self.unix.sun_path[0] as u8 == b'\0' {
97 let end = len as usize - offsetof_sun_path();
98 let bytes = &self.unix.sun_path[1..end];
99
100 // SAFETY: Convert `&[c_char]` to `&[u8]`.
101 let bytes = unsafe { slice::from_raw_parts(bytes.as_ptr().cast::<u8>(), bytes.len()) };
102
103 Some(bytes)
104 } else {
105 None
106 }
107 }
108
109 #[inline]
addr_len(&self) -> c::socklen_t110 pub(crate) fn addr_len(&self) -> c::socklen_t {
111 self.len
112 }
113
114 #[inline]
len(&self) -> usize115 pub(crate) fn len(&self) -> usize {
116 self.addr_len() as usize
117 }
118 }
119
120 impl PartialEq for SocketAddrUnix {
121 #[inline]
eq(&self, other: &Self) -> bool122 fn eq(&self, other: &Self) -> bool {
123 let self_len = self.len() - offsetof_sun_path();
124 let other_len = other.len() - offsetof_sun_path();
125 self.unix.sun_path[..self_len].eq(&other.unix.sun_path[..other_len])
126 }
127 }
128
129 impl Eq for SocketAddrUnix {}
130
131 impl PartialOrd for SocketAddrUnix {
132 #[inline]
partial_cmp(&self, other: &Self) -> Option<Ordering>133 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
134 Some(self.cmp(other))
135 }
136 }
137
138 impl Ord for SocketAddrUnix {
139 #[inline]
cmp(&self, other: &Self) -> Ordering140 fn cmp(&self, other: &Self) -> Ordering {
141 let self_len = self.len() - offsetof_sun_path();
142 let other_len = other.len() - offsetof_sun_path();
143 self.unix.sun_path[..self_len].cmp(&other.unix.sun_path[..other_len])
144 }
145 }
146
147 impl Hash for SocketAddrUnix {
148 #[inline]
hash<H: Hasher>(&self, state: &mut H)149 fn hash<H: Hasher>(&self, state: &mut H) {
150 let self_len = self.len() - offsetof_sun_path();
151 self.unix.sun_path[..self_len].hash(state)
152 }
153 }
154
155 impl fmt::Debug for SocketAddrUnix {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result156 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
157 if let Some(path) = self.path() {
158 path.fmt(fmt)
159 } else if let Some(name) = self.abstract_name() {
160 name.fmt(fmt)
161 } else {
162 "(unnamed)".fmt(fmt)
163 }
164 }
165 }
166
167 /// `struct sockaddr_storage` as a raw struct.
168 pub type SocketAddrStorage = c::sockaddr;
169
170 /// Return the offset of the `sun_path` field of `sockaddr_un`.
171 #[inline]
offsetof_sun_path() -> usize172 pub(crate) fn offsetof_sun_path() -> usize {
173 let z = c::sockaddr_un {
174 sun_family: 0_u16,
175 sun_path: [0; 108],
176 };
177 (crate::utils::as_ptr(&z.sun_path) as usize) - (crate::utils::as_ptr(&z) as usize)
178 }
179