use std::io;
use clap::Parser;
use supertunnel::io::{CopyError, TransferError, copy_spawn_try_join};
use supertunnel::proto::*;
use supertunnel::util::{DecodedSinkWriter, EncodedStreamReader};
use supertunnel::{FrameSize, Protocol};
use tokio::net::{TcpListener, TcpStream};
#[derive(Parser, Debug)]
#[command(
version,
about = "A server-side proxy forwarding supertunnel client connections to internet destinations"
)]
struct Args {
#[arg(short, long, value_name = "ADDR:PORT", default_value = "0.0.0.0:8080")]
listen: String,
}
#[tokio::main]
async fn main() -> io::Result<()> {
env_logger::init();
let args = Args::parse();
let listener = TcpListener::bind(&args.listen).await?;
log::info!("Listening on {}", args.listen);
let resume_map = ResumptionMap::new();
loop {
let (inbound, _) = listener.accept().await?; let map = resume_map.clone();
tokio::spawn(handle_connection(inbound, map));
}
}
type MapInner = Reliability<RoutingServer<TcpPayload, TcpPayloadFactory>>;
async fn handle_connection(inbound: TcpStream, map: ResumptionMap<MapInner>) {
log::info!(
"New incoming connection {:?} -> {:?}",
inbound.peer_addr(),
inbound.local_addr()
);
let stack_mss = PayloadCodec::mss(RoutingCodec::mss(ReliabilityCodec::mss(
ResumptionCodec::mss(FramingCodec::mss(FramingCodec::mtu())),
)));
let connector = TcpPayloadFactory::new(stack_mss);
let tunnel = RoutingServer::new(connector).await;
let resume = ResumptionServer::new_with(Reliability::new(tunnel), map);
let stack = Framing::new(resume);
let result = transfer(stack, inbound).await;
log::info!("Transfer task completed: {result:?}");
}
async fn transfer<T>(stack: T, net: TcpStream) -> Result<(usize, usize), TransferError<CopyError>>
where
T: Protocol + Send + 'static,
<T as Protocol>::Codec: Send,
<T as Protocol>::Message: Send,
<T as Protocol>::StreamHalf: Unpin + Send,
<T as Protocol>::SinkHalf: Unpin + Send,
{
let (stream, sink) = stack.into_split();
let stack_reader = EncodedStreamReader::<T>::new(stream, T::codec());
let stack_writer = DecodedSinkWriter::<T>::new(sink, T::codec());
let (net_reader, net_writer) = net.into_split();
let (_, result) = copy_spawn_try_join(
stack_reader,
stack_writer,
net_reader,
net_writer,
None,
Some(io::ErrorKind::UnexpectedEof.into()),
)
.await;
result
}