use std::{ net::{ Ipv4Addr, SocketAddrV4, }, sync::Arc, }; use tokio::{ net::{ TcpListener, TcpStream, UdpSocket, }, spawn, }; use crate::loops; #[derive (Clone)] pub struct Config { /// The well-known TCP port that the UDP-over-TCP server will bind pub tcp_port: u16, /// The well-known UDP port that the PTTH_QUIC relay will bind pub udp_port: u16, } pub async fn main (cfg: Config) -> anyhow::Result <()> { let tcp_listener = TcpListener::bind ((Ipv4Addr::UNSPECIFIED, cfg.tcp_port)).await?; loop { let (conn, _peer_addr) = tcp_listener.accept ().await?; let cfg = cfg.clone (); spawn (handle_connection (cfg, conn)); } } async fn handle_connection (cfg: Config, conn: TcpStream) -> anyhow::Result <()> { let udp_sock = UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, 0)).await?; udp_sock.connect ((Ipv4Addr::LOCALHOST, cfg.udp_port)).await?; let (tcp_read, tcp_write) = conn.into_split (); let rx_task; let tx_task; { let udp_sock = Arc::new (udp_sock); rx_task = spawn (loops::rx (Arc::clone (&udp_sock), tcp_read)); tx_task = spawn (loops::tx (Arc::clone (&udp_sock), tcp_write)); } tokio::select! { _val = tx_task => { println! ("server_handle_connection: tx_task exited, exiting"); } _val = rx_task => { println! ("server_handle_connection: rx_task exited, exiting"); } } Ok (()) }