use std::{io, net::SocketAddr, sync::Arc};
use scion_proto::{
address::IsdAsn,
packet::ScionPacketRaw,
wire_encoding::{WireDecode, WireEncodeVec},
};
use tokio::net::UdpSocket;
#[derive(Debug, Clone)]
pub struct ExternalAsConnection {
isd_as: IsdAsn,
socket: Arc<UdpSocket>,
peer_addr: SocketAddr,
}
impl ExternalAsConnection {
pub fn new(
isd_as: IsdAsn,
socket: UdpSocket,
upstream_addr: SocketAddr,
) -> ExternalAsConnection {
ExternalAsConnection {
isd_as,
socket: Arc::new(socket),
peer_addr: upstream_addr,
}
}
#[expect(unused)]
pub async fn send(&self, send_msg: ScionPacketRaw) -> io::Result<usize> {
let bytes: Vec<u8> = send_msg.encode_to_bytes_vec().concat();
self.socket.send_to(&bytes, self.peer_addr).await
}
pub fn try_send(&self, send_msg: ScionPacketRaw) -> io::Result<usize> {
let bytes: Vec<u8> = send_msg.encode_to_bytes_vec().concat();
self.socket.try_send_to(&bytes, self.peer_addr)
}
fn check_recv(&self, buf: &[u8], recv_addr: SocketAddr) -> io::Result<ScionPacketRaw> {
let recv_ip = recv_addr.ip();
let peer_ip = self.peer_addr.ip();
if recv_ip != peer_ip {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"Received packet from unexpected IP address {}, expected {}",
recv_ip, peer_ip
),
));
}
let packet = ScionPacketRaw::decode(&mut &buf[..])
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
Ok(packet)
}
pub async fn recv(&self, buf: &mut [u8]) -> io::Result<ScionPacketRaw> {
loop {
let (size, recv_addr) = self.socket.recv_from(buf).await?;
match self.check_recv(&buf[..size], recv_addr) {
Ok(pkt) => return Ok(pkt),
Err(e) => {
tracing::warn!(
error = ?e,
"Received invalid packet from External Interface {}, ignoring packet and continuing to receive",
self.isd_as
);
}
}
}
}
#[expect(unused)]
pub fn try_recv(&self, buf: &mut [u8]) -> io::Result<ScionPacketRaw> {
let (size, recv_addr) = self.socket.try_recv_from(buf)?;
self.check_recv(&buf[..size], recv_addr)
}
pub fn peer_addr(&self) -> SocketAddr {
self.peer_addr
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.socket.local_addr()
}
}