1 use super::super::c;
2 #[cfg(unix)]
3 use super::addr::SocketAddrUnix;
4 use super::ext::{in6_addr_s6_addr, in_addr_s_addr, sockaddr_in6_sin6_scope_id};
5 #[cfg(not(windows))]
6 use crate::ffi::CStr;
7 use crate::io;
8 use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrV4, SocketAddrV6};
9 #[cfg(not(windows))]
10 use alloc::vec::Vec;
11 use core::mem::size_of;
12
13 // This must match the header of `sockaddr`.
14 #[repr(C)]
15 struct sockaddr_header {
16 #[cfg(any(
17 target_os = "dragonfly",
18 target_os = "freebsd",
19 target_os = "ios",
20 target_os = "macos",
21 target_os = "netbsd",
22 target_os = "openbsd",
23 ))]
24 sa_len: u8,
25 #[cfg(any(
26 target_os = "dragonfly",
27 target_os = "freebsd",
28 target_os = "ios",
29 target_os = "macos",
30 target_os = "netbsd",
31 target_os = "openbsd",
32 ))]
33 ss_family: u8,
34 #[cfg(not(any(
35 target_os = "dragonfly",
36 target_os = "freebsd",
37 target_os = "ios",
38 target_os = "macos",
39 target_os = "netbsd",
40 target_os = "openbsd",
41 )))]
42 ss_family: u16,
43 }
44
45 #[inline]
read_ss_family(storage: *const c::sockaddr_storage) -> u1646 unsafe fn read_ss_family(storage: *const c::sockaddr_storage) -> u16 {
47 // Assert that we know the layout of `sockaddr`.
48 let _ = c::sockaddr {
49 #[cfg(any(
50 target_os = "dragonfly",
51 target_os = "freebsd",
52 target_os = "haiku",
53 target_os = "ios",
54 target_os = "macos",
55 target_os = "netbsd",
56 target_os = "openbsd",
57 ))]
58 sa_len: 0_u8,
59 #[cfg(any(
60 target_os = "dragonfly",
61 target_os = "freebsd",
62 target_os = "haiku",
63 target_os = "ios",
64 target_os = "macos",
65 target_os = "netbsd",
66 target_os = "openbsd",
67 ))]
68 sa_family: 0_u8,
69 #[cfg(not(any(
70 target_os = "dragonfly",
71 target_os = "freebsd",
72 target_os = "haiku",
73 target_os = "ios",
74 target_os = "macos",
75 target_os = "netbsd",
76 target_os = "openbsd",
77 )))]
78 sa_family: 0_u16,
79 #[cfg(not(target_os = "haiku"))]
80 sa_data: [0; 14],
81 #[cfg(target_os = "haiku")]
82 sa_data: [0; 30],
83 };
84
85 (*storage.cast::<sockaddr_header>()).ss_family.into()
86 }
87
88 /// Set the `ss_family` field of a socket address to `AF_UNSPEC`, so that we
89 /// can test for `AF_UNSPEC` to test whether it was stored to.
initialize_family_to_unspec(storage: *mut c::sockaddr_storage)90 pub(crate) unsafe fn initialize_family_to_unspec(storage: *mut c::sockaddr_storage) {
91 (*storage.cast::<sockaddr_header>()).ss_family = c::AF_UNSPEC as _;
92 }
93
read_sockaddr( storage: *const c::sockaddr_storage, len: usize, ) -> io::Result<SocketAddrAny>94 pub(crate) unsafe fn read_sockaddr(
95 storage: *const c::sockaddr_storage,
96 len: usize,
97 ) -> io::Result<SocketAddrAny> {
98 #[cfg(unix)]
99 let offsetof_sun_path = super::addr::offsetof_sun_path();
100
101 if len < size_of::<c::sa_family_t>() {
102 return Err(io::Errno::INVAL);
103 }
104 match read_ss_family(storage).into() {
105 c::AF_INET => {
106 if len < size_of::<c::sockaddr_in>() {
107 return Err(io::Errno::INVAL);
108 }
109 let decode = *storage.cast::<c::sockaddr_in>();
110 Ok(SocketAddrAny::V4(SocketAddrV4::new(
111 Ipv4Addr::from(u32::from_be(in_addr_s_addr(decode.sin_addr))),
112 u16::from_be(decode.sin_port),
113 )))
114 }
115 c::AF_INET6 => {
116 if len < size_of::<c::sockaddr_in6>() {
117 return Err(io::Errno::INVAL);
118 }
119 let decode = *storage.cast::<c::sockaddr_in6>();
120 #[cfg(not(windows))]
121 let s6_addr = decode.sin6_addr.s6_addr;
122 #[cfg(windows)]
123 let s6_addr = decode.sin6_addr.u.Byte;
124 #[cfg(not(windows))]
125 let sin6_scope_id = decode.sin6_scope_id;
126 #[cfg(windows)]
127 let sin6_scope_id = decode.Anonymous.sin6_scope_id;
128 Ok(SocketAddrAny::V6(SocketAddrV6::new(
129 Ipv6Addr::from(s6_addr),
130 u16::from_be(decode.sin6_port),
131 u32::from_be(decode.sin6_flowinfo),
132 sin6_scope_id,
133 )))
134 }
135 #[cfg(unix)]
136 c::AF_UNIX => {
137 if len < offsetof_sun_path {
138 return Err(io::Errno::INVAL);
139 }
140 if len == offsetof_sun_path {
141 Ok(SocketAddrAny::Unix(SocketAddrUnix::new(&[][..]).unwrap()))
142 } else {
143 let decode = *storage.cast::<c::sockaddr_un>();
144
145 // Trim off unused bytes from the end of `path_bytes`.
146 let path_bytes = if cfg!(target_os = "freebsd") {
147 // FreeBSD sometimes sets the length to longer than the length
148 // of the NUL-terminated string. Find the NUL and truncate the
149 // string accordingly.
150 &decode.sun_path[..decode.sun_path.iter().position(|b| *b == 0).unwrap()]
151 } else {
152 // Otherwise, use the provided length.
153 let provided_len = len - 1 - offsetof_sun_path;
154 if decode.sun_path[provided_len] != b'\0' as c::c_char {
155 return Err(io::Errno::INVAL);
156 }
157 debug_assert_eq!(
158 CStr::from_ptr(decode.sun_path.as_ptr()).to_bytes().len(),
159 provided_len
160 );
161 &decode.sun_path[..provided_len]
162 };
163
164 Ok(SocketAddrAny::Unix(
165 SocketAddrUnix::new(path_bytes.iter().map(|c| *c as u8).collect::<Vec<u8>>())
166 .unwrap(),
167 ))
168 }
169 }
170 _ => Err(io::Errno::INVAL),
171 }
172 }
173
maybe_read_sockaddr_os( storage: *const c::sockaddr_storage, len: usize, ) -> Option<SocketAddrAny>174 pub(crate) unsafe fn maybe_read_sockaddr_os(
175 storage: *const c::sockaddr_storage,
176 len: usize,
177 ) -> Option<SocketAddrAny> {
178 if len == 0 {
179 return None;
180 }
181
182 assert!(len >= size_of::<c::sa_family_t>());
183 let family = read_ss_family(storage).into();
184 if family == c::AF_UNSPEC {
185 None
186 } else {
187 Some(inner_read_sockaddr_os(family, storage, len))
188 }
189 }
190
read_sockaddr_os( storage: *const c::sockaddr_storage, len: usize, ) -> SocketAddrAny191 pub(crate) unsafe fn read_sockaddr_os(
192 storage: *const c::sockaddr_storage,
193 len: usize,
194 ) -> SocketAddrAny {
195 assert!(len >= size_of::<c::sa_family_t>());
196 let family = read_ss_family(storage).into();
197 inner_read_sockaddr_os(family, storage, len)
198 }
199
inner_read_sockaddr_os( family: c::c_int, storage: *const c::sockaddr_storage, len: usize, ) -> SocketAddrAny200 unsafe fn inner_read_sockaddr_os(
201 family: c::c_int,
202 storage: *const c::sockaddr_storage,
203 len: usize,
204 ) -> SocketAddrAny {
205 #[cfg(unix)]
206 let offsetof_sun_path = super::addr::offsetof_sun_path();
207
208 assert!(len >= size_of::<c::sa_family_t>());
209 match family {
210 c::AF_INET => {
211 assert!(len >= size_of::<c::sockaddr_in>());
212 let decode = *storage.cast::<c::sockaddr_in>();
213 SocketAddrAny::V4(SocketAddrV4::new(
214 Ipv4Addr::from(u32::from_be(in_addr_s_addr(decode.sin_addr))),
215 u16::from_be(decode.sin_port),
216 ))
217 }
218 c::AF_INET6 => {
219 assert!(len >= size_of::<c::sockaddr_in6>());
220 let decode = *storage.cast::<c::sockaddr_in6>();
221 SocketAddrAny::V6(SocketAddrV6::new(
222 Ipv6Addr::from(in6_addr_s6_addr(decode.sin6_addr)),
223 u16::from_be(decode.sin6_port),
224 u32::from_be(decode.sin6_flowinfo),
225 sockaddr_in6_sin6_scope_id(decode),
226 ))
227 }
228 #[cfg(unix)]
229 c::AF_UNIX => {
230 assert!(len >= offsetof_sun_path);
231 if len == offsetof_sun_path {
232 SocketAddrAny::Unix(SocketAddrUnix::new(&[][..]).unwrap())
233 } else {
234 let decode = *storage.cast::<c::sockaddr_un>();
235 assert_eq!(
236 decode.sun_path[len - 1 - offsetof_sun_path],
237 b'\0' as c::c_char
238 );
239 let path_bytes = &decode.sun_path[..len - 1 - offsetof_sun_path];
240
241 // FreeBSD sometimes sets the length to longer than the length
242 // of the NUL-terminated string. Find the NUL and truncate the
243 // string accordingly.
244 #[cfg(target_os = "freebsd")]
245 let path_bytes = &path_bytes[..path_bytes.iter().position(|b| *b == 0).unwrap()];
246
247 SocketAddrAny::Unix(
248 SocketAddrUnix::new(path_bytes.iter().map(|c| *c as u8).collect::<Vec<u8>>())
249 .unwrap(),
250 )
251 }
252 }
253 other => unimplemented!("{:?}", other),
254 }
255 }
256