use std::io;
use std::net::SocketAddr;
use gotatun::packet::{Packet, PacketBufPool};
use gotatun::udp::socket::{UdpSocket, UdpSocketFactory};
use gotatun::udp::{UdpRecv, UdpTransportFactory, UdpTransportFactoryParams};
#[derive(Debug, Default)]
pub struct UdpFactory(UdpSocketFactory);
impl UdpTransportFactory for UdpFactory {
type Send = UdpSocket;
type Recv = SkipResets<UdpSocket>;
async fn bind(
&mut self,
params: &UdpTransportFactoryParams,
) -> io::Result<(Self::Send, Self::Recv)> {
let (send, recv) = self.0.bind(params).await?;
Ok((send, SkipResets(recv)))
}
}
#[derive(Debug)]
pub struct SkipResets<R>(R);
impl<R: UdpRecv> UdpRecv for SkipResets<R> {
type RecvManyBuf = ();
async fn recv_from(&mut self, pool: &mut PacketBufPool) -> io::Result<(Packet, SocketAddr)> {
loop {
match self.0.recv_from(pool).await {
Err(error) if error.kind() == io::ErrorKind::ConnectionReset => continue,
other => return other,
}
}
}
fn enable_udp_gro(&self) -> io::Result<()> {
self.0.enable_udp_gro()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::VecDeque;
struct Scripted(VecDeque<io::Result<()>>);
impl UdpRecv for Scripted {
type RecvManyBuf = ();
async fn recv_from(
&mut self,
pool: &mut PacketBufPool,
) -> io::Result<(Packet, SocketAddr)> {
let next = self.0.pop_front().expect("no more scripted results");
next.map(|()| (pool.get(), "192.0.2.10:51820".parse().unwrap()))
}
}
fn receive(script: Vec<io::Result<()>>) -> (io::Result<SocketAddr>, usize) {
let mut socket = SkipResets(Scripted(script.into()));
let mut pool = PacketBufPool::new(1);
let result = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap()
.block_on(socket.recv_from(&mut pool))
.map(|(_, from)| from);
(result, socket.0.0.len())
}
fn reset() -> io::Result<()> {
Err(io::ErrorKind::ConnectionReset.into())
}
#[test]
fn connection_resets_are_skipped_until_a_packet_arrives() {
let (result, left) = receive(vec![reset(), reset(), Ok(()), reset()]);
assert_eq!(result.unwrap(), "192.0.2.10:51820".parse().unwrap());
assert_eq!(left, 1, "it read past the packet");
}
#[test]
fn other_errors_still_end_the_receive() {
let (result, _) = receive(vec![reset(), Err(io::ErrorKind::PermissionDenied.into())]);
assert_eq!(result.unwrap_err().kind(), io::ErrorKind::PermissionDenied);
}
}