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