use tokio::sync::watch;
use crate::packet::{Ip, Packet, PacketBufPool};
use std::future::{Future, pending};
use std::io;
pub mod buffer;
pub mod channel;
#[cfg(feature = "pcap")]
pub mod pcap;
#[cfg(feature = "tun")]
pub mod tun_async_device;
pub trait IpSend: Send + Sync + 'static {
fn send(&mut self, packet: Packet<Ip>) -> impl Future<Output = io::Result<()>> + Send;
}
pub trait IpRecv: Send + Sync + 'static {
fn recv<'a>(
&'a mut self,
pool: &mut PacketBufPool,
) -> impl Future<Output = io::Result<impl Iterator<Item = Packet<Ip>> + Send + 'a>> + Send;
fn mtu(&self) -> MtuWatcher;
}
#[derive(Clone)]
pub struct MtuWatcher {
mtu_source: MtuSource,
modifier: i32,
}
#[derive(Clone)]
enum MtuSource {
Constant(u16),
Watch(watch::Receiver<u16>),
}
impl MtuWatcher {
pub const fn new(mtu: u16) -> Self {
Self {
mtu_source: MtuSource::Constant(mtu),
modifier: 0,
}
}
pub fn get(&mut self) -> u16 {
let mtu = match &mut self.mtu_source {
MtuSource::Constant(mtu) => *mtu,
MtuSource::Watch(mtu_rx) => *mtu_rx.borrow_and_update(),
};
i32::from(mtu)
.checked_add(self.modifier)
.and_then(|int| u16::try_from(int).ok())
.expect("MTU over/underflow")
}
pub async fn wait(&mut self) -> u16 {
match &mut self.mtu_source {
MtuSource::Constant(_) => return pending().await,
MtuSource::Watch(mtu_rx) => {
if mtu_rx.changed().await.is_err() {
return pending().await;
}
}
}
self.get()
}
pub fn increase(self, value: u16) -> Option<Self> {
Some(Self {
modifier: self.modifier.checked_add(i32::from(value))?,
..self
})
}
pub fn decrease(self, value: u16) -> Option<Self> {
Some(Self {
modifier: self.modifier.checked_sub(i32::from(value))?,
..self
})
}
}
impl From<watch::Receiver<u16>> for MtuWatcher {
fn from(mtu_rx: watch::Receiver<u16>) -> Self {
Self {
mtu_source: MtuSource::Watch(mtu_rx),
modifier: 0,
}
}
}