#![allow(unsafe_code)]
use crate::backend::c;
use crate::io::Errno;
use crate::net::addr::SocketAddrLen;
use crate::net::netlink::SocketAddrNetlink;
#[cfg(target_os = "linux")]
use crate::net::xdp::{SocketAddrXdp, SocketAddrXdpFlags};
use crate::net::{
AddressFamily, Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrUnix, SocketAddrV4, SocketAddrV6,
};
use core::mem::size_of;
use core::slice;
#[repr(C)]
pub(crate) struct sockaddr_header {
sa_family: u16,
}
#[inline]
pub(crate) const unsafe fn read_sa_family(storage: *const c::sockaddr) -> u16 {
let _ = c::sockaddr {
__storage: c::sockaddr_storage {
__bindgen_anon_1: linux_raw_sys::net::__kernel_sockaddr_storage__bindgen_ty_1 {
__bindgen_anon_1:
linux_raw_sys::net::__kernel_sockaddr_storage__bindgen_ty_1__bindgen_ty_1 {
ss_family: 0_u16,
__data: [0; 126_usize],
},
},
},
};
(*storage.cast::<sockaddr_header>()).sa_family
}
#[inline]
pub(crate) unsafe fn initialize_family_to_unspec(storage: *mut c::sockaddr) {
(*storage.cast::<sockaddr_header>()).sa_family = c::AF_UNSPEC as _;
}
#[inline]
pub(crate) unsafe fn sockaddr_nonempty(_storage: *const c::sockaddr, len: SocketAddrLen) -> bool {
len != 0
}
#[inline]
pub(crate) fn read_sockaddr_v4(addr: &SocketAddrAny) -> Result<SocketAddrV4, Errno> {
if addr.address_family() != AddressFamily::INET {
return Err(Errno::AFNOSUPPORT);
}
assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_in>());
let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_in>() };
Ok(SocketAddrV4::new(
Ipv4Addr::from(u32::from_be(decode.sin_addr.s_addr)),
u16::from_be(decode.sin_port),
))
}
#[inline]
pub(crate) fn read_sockaddr_v6(addr: &SocketAddrAny) -> Result<SocketAddrV6, Errno> {
if addr.address_family() != AddressFamily::INET6 {
return Err(Errno::AFNOSUPPORT);
}
assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_in6>());
let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_in6>() };
Ok(SocketAddrV6::new(
Ipv6Addr::from(unsafe { decode.sin6_addr.in6_u.u6_addr8 }),
u16::from_be(decode.sin6_port),
u32::from_be(decode.sin6_flowinfo),
decode.sin6_scope_id,
))
}
#[inline]
pub(crate) fn read_sockaddr_unix(addr: &SocketAddrAny) -> Result<SocketAddrUnix, Errno> {
if addr.address_family() != AddressFamily::UNIX {
return Err(Errno::AFNOSUPPORT);
}
let offsetof_sun_path = super::addr::offsetof_sun_path();
let len = addr.addr_len() as usize;
assert!(len >= offsetof_sun_path);
if len == offsetof_sun_path {
SocketAddrUnix::new(&[][..])
} else {
let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_un>() };
if decode.sun_path[0] == 0 {
let bytes = &decode.sun_path[1..len - offsetof_sun_path];
let bytes = unsafe { slice::from_raw_parts(bytes.as_ptr().cast::<u8>(), bytes.len()) };
return SocketAddrUnix::new_abstract_name(bytes);
}
let bytes = &decode.sun_path[..len - 1 - offsetof_sun_path];
let bytes = unsafe { slice::from_raw_parts(bytes.as_ptr().cast::<u8>(), bytes.len()) };
assert_eq!(decode.sun_path[len - 1 - offsetof_sun_path], 0);
SocketAddrUnix::new(bytes)
}
}
#[inline]
pub(crate) fn read_sockaddr_xdp(addr: &SocketAddrAny) -> Result<SocketAddrXdp, Errno> {
if addr.address_family() != AddressFamily::XDP {
return Err(Errno::AFNOSUPPORT);
}
assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_xdp>());
let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_xdp>() };
Ok(SocketAddrXdp::new(
SocketAddrXdpFlags::from_bits_retain(decode.sxdp_flags),
u32::from_be(decode.sxdp_ifindex),
u32::from_be(decode.sxdp_queue_id),
))
}
#[inline]
pub(crate) fn read_sockaddr_netlink(addr: &SocketAddrAny) -> Result<SocketAddrNetlink, Errno> {
if addr.address_family() != AddressFamily::NETLINK {
return Err(Errno::AFNOSUPPORT);
}
assert!(addr.addr_len() as usize >= size_of::<c::sockaddr_nl>());
let decode = unsafe { &*addr.as_ptr().cast::<c::sockaddr_nl>() };
Ok(SocketAddrNetlink::new(decode.nl_pid, decode.nl_groups))
}