]> git.proxmox.com Git - rustc.git/blob - vendor/rustix/src/imp/libc/net/read_sockaddr.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / vendor / rustix / src / imp / libc / net / read_sockaddr.rs
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]
46 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 = "ios",
53 target_os = "macos",
54 target_os = "netbsd",
55 target_os = "openbsd",
56 ))]
57 sa_len: 0_u8,
58 #[cfg(any(
59 target_os = "dragonfly",
60 target_os = "freebsd",
61 target_os = "ios",
62 target_os = "macos",
63 target_os = "netbsd",
64 target_os = "openbsd",
65 ))]
66 sa_family: 0_u8,
67 #[cfg(not(any(
68 target_os = "dragonfly",
69 target_os = "freebsd",
70 target_os = "ios",
71 target_os = "macos",
72 target_os = "netbsd",
73 target_os = "openbsd",
74 )))]
75 sa_family: 0_u16,
76 sa_data: [0; 14],
77 };
78
79 (*storage.cast::<sockaddr_header>()).ss_family.into()
80 }
81
82 /// Set the `ss_family` field of a socket address to `AF_UNSPEC`, so that we
83 /// can test for `AF_UNSPEC` to test whether it was stored to.
84 pub(crate) unsafe fn initialize_family_to_unspec(storage: *mut c::sockaddr_storage) {
85 (*storage.cast::<sockaddr_header>()).ss_family = c::AF_UNSPEC as _;
86 }
87
88 pub(crate) unsafe fn read_sockaddr(
89 storage: *const c::sockaddr_storage,
90 len: usize,
91 ) -> io::Result<SocketAddrAny> {
92 #[cfg(unix)]
93 let offsetof_sun_path = super::addr::offsetof_sun_path();
94
95 if len < size_of::<c::sa_family_t>() {
96 return Err(io::Errno::INVAL);
97 }
98 match read_ss_family(storage).into() {
99 c::AF_INET => {
100 if len < size_of::<c::sockaddr_in>() {
101 return Err(io::Errno::INVAL);
102 }
103 let decode = *storage.cast::<c::sockaddr_in>();
104 Ok(SocketAddrAny::V4(SocketAddrV4::new(
105 Ipv4Addr::from(u32::from_be(in_addr_s_addr(decode.sin_addr))),
106 u16::from_be(decode.sin_port),
107 )))
108 }
109 c::AF_INET6 => {
110 if len < size_of::<c::sockaddr_in6>() {
111 return Err(io::Errno::INVAL);
112 }
113 let decode = *storage.cast::<c::sockaddr_in6>();
114 #[cfg(not(windows))]
115 let s6_addr = decode.sin6_addr.s6_addr;
116 #[cfg(windows)]
117 let s6_addr = decode.sin6_addr.u.Byte;
118 #[cfg(not(windows))]
119 let sin6_scope_id = decode.sin6_scope_id;
120 #[cfg(windows)]
121 let sin6_scope_id = decode.Anonymous.sin6_scope_id;
122 Ok(SocketAddrAny::V6(SocketAddrV6::new(
123 Ipv6Addr::from(s6_addr),
124 u16::from_be(decode.sin6_port),
125 u32::from_be(decode.sin6_flowinfo),
126 sin6_scope_id,
127 )))
128 }
129 #[cfg(unix)]
130 c::AF_UNIX => {
131 if len < offsetof_sun_path {
132 return Err(io::Errno::INVAL);
133 }
134 if len == offsetof_sun_path {
135 Ok(SocketAddrAny::Unix(SocketAddrUnix::new(&[][..]).unwrap()))
136 } else {
137 let decode = *storage.cast::<c::sockaddr_un>();
138
139 // Trim off unused bytes from the end of `path_bytes`.
140 let path_bytes = if cfg!(target_os = "freebsd") {
141 // FreeBSD sometimes sets the length to longer than the length
142 // of the NUL-terminated string. Find the NUL and truncate the
143 // string accordingly.
144 &decode.sun_path[..decode.sun_path.iter().position(|b| *b == 0).unwrap()]
145 } else {
146 // Otherwise, use the provided length.
147 let provided_len = len - 1 - offsetof_sun_path;
148 if decode.sun_path[provided_len] != b'\0' as c::c_char {
149 return Err(io::Errno::INVAL);
150 }
151 debug_assert_eq!(
152 CStr::from_ptr(decode.sun_path.as_ptr()).to_bytes().len(),
153 provided_len
154 );
155 &decode.sun_path[..provided_len]
156 };
157
158 Ok(SocketAddrAny::Unix(
159 SocketAddrUnix::new(path_bytes.iter().map(|c| *c as u8).collect::<Vec<u8>>())
160 .unwrap(),
161 ))
162 }
163 }
164 _ => Err(io::Errno::INVAL),
165 }
166 }
167
168 pub(crate) unsafe fn maybe_read_sockaddr_os(
169 storage: *const c::sockaddr_storage,
170 len: usize,
171 ) -> Option<SocketAddrAny> {
172 if len == 0 {
173 return None;
174 }
175
176 assert!(len >= size_of::<c::sa_family_t>());
177 let family = read_ss_family(storage).into();
178 if family == c::AF_UNSPEC {
179 None
180 } else {
181 Some(inner_read_sockaddr_os(family, storage, len))
182 }
183 }
184
185 pub(crate) unsafe fn read_sockaddr_os(
186 storage: *const c::sockaddr_storage,
187 len: usize,
188 ) -> SocketAddrAny {
189 assert!(len >= size_of::<c::sa_family_t>());
190 let family = read_ss_family(storage).into();
191 inner_read_sockaddr_os(family, storage, len)
192 }
193
194 unsafe fn inner_read_sockaddr_os(
195 family: c::c_int,
196 storage: *const c::sockaddr_storage,
197 len: usize,
198 ) -> SocketAddrAny {
199 #[cfg(unix)]
200 let offsetof_sun_path = super::addr::offsetof_sun_path();
201
202 assert!(len >= size_of::<c::sa_family_t>());
203 match family {
204 c::AF_INET => {
205 assert!(len >= size_of::<c::sockaddr_in>());
206 let decode = *storage.cast::<c::sockaddr_in>();
207 SocketAddrAny::V4(SocketAddrV4::new(
208 Ipv4Addr::from(u32::from_be(in_addr_s_addr(decode.sin_addr))),
209 u16::from_be(decode.sin_port),
210 ))
211 }
212 c::AF_INET6 => {
213 assert!(len >= size_of::<c::sockaddr_in6>());
214 let decode = *storage.cast::<c::sockaddr_in6>();
215 SocketAddrAny::V6(SocketAddrV6::new(
216 Ipv6Addr::from(in6_addr_s6_addr(decode.sin6_addr)),
217 u16::from_be(decode.sin6_port),
218 u32::from_be(decode.sin6_flowinfo),
219 sockaddr_in6_sin6_scope_id(decode),
220 ))
221 }
222 #[cfg(unix)]
223 c::AF_UNIX => {
224 assert!(len >= offsetof_sun_path);
225 if len == offsetof_sun_path {
226 SocketAddrAny::Unix(SocketAddrUnix::new(&[][..]).unwrap())
227 } else {
228 let decode = *storage.cast::<c::sockaddr_un>();
229 assert_eq!(
230 decode.sun_path[len - 1 - offsetof_sun_path],
231 b'\0' as c::c_char
232 );
233 let path_bytes = &decode.sun_path[..len - 1 - offsetof_sun_path];
234
235 // FreeBSD sometimes sets the length to longer than the length
236 // of the NUL-terminated string. Find the NUL and truncate the
237 // string accordingly.
238 #[cfg(target_os = "freebsd")]
239 let path_bytes = &path_bytes[..path_bytes.iter().position(|b| *b == 0).unwrap()];
240
241 SocketAddrAny::Unix(
242 SocketAddrUnix::new(path_bytes.iter().map(|c| *c as u8).collect::<Vec<u8>>())
243 .unwrap(),
244 )
245 }
246 }
247 other => unimplemented!("{:?}", other),
248 }
249 }