use std::mem::{self, MaybeUninit};
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
use std::{fmt, ptr};
use crate::sys::{
c_int, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET,
AF_INET6,
};
pub struct SockAddr {
storage: sockaddr_storage,
len: socklen_t,
}
impl SockAddr {
pub unsafe fn from_raw_parts(addr: *const sockaddr, len: socklen_t) -> SockAddr {
let mut storage = MaybeUninit::<sockaddr_storage>::uninit();
ptr::copy_nonoverlapping(
addr as *const _ as *const u8,
storage.as_mut_ptr() as *mut u8,
len as usize,
);
SockAddr {
storage: storage.assume_init(),
len: len,
}
}
pub fn family(&self) -> sa_family_t {
self.storage.ss_family
}
pub fn len(&self) -> socklen_t {
self.len
}
pub fn as_ptr(&self) -> *const sockaddr {
&self.storage as *const _ as *const _
}
pub fn as_std(&self) -> Option<SocketAddr> {
self.as_inet()
.map(|a| a.into())
.or_else(|| self.as_inet6().map(|a| a.into()))
}
pub fn as_inet(&self) -> Option<SocketAddrV4> {
if self.storage.ss_family as c_int == AF_INET {
let storage: *const sockaddr_storage = (&self.storage) as *const _;
Some(unsafe { *(storage as *const sockaddr_in as *const _) })
} else {
None
}
}
pub fn as_inet6(&self) -> Option<SocketAddrV6> {
if self.storage.ss_family as c_int == AF_INET6 {
let storage: *const sockaddr_storage = (&self.storage) as *const _;
Some(unsafe { *(storage as *const sockaddr_in6 as *const _) })
} else {
None
}
}
}
impl From<SocketAddr> for SockAddr {
fn from(addr: SocketAddr) -> SockAddr {
match addr {
SocketAddr::V4(addr) => addr.into(),
SocketAddr::V6(addr) => addr.into(),
}
}
}
impl From<SocketAddrV4> for SockAddr {
fn from(addr: SocketAddrV4) -> SockAddr {
unsafe {
SockAddr::from_raw_parts(
&addr as *const _ as *const _,
mem::size_of::<SocketAddrV4>() as socklen_t,
)
}
}
}
impl From<SocketAddrV6> for SockAddr {
fn from(addr: SocketAddrV6) -> SockAddr {
unsafe {
SockAddr::from_raw_parts(
&addr as *const _ as *const _,
mem::size_of::<SocketAddrV6>() as socklen_t,
)
}
}
}
impl fmt::Debug for SockAddr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut f = fmt.debug_struct("SockAddr");
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "haiku",
target_os = "hermit",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "vxworks",
))]
f.field("ss_len", &self.storage.ss_len);
f.field("ss_family", &self.storage.ss_family)
.field("len", &self.len)
.finish()
}
}