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}
;
9 use core
::mem
::size_of
;
11 // This must match the header of `sockaddr`.
13 struct sockaddr_header
{
14 #[cfg(any(bsd, target_os = "haiku"))]
16 #[cfg(any(bsd, target_os = "haiku"))]
18 #[cfg(not(any(bsd, target_os = "haiku")))]
23 unsafe fn read_ss_family(storage
: *const c
::sockaddr_storage
) -> u16 {
24 // Assert that we know the layout of `sockaddr`.
26 #[cfg(any(bsd, target_os = "haiku"))]
28 #[cfg(any(bsd, target_os = "haiku"))]
30 #[cfg(not(any(bsd, target_os = "haiku")))]
32 #[cfg(not(target_os = "haiku"))]
34 #[cfg(target_os = "haiku")]
38 (*storage
.cast
::<sockaddr_header
>()).ss_family
.into()
41 /// Set the `ss_family` field of a socket address to `AF_UNSPEC`, so that we
42 /// can test for `AF_UNSPEC` to test whether it was stored to.
43 pub(crate) unsafe fn initialize_family_to_unspec(storage
: *mut c
::sockaddr_storage
) {
44 (*storage
.cast
::<sockaddr_header
>()).ss_family
= c
::AF_UNSPEC
as _
;
47 pub(crate) unsafe fn read_sockaddr(
48 storage
: *const c
::sockaddr_storage
,
50 ) -> io
::Result
<SocketAddrAny
> {
52 let offsetof_sun_path
= super::addr
::offsetof_sun_path();
54 if len
< size_of
::<c
::sa_family_t
>() {
55 return Err(io
::Errno
::INVAL
);
57 match read_ss_family(storage
).into() {
59 if len
< size_of
::<c
::sockaddr_in
>() {
60 return Err(io
::Errno
::INVAL
);
62 let decode
= &*storage
.cast
::<c
::sockaddr_in
>();
63 Ok(SocketAddrAny
::V4(SocketAddrV4
::new(
64 Ipv4Addr
::from(u32::from_be(in_addr_s_addr(decode
.sin_addr
))),
65 u16::from_be(decode
.sin_port
),
69 if len
< size_of
::<c
::sockaddr_in6
>() {
70 return Err(io
::Errno
::INVAL
);
72 let decode
= &*storage
.cast
::<c
::sockaddr_in6
>();
74 let s6_addr
= decode
.sin6_addr
.s6_addr
;
76 let s6_addr
= decode
.sin6_addr
.u
.Byte
;
78 let sin6_scope_id
= decode
.sin6_scope_id
;
80 let sin6_scope_id
= decode
.Anonymous
.sin6_scope_id
;
81 Ok(SocketAddrAny
::V6(SocketAddrV6
::new(
82 Ipv6Addr
::from(s6_addr
),
83 u16::from_be(decode
.sin6_port
),
84 u32::from_be(decode
.sin6_flowinfo
),
90 if len
< offsetof_sun_path
{
91 return Err(io
::Errno
::INVAL
);
93 if len
== offsetof_sun_path
{
94 SocketAddrUnix
::new(&[][..]).map(SocketAddrAny
::Unix
)
96 let decode
= &*storage
.cast
::<c
::sockaddr_un
>();
98 // On Linux check for Linux's [abstract namespace].
100 // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html
102 if decode
.sun_path
[0] == 0 {
103 return SocketAddrUnix
::new_abstract_name(core
::mem
::transmute
::<
107 &decode
.sun_path
[1..len
- offsetof_sun_path
],
109 .map(SocketAddrAny
::Unix
);
112 // Otherwise we expect a NUL-terminated filesystem path.
114 // Trim off unused bytes from the end of `path_bytes`.
115 let path_bytes
= if cfg
!(target_os
= "freebsd") {
116 // FreeBSD sometimes sets the length to longer than the length
117 // of the NUL-terminated string. Find the NUL and truncate the
118 // string accordingly.
119 &decode
.sun_path
[..decode
122 .position(|b
| *b
== 0)
123 .ok_or(io
::Errno
::INVAL
)?
]
125 // Otherwise, use the provided length.
126 let provided_len
= len
- 1 - offsetof_sun_path
;
127 if decode
.sun_path
[provided_len
] != 0 {
128 return Err(io
::Errno
::INVAL
);
131 CStr
::from_ptr(decode
.sun_path
.as_ptr()).to_bytes().len(),
134 &decode
.sun_path
[..provided_len
]
137 SocketAddrUnix
::new(core
::mem
::transmute
::<&[c
::c_char
], &[u8]>(path_bytes
))
138 .map(SocketAddrAny
::Unix
)
141 _
=> Err(io
::Errno
::INVAL
),
145 pub(crate) unsafe fn maybe_read_sockaddr_os(
146 storage
: *const c
::sockaddr_storage
,
148 ) -> Option
<SocketAddrAny
> {
153 assert
!(len
>= size_of
::<c
::sa_family_t
>());
154 let family
= read_ss_family(storage
).into();
155 if family
== c
::AF_UNSPEC
{
158 Some(inner_read_sockaddr_os(family
, storage
, len
))
162 pub(crate) unsafe fn read_sockaddr_os(
163 storage
: *const c
::sockaddr_storage
,
166 assert
!(len
>= size_of
::<c
::sa_family_t
>());
167 let family
= read_ss_family(storage
).into();
168 inner_read_sockaddr_os(family
, storage
, len
)
171 unsafe fn inner_read_sockaddr_os(
173 storage
: *const c
::sockaddr_storage
,
177 let offsetof_sun_path
= super::addr
::offsetof_sun_path();
179 assert
!(len
>= size_of
::<c
::sa_family_t
>());
182 assert
!(len
>= size_of
::<c
::sockaddr_in
>());
183 let decode
= &*storage
.cast
::<c
::sockaddr_in
>();
184 SocketAddrAny
::V4(SocketAddrV4
::new(
185 Ipv4Addr
::from(u32::from_be(in_addr_s_addr(decode
.sin_addr
))),
186 u16::from_be(decode
.sin_port
),
190 assert
!(len
>= size_of
::<c
::sockaddr_in6
>());
191 let decode
= &*storage
.cast
::<c
::sockaddr_in6
>();
192 SocketAddrAny
::V6(SocketAddrV6
::new(
193 Ipv6Addr
::from(in6_addr_s6_addr(decode
.sin6_addr
)),
194 u16::from_be(decode
.sin6_port
),
195 u32::from_be(decode
.sin6_flowinfo
),
196 sockaddr_in6_sin6_scope_id(decode
),
201 assert
!(len
>= offsetof_sun_path
);
202 if len
== offsetof_sun_path
{
203 SocketAddrAny
::Unix(SocketAddrUnix
::new(&[][..]).unwrap())
205 let decode
= &*storage
.cast
::<c
::sockaddr_un
>();
207 // On Linux check for Linux's [abstract namespace].
209 // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html
211 if decode
.sun_path
[0] == 0 {
212 return SocketAddrAny
::Unix(
213 SocketAddrUnix
::new_abstract_name(core
::mem
::transmute
::<
217 &decode
.sun_path
[1..len
- offsetof_sun_path
],
223 // Otherwise we expect a NUL-terminated filesystem path.
224 assert_eq
!(decode
.sun_path
[len
- 1 - offsetof_sun_path
], 0);
225 let path_bytes
= &decode
.sun_path
[..len
- 1 - offsetof_sun_path
];
227 // FreeBSD sometimes sets the length to longer than the length
228 // of the NUL-terminated string. Find the NUL and truncate the
229 // string accordingly.
230 #[cfg(target_os = "freebsd")]
231 let path_bytes
= &path_bytes
[..path_bytes
.iter().position(|b
| *b
== 0).unwrap()];
234 SocketAddrUnix
::new(core
::mem
::transmute
::<&[c
::c_char
], &[u8]>(path_bytes
))
239 other
=> unimplemented
!("{:?}", other
),