3 use super::addr
::SocketAddrUnix
;
4 use super::ext
::{in6_addr_s6_addr, in_addr_s_addr, sockaddr_in6_sin6_scope_id}
;
8 use crate::net
::{Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrV4, SocketAddrV6}
;
11 use core
::mem
::size_of
;
13 // This must match the header of `sockaddr`.
15 struct sockaddr_header
{
17 target_os
= "dragonfly",
18 target_os
= "freebsd",
22 target_os
= "openbsd",
26 target_os
= "dragonfly",
27 target_os
= "freebsd",
31 target_os
= "openbsd",
35 target_os
= "dragonfly",
36 target_os
= "freebsd",
40 target_os
= "openbsd",
46 unsafe fn read_ss_family(storage
: *const c
::sockaddr_storage
) -> u16 {
47 // Assert that we know the layout of `sockaddr`.
50 target_os
= "dragonfly",
51 target_os
= "freebsd",
55 target_os
= "openbsd",
59 target_os
= "dragonfly",
60 target_os
= "freebsd",
64 target_os
= "openbsd",
68 target_os
= "dragonfly",
69 target_os
= "freebsd",
73 target_os
= "openbsd",
79 (*storage
.cast
::<sockaddr_header
>()).ss_family
.into()
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 _
;
88 pub(crate) unsafe fn read_sockaddr(
89 storage
: *const c
::sockaddr_storage
,
91 ) -> io
::Result
<SocketAddrAny
> {
93 let offsetof_sun_path
= super::addr
::offsetof_sun_path();
95 if len
< size_of
::<c
::sa_family_t
>() {
96 return Err(io
::Errno
::INVAL
);
98 match read_ss_family(storage
).into() {
100 if len
< size_of
::<c
::sockaddr_in
>() {
101 return Err(io
::Errno
::INVAL
);
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
),
110 if len
< size_of
::<c
::sockaddr_in6
>() {
111 return Err(io
::Errno
::INVAL
);
113 let decode
= *storage
.cast
::<c
::sockaddr_in6
>();
115 let s6_addr
= decode
.sin6_addr
.s6_addr
;
117 let s6_addr
= decode
.sin6_addr
.u
.Byte
;
119 let sin6_scope_id
= decode
.sin6_scope_id
;
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
),
131 if len
< offsetof_sun_path
{
132 return Err(io
::Errno
::INVAL
);
134 if len
== offsetof_sun_path
{
135 Ok(SocketAddrAny
::Unix(SocketAddrUnix
::new(&[][..]).unwrap()))
137 let decode
= *storage
.cast
::<c
::sockaddr_un
>();
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()]
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
);
152 CStr
::from_ptr(decode
.sun_path
.as_ptr()).to_bytes().len(),
155 &decode
.sun_path
[..provided_len
]
158 Ok(SocketAddrAny
::Unix(
159 SocketAddrUnix
::new(path_bytes
.iter().map(|c
| *c
as u8).collect
::<Vec
<u8>>())
164 _
=> Err(io
::Errno
::INVAL
),
168 pub(crate) unsafe fn maybe_read_sockaddr_os(
169 storage
: *const c
::sockaddr_storage
,
171 ) -> Option
<SocketAddrAny
> {
176 assert
!(len
>= size_of
::<c
::sa_family_t
>());
177 let family
= read_ss_family(storage
).into();
178 if family
== c
::AF_UNSPEC
{
181 Some(inner_read_sockaddr_os(family
, storage
, len
))
185 pub(crate) unsafe fn read_sockaddr_os(
186 storage
: *const c
::sockaddr_storage
,
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
)
194 unsafe fn inner_read_sockaddr_os(
196 storage
: *const c
::sockaddr_storage
,
200 let offsetof_sun_path
= super::addr
::offsetof_sun_path();
202 assert
!(len
>= size_of
::<c
::sa_family_t
>());
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
),
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
),
224 assert
!(len
>= offsetof_sun_path
);
225 if len
== offsetof_sun_path
{
226 SocketAddrAny
::Unix(SocketAddrUnix
::new(&[][..]).unwrap())
228 let decode
= *storage
.cast
::<c
::sockaddr_un
>();
230 decode
.sun_path
[len
- 1 - offsetof_sun_path
],
233 let path_bytes
= &decode
.sun_path
[..len
- 1 - offsetof_sun_path
];
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()];
242 SocketAddrUnix
::new(path_bytes
.iter().map(|c
| *c
as u8).collect
::<Vec
<u8>>())
247 other
=> unimplemented
!("{:?}", other
),