use std::{ net::{ Ipv4Addr, SocketAddr, SocketAddrV4, }, sync::Arc, }; use tokio::{ net::{ TcpSocket, UdpSocket, }, spawn, }; use crate::loops; pub struct Config { pub udp_eph_port: u16, pub udp_local_server_port: u16, pub tcp_server_port: u16, } pub async fn main (cfg: Config) -> anyhow::Result <()> { let udp_sock = UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, cfg.udp_local_server_port)).await?; udp_sock.connect ((Ipv4Addr::LOCALHOST, cfg.udp_eph_port)).await?; let tcp_sock = TcpSocket::new_v4 ()?; let tcp_conn = tcp_sock.connect (SocketAddr::V4 (SocketAddrV4::new (Ipv4Addr::LOCALHOST, cfg.tcp_server_port))).await?; let (tcp_read, tcp_write) = tcp_conn.into_split (); let tx_task; let rx_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! ("client_main: tx_task exited, exiting"); } _val = rx_task => { println! ("client_main: rx_task exited, exiting"); } } Ok (()) }