use std::{
fmt::Display,
net::{IpAddr, SocketAddr},
str::FromStr,
};
use serde_with::{DeserializeFromStr, SerializeDisplay};
use crate::{
address::{
ip_addr::ScionIpAddr,
socket_addr::{ScionSocketAddr, ScionSocketAddrV4, ScionSocketAddrV6},
},
core::macros::impl_from,
scion::{
address::{
AddressParseError,
addr::{ScionAddr, ScionAddrV4, ScionAddrV6},
},
identifier::isd_asn::IsdAsn,
},
};
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, SerializeDisplay, DeserializeFromStr,
)]
#[cfg_attr(feature = "proptest", derive(proptest_derive::Arbitrary))]
pub enum ScionSocketIpAddr {
V4(ScionSocketAddrV4),
V6(ScionSocketAddrV6),
}
impl ScionSocketIpAddr {
#[inline]
pub const fn new(isd_asn: IsdAsn, host: IpAddr, port: u16) -> Self {
match host {
IpAddr::V4(host) => {
Self::V4(ScionSocketAddrV4 {
isd_asn,
host,
port,
})
}
IpAddr::V6(host) => {
Self::V6(ScionSocketAddrV6 {
isd_asn,
host,
port,
})
}
}
}
#[inline]
pub const fn from_std(isd_asn: IsdAsn, addr: std::net::SocketAddr) -> Self {
match addr {
SocketAddr::V4(v4) => {
Self::V4(ScionSocketAddrV4 {
isd_asn,
host: *v4.ip(),
port: v4.port(),
})
}
SocketAddr::V6(v6) => {
Self::V6(ScionSocketAddrV6 {
isd_asn,
host: *v6.ip(),
port: v6.port(),
})
}
}
}
#[inline]
pub const fn try_from_scion_addr(scion_addr: ScionAddr, port: u16) -> Result<Self, ScionAddr> {
match scion_addr {
ScionAddr::V4(addr) => {
Ok(Self::V4(ScionSocketAddrV4 {
isd_asn: addr.isd_asn,
host: addr.host,
port,
}))
}
ScionAddr::V6(addr) => {
Ok(Self::V6(ScionSocketAddrV6 {
isd_asn: addr.isd_asn,
host: addr.host,
port,
}))
}
ScionAddr::Svc(_) => Err(scion_addr),
}
}
#[inline]
pub const fn socket_addr(&self) -> SocketAddr {
match self {
ScionSocketIpAddr::V4(addr) => {
SocketAddr::V4(std::net::SocketAddrV4::new(addr.host, addr.port))
}
ScionSocketIpAddr::V6(addr) => {
SocketAddr::V6(std::net::SocketAddrV6::new(addr.host, addr.port, 0, 0))
}
}
}
#[inline]
pub const fn into_scion_sock_addr(self) -> ScionSocketAddr {
match self {
ScionSocketIpAddr::V4(addr) => ScionSocketAddr::V4(addr),
ScionSocketIpAddr::V6(addr) => ScionSocketAddr::V6(addr),
}
}
#[inline]
pub const fn ip(&self) -> IpAddr {
match self {
ScionSocketIpAddr::V4(addr) => IpAddr::V4(addr.host),
ScionSocketIpAddr::V6(addr) => IpAddr::V6(addr.host),
}
}
#[inline]
pub const fn is_ipv4(&self) -> bool {
matches!(self, ScionSocketIpAddr::V4(_))
}
#[inline]
pub const fn is_ipv6(&self) -> bool {
matches!(self, ScionSocketIpAddr::V6(_))
}
#[inline]
pub fn set_ip(&mut self, host: IpAddr) {
*self = Self::new(self.isd_asn(), host, self.port());
}
#[inline]
pub const fn scion_addr(&self) -> ScionAddr {
match self {
ScionSocketIpAddr::V4(addr) => {
ScionAddr::V4(crate::scion::address::addr::ScionAddrV4 {
isd_asn: addr.isd_asn,
host: addr.host,
})
}
ScionSocketIpAddr::V6(addr) => {
ScionAddr::V6(crate::scion::address::addr::ScionAddrV6 {
isd_asn: addr.isd_asn,
host: addr.host,
})
}
}
}
#[inline]
pub const fn scion_ip_addr(&self) -> ScionIpAddr {
match self {
ScionSocketIpAddr::V4(addr) => {
ScionIpAddr::V4(crate::scion::address::addr::ScionAddrV4 {
isd_asn: addr.isd_asn,
host: addr.host,
})
}
ScionSocketIpAddr::V6(addr) => {
ScionIpAddr::V6(crate::scion::address::addr::ScionAddrV6 {
isd_asn: addr.isd_asn,
host: addr.host,
})
}
}
}
#[inline]
pub const fn port(&self) -> u16 {
match self {
ScionSocketIpAddr::V4(addr) => addr.port,
ScionSocketIpAddr::V6(addr) => addr.port,
}
}
#[inline]
pub fn set_port(&mut self, port: u16) {
*self = Self::new(self.isd_asn(), self.ip(), port);
}
#[inline]
pub const fn host(&self) -> ScionIpAddr {
match self {
ScionSocketIpAddr::V4(addr) => {
ScionIpAddr::V4(ScionAddrV4 {
isd_asn: addr.isd_asn,
host: addr.host,
})
}
ScionSocketIpAddr::V6(addr) => {
ScionIpAddr::V6(ScionAddrV6 {
isd_asn: addr.isd_asn,
host: addr.host,
})
}
}
}
#[inline]
pub fn set_host(&mut self, host: ScionIpAddr) {
*self = Self::new(host.isd_asn(), host.ip(), self.port());
}
#[inline]
pub const fn isd_asn(&self) -> IsdAsn {
match self {
ScionSocketIpAddr::V4(addr) => addr.isd_asn,
ScionSocketIpAddr::V6(addr) => addr.isd_asn,
}
}
#[inline]
pub fn set_isd_asn(&mut self, isd_asn: IsdAsn) {
match self {
ScionSocketIpAddr::V4(addr) => addr.isd_asn = isd_asn,
ScionSocketIpAddr::V6(addr) => addr.isd_asn = isd_asn,
}
}
}
impl Display for ScionSocketIpAddr {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ScionSocketIpAddr::V4(addr) => addr.fmt(f),
ScionSocketIpAddr::V6(addr) => addr.fmt(f),
}
}
}
impl FromStr for ScionSocketIpAddr {
type Err = AddressParseError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
ScionSocketAddrV4::from_str(s)
.map(Self::V4)
.or_else(|_| ScionSocketAddrV6::from_str(s).map(Self::V6))
.map_err(|_| AddressParseError::Socket)
}
}
impl_from!(ScionSocketAddrV4, ScionSocketIpAddr, |v| Self::V4(v));
impl_from!(ScionSocketAddrV6, ScionSocketIpAddr, |v| Self::V6(v));
impl TryFrom<ScionAddr> for ScionSocketIpAddr {
type Error = ScionAddr;
#[inline]
fn try_from(value: ScionAddr) -> Result<Self, Self::Error> {
Self::try_from_scion_addr(value, 0)
}
}