#[cfg(feature = "feat-codec-encode")]
use alloc::vec::Vec;
use core::net::{Ipv4Addr, Ipv6Addr};
#[cfg(feature = "feat-uni-addr")]
use std::io;
#[cfg(feature = "feat-codec-decode")]
use slicur::Reader;
#[cfg(feature = "feat-codec-v1")]
use crate::v1;
#[cfg(feature = "feat-codec-decode")]
use crate::v2::DecodeError;
#[cfg(any(feature = "feat-codec-encode", feature = "feat-codec-decode"))]
pub(crate) const BYTE_VERSION: u8 = 0x20;
pub const HEADER_SIZE: usize = 16;
#[cfg(any(feature = "feat-codec-encode", feature = "feat-codec-decode"))]
pub(crate) const ADDR_INET_SIZE: usize = 12;
#[cfg(any(feature = "feat-codec-encode", feature = "feat-codec-decode"))]
pub(crate) const ADDR_INET6_SIZE: usize = 36;
#[cfg(any(feature = "feat-codec-encode", feature = "feat-codec-decode"))]
pub(crate) const ADDR_UNIX_SIZE: usize = 216;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Command {
Local = 0x00,
Proxy = 0x01,
}
#[cfg(any(feature = "feat-codec-encode", feature = "feat-codec-decode"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub(crate) enum Family {
Unspecified = 0x00,
Inet = 0x10,
Inet6 = 0x20,
Unix = 0x30,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Protocol {
Unspecified = 0x00,
Stream = 0x01,
Dgram = 0x02,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AddressPair {
Unspecified,
Inet {
src_ip: Ipv4Addr,
dst_ip: Ipv4Addr,
src_port: u16,
dst_port: u16,
},
Inet6 {
src_ip: Ipv6Addr,
dst_ip: Ipv6Addr,
src_port: u16,
dst_port: u16,
},
Unix {
src_addr: [u8; 108],
dst_addr: [u8; 108],
},
}
#[cfg(feature = "feat-codec-v1")]
impl From<v1::AddressPair> for AddressPair {
fn from(addr: v1::AddressPair) -> Self {
AddressPair::from_v1(addr)
}
}
impl AddressPair {
#[cfg(feature = "feat-codec-v1")]
#[inline]
pub const fn from_v1(addr: v1::AddressPair) -> Self {
match addr {
v1::AddressPair::Unspecified => Self::Unspecified,
v1::AddressPair::Inet {
src_ip,
dst_ip,
src_port,
dst_port,
} => Self::Inet {
src_ip,
dst_ip,
src_port,
dst_port,
},
v1::AddressPair::Inet6 {
src_ip,
dst_ip,
src_port,
dst_port,
} => Self::Inet6 {
src_ip,
dst_ip,
src_port,
dst_port,
},
}
}
#[cfg(feature = "feat-codec-encode")]
#[inline]
pub(crate) const fn address_family(&self) -> Family {
match self {
Self::Unspecified => Family::Unspecified,
Self::Inet { .. } => Family::Inet,
Self::Inet6 { .. } => Family::Inet6,
Self::Unix { .. } => Family::Unix,
}
}
#[cfg(feature = "feat-uni-addr")]
pub fn src_uni_addr(&self) -> io::Result<Option<uni_addr::UniAddr>> {
use core::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
match self {
Self::Unspecified => Ok(None),
Self::Inet { src_ip, src_port, .. } => Ok(Some(uni_addr::UniAddr::from(SocketAddr::V4(
SocketAddrV4::new(*src_ip, *src_port),
)))),
Self::Inet6 { src_ip, src_port, .. } => Ok(Some(uni_addr::UniAddr::from(SocketAddr::V6(
SocketAddrV6::new(*src_ip, *src_port, 0, 0),
)))),
#[cfg(unix)]
Self::Unix { src_addr, .. } => uni_addr::unix::SocketAddr::from_bytes_until_nul(src_addr)
.map(Into::into)
.map(Some),
#[cfg(not(unix))]
Self::Unix { .. } => Err(io::Error::other("The platform does not support UDS addresses.")),
}
}
#[cfg(feature = "feat-uni-addr")]
pub fn dst_uni_addr(&self) -> io::Result<Option<uni_addr::UniAddr>> {
use core::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
match self {
Self::Unspecified => Ok(None),
Self::Inet { dst_ip, dst_port, .. } => Ok(Some(uni_addr::UniAddr::from(SocketAddr::V4(
SocketAddrV4::new(*dst_ip, *dst_port),
)))),
Self::Inet6 { dst_ip, dst_port, .. } => Ok(Some(uni_addr::UniAddr::from(SocketAddr::V6(
SocketAddrV6::new(*dst_ip, *dst_port, 0, 0),
)))),
#[cfg(unix)]
Self::Unix { dst_addr, .. } => uni_addr::unix::SocketAddr::from_bytes_until_nul(dst_addr)
.map(Into::into)
.map(Some),
#[cfg(not(unix))]
Self::Unix { .. } => Err(io::Error::other("The platform does not support UDS addresses.")),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum ExtensionType {
ALPN = 0x01,
Authority = 0x02,
CRC32C = 0x03,
NoOp = 0x04,
UniqueId = 0x05,
NetworkNamespace = 0x30,
}
impl ExtensionType {
#[inline]
const fn from_u8(value: u8) -> Option<Self> {
Some(match value {
v if v == Self::ALPN as u8 => Self::ALPN,
v if v == Self::Authority as u8 => Self::Authority,
v if v == Self::CRC32C as u8 => Self::CRC32C,
v if v == Self::NoOp as u8 => Self::NoOp,
v if v == Self::UniqueId as u8 => Self::UniqueId,
v if v == Self::NetworkNamespace as u8 => Self::NetworkNamespace,
_ => return None,
})
}
}
#[derive(Debug, Clone, Copy)]
pub struct ExtensionRef<'a> {
typ: u8,
#[allow(unused, reason = "XXX")]
len: u16,
payload: &'a [u8],
}
impl<'a> ExtensionRef<'a> {
#[inline]
pub const fn new(typ: ExtensionType, payload: &'a [u8]) -> Option<Self> {
Self::new_custom(typ as u8, payload)
}
#[inline]
pub const fn new_custom(typ: u8, payload: &'a [u8]) -> Option<Self> {
let len = payload.len();
if len > u16::MAX as usize {
return None; }
#[allow(clippy::cast_possible_truncation, reason = "Checked above")]
Some(Self {
typ,
len: len as u16,
payload,
})
}
#[inline]
pub const fn typ(&self) -> Result<ExtensionType, u8> {
match ExtensionType::from_u8(self.typ) {
Some(typ) => Ok(typ),
None => Err(self.typ),
}
}
#[inline]
pub const fn payload(&self) -> &'a [u8] {
self.payload
}
#[inline]
#[cfg(feature = "feat-codec-encode")]
pub(crate) fn encode(&self, buf: &mut Vec<u8>) {
buf.reserve(self.len as usize);
buf.push(self.typ);
buf.extend(&self.len.to_be_bytes());
buf.extend(self.payload);
}
#[inline]
#[cfg(feature = "feat-codec-decode")]
pub(crate) fn decode(reader: &mut Reader<'a>) -> Result<Option<Self>, DecodeError> {
let Ok(typ) = reader.read_u8() else {
return Ok(None);
};
let Ok(len) = reader.read_u16() else {
return Err(DecodeError::MalformedData);
};
let Ok(payload) = reader.read(len as usize) else {
return Err(DecodeError::MalformedData);
};
Ok(Some(Self { typ, len, payload }))
}
}