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