use std::os::raw::c_int;
mod inet4;
mod inet6;
mod unix;
pub use inet4::*;
pub use inet6::*;
pub use unix::*;
pub trait GenericSocketAddress: AsSocketAddress {}
pub trait SpecificSocketAddress: AsSocketAddress {
fn static_family() -> libc::sa_family_t;
}
pub unsafe trait AsSocketAddress: Sized {
fn as_sockaddr(&self) -> *const libc::sockaddr;
fn len(&self) -> libc::socklen_t;
fn family(&self) -> libc::sa_family_t {
unsafe {
(*self.as_sockaddr()).sa_family
}
}
fn as_sockaddr_mut(address: &mut std::mem::MaybeUninit<Self>) -> *mut libc::sockaddr;
fn max_len() -> libc::socklen_t;
fn finalize(address: std::mem::MaybeUninit<Self>, len: libc::socklen_t) -> std::io::Result<Self>;
}
#[derive(Clone)]
#[repr(C)]
pub struct SocketAddress {
inner: libc::sockaddr_storage,
len: libc::socklen_t,
}
impl SocketAddress {
pub fn from_raw(inner: libc::sockaddr_storage, len: libc::socklen_t) -> Self {
Self { inner, len }
}
pub fn from_other<Address: AsSocketAddress>(other: &Address) -> Self {
unsafe {
let mut output = std::mem::MaybeUninit::zeroed();
std::ptr::copy(
other.as_sockaddr(),
AsSocketAddress::as_sockaddr_mut(&mut output),
other.len() as usize
);
AsSocketAddress::finalize(output, other.len()).unwrap()
}
}
pub fn into_raw(self) -> (libc::sockaddr_storage, libc::socklen_t) {
(self.inner, self.len)
}
pub fn family(&self) -> c_int {
self.inner.ss_family as c_int
}
pub fn as_inet4(&self) -> Option<Inet4SocketAddress> {
if self.family() == libc::AF_INET {
let addr: &libc::sockaddr_in = unsafe { std::mem::transmute(&self.inner) };
Some(Inet4SocketAddress::from_raw(*addr))
} else {
None
}
}
pub fn as_inet6(&self) -> Option<Inet6SocketAddress> {
if self.family() == libc::AF_INET6 {
let addr: &libc::sockaddr_in6 = unsafe { std::mem::transmute(&self.inner) };
Some(Inet6SocketAddress::from_raw(*addr))
} else {
None
}
}
pub fn as_unix(&self) -> Option<UnixSocketAddress> {
if self.family() == libc::AF_LOCAL {
let addr: &libc::sockaddr_un = unsafe { std::mem::transmute(&self.inner) };
Some(UnixSocketAddress::from_raw(*addr, self.len))
} else {
None
}
}
}
unsafe impl AsSocketAddress for SocketAddress {
fn as_sockaddr(&self) -> *const libc::sockaddr {
&self.inner as *const _ as *const _
}
fn as_sockaddr_mut(address: &mut std::mem::MaybeUninit<Self>) -> *mut libc::sockaddr {
unsafe { &mut address.as_mut_ptr().as_mut().unwrap().inner as *mut _ as *mut _ }
}
fn len(&self) -> libc::socklen_t {
self.len
}
fn finalize(address: std::mem::MaybeUninit<Self>, len: libc::socklen_t) -> std::io::Result<Self> {
unsafe {
let mut address = address.assume_init();
if len > Self::max_len() {
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "address too large"));
}
address.len = len;
Ok(address)
}
}
fn max_len() -> libc::socklen_t {
std::mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t
}
}
impl GenericSocketAddress for SocketAddress {}