use std::{
ffi::{self, CStr, c_char},
fmt::{Debug, Formatter},
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
};
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct sa_family_t(pub u16);
impl Debug for sa_family_t {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match *self {
AF_INET => write!(f, "AF_INET"),
AF_INET6 => write!(f, "AF_INET6"),
_ => write!(f, "sa_family_t({})", self.0),
}
}
}
pub const AF_INET: sa_family_t = sa_family_t(2);
pub const AF_INET6: sa_family_t = sa_family_t(23);
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct in_addr_t(pub [u8; 4]);
impl From<&in_addr_t> for Ipv4Addr {
fn from(value: &in_addr_t) -> Self {
Ipv4Addr::from_octets(value.0)
}
}
impl From<in_addr_t> for Ipv4Addr {
fn from(value: in_addr_t) -> Self {
Ipv4Addr::from_octets(value.0)
}
}
impl From<&Ipv4Addr> for in_addr_t {
fn from(value: &Ipv4Addr) -> Self {
Self(value.octets())
}
}
impl From<Ipv4Addr> for in_addr_t {
fn from(value: Ipv4Addr) -> Self {
Self(value.octets())
}
}
impl Debug for in_addr_t {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Ipv4Addr::from(self).fmt(f)
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct in6_addr_t(pub [u16; 8]);
impl Debug for in6_addr_t {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Ipv6Addr::from(*self).fmt(f)
}
}
impl From<in6_addr_t> for Ipv6Addr {
fn from(value: in6_addr_t) -> Self {
Ipv6Addr::from(value.0)
}
}
impl From<&in6_addr_t> for Ipv6Addr {
fn from(value: &in6_addr_t) -> Self {
Ipv6Addr::from(value.0)
}
}
impl From<Ipv6Addr> for in6_addr_t {
fn from(value: Ipv6Addr) -> Self {
Self(value.segments())
}
}
impl From<&Ipv6Addr> for in6_addr_t {
fn from(value: &Ipv6Addr) -> Self {
Self(value.segments())
}
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct sockaddr {
pub sa_family: sa_family_t,
pub sa_data: sockaddr_data,
}
impl Debug for sockaddr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self.sa_family {
AF_INET => unsafe { &self.sa_data.sockaddr_in }.fmt(f),
AF_INET6 => unsafe { &self.sa_data.sockaddr_in6 }.fmt(f),
unknown => f
.debug_struct("sockaddr")
.field("sa_family", &unknown)
.finish_non_exhaustive(),
}
}
}
#[derive(Copy, Clone)]
#[repr(C)]
pub union sockaddr_data {
pub sockaddr_in: sockaddr_in,
pub sockaddr_in6: sockaddr_in6,
}
impl TryFrom<sockaddr> for SocketAddr {
type Error = ();
fn try_from(sockaddr: sockaddr) -> Result<Self, Self::Error> {
sockaddr.try_into()
}
}
impl TryFrom<&sockaddr> for SocketAddr {
type Error = ();
fn try_from(sockaddr: &sockaddr) -> Result<Self, Self::Error> {
match sockaddr.sa_family {
AF_INET => {
let sin = unsafe { &sockaddr.sa_data.sockaddr_in };
let addrv4: SocketAddrV4 = sin.into();
Ok(addrv4.into())
}
AF_INET6 => {
let sin6 = unsafe { &sockaddr.sa_data.sockaddr_in6 };
let addrv6: SocketAddrV6 = sin6.into();
Ok(addrv6.into())
}
invalid_af => {
tracing::error!(?invalid_af);
Err(())
}
}
}
}
impl From<SocketAddr> for sockaddr {
fn from(value: SocketAddr) -> Self {
match value {
SocketAddr::V4(addr) => sockaddr {
sa_family: AF_INET,
sa_data: sockaddr_data {
sockaddr_in: addr.into(),
},
},
SocketAddr::V6(addr) => sockaddr {
sa_family: AF_INET6,
sa_data: sockaddr_data {
sockaddr_in6: addr.into(),
},
},
}
}
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct sockaddr_in {
pub sin_port: u16,
pub sin_addr: in_addr_t,
}
impl From<&SocketAddrV4> for sockaddr_in {
fn from(addr: &SocketAddrV4) -> Self {
sockaddr_in {
sin_addr: addr.ip().into(),
sin_port: addr.port(),
}
}
}
impl From<SocketAddrV4> for sockaddr_in {
fn from(addr: SocketAddrV4) -> Self {
(&addr).into()
}
}
impl From<sockaddr_in> for SocketAddrV4 {
fn from(value: sockaddr_in) -> Self {
(&value).into()
}
}
impl From<&sockaddr_in> for SocketAddrV4 {
fn from(value: &sockaddr_in) -> Self {
SocketAddrV4::new(value.sin_addr.into(), value.sin_port)
}
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct sockaddr_in6 {
pub sin6_port: u16,
pub sin6_flowinfo: u32,
pub sin6_addr: in6_addr_t,
pub sin6_scope_id: u32,
}
impl From<&SocketAddrV6> for sockaddr_in6 {
fn from(addr: &SocketAddrV6) -> Self {
sockaddr_in6 {
sin6_addr: addr.ip().into(),
sin6_port: addr.port(),
sin6_scope_id: addr.scope_id(),
sin6_flowinfo: addr.flowinfo(),
}
}
}
impl From<SocketAddrV6> for sockaddr_in6 {
fn from(addr: SocketAddrV6) -> Self {
(&addr).into()
}
}
impl From<&sockaddr_in6> for SocketAddrV6 {
fn from(sin6: &sockaddr_in6) -> Self {
SocketAddrV6::new(
sin6.sin6_addr.into(),
sin6.sin6_port,
sin6.sin6_flowinfo,
sin6.sin6_flowinfo,
)
}
}
impl From<sockaddr_in6> for SocketAddrV6 {
fn from(sin6: sockaddr_in6) -> Self {
(&sin6).into()
}
}
#[unsafe(no_mangle)]
pub extern "C" fn ts_parse_sockaddr(s: *const c_char, addr: &mut sockaddr) -> ffi::c_int {
let Ok(s) = (unsafe { CStr::from_ptr(s) }).to_str() else {
tracing::error!("bad utf8");
return -1;
};
let parsed = match s.parse::<SocketAddr>() {
Ok(parsed) => parsed,
Err(e) => {
tracing::error!(error = %e, "invalid addr");
return -1;
}
};
*addr = parsed.into();
0
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ts_parse_ip(s: *const c_char, addr: &mut sockaddr) -> ffi::c_int {
let Ok(s) = (unsafe { CStr::from_ptr(s) }).to_str() else {
tracing::error!("bad utf8");
return -1;
};
let parsed = match s.parse::<IpAddr>() {
Ok(parsed) => parsed,
Err(e) => {
tracing::error!(error = %e, "invalid addr");
return -1;
}
};
*addr = SocketAddr::from((parsed, 0)).into();
0
}
#[unsafe(no_mangle)]
pub extern "C" fn ts_sockaddr_set_port(addr: &mut sockaddr, port: u16) -> ffi::c_int {
match addr.sa_family {
AF_INET => {
unsafe { addr.sa_data.sockaddr_in }.sin_port = port;
0
}
AF_INET6 => {
unsafe { addr.sa_data.sockaddr_in6 }.sin6_port = port;
0
}
_ => -1,
}
}