use structopt::StructOpt; use tokio::{ net::UdpSocket, sync::watch, }; use ptth_quic::{ client_proxy::{ ForwardingParams, forward_port, }, prelude::*, }; use protocol::PeerId; #[derive (Debug, StructOpt)] struct Opt { #[structopt (long)] relay_addr: Option , #[structopt (long)] client_id: Option , #[structopt (long)] server_id: Option , #[structopt (long)] client_tcp_port: Option , #[structopt (long)] server_tcp_port: Option , } #[tokio::main] async fn main () -> anyhow::Result <()> { tracing_subscriber::fmt::init (); let opt = Opt::from_args (); let conf = opt.into_config ().await?; let client = P2Client::connect (conf)?; client.run ().await?; Ok (()) } pub struct P2Client { endpoint: quinn::Endpoint, conf: Arc , } impl P2Client { pub fn connect (conf: Config) -> anyhow::Result { let endpoint = make_client_endpoint ("0.0.0.0:0".parse ()?, &[&conf.relay_cert])?; let conf = Arc::new (conf); Ok (Self { endpoint, conf, }) } pub async fn run (&self) -> anyhow::Result <()> { debug! ("P2 client connecting to P3 relay server"); let conf = Arc::clone (&self.conf); let quinn::NewConnection { connection, .. } = protocol::p2_connect_to_p3 (&self.endpoint, conf.relay_addr, &conf.client_id).await?; let client_tcp_port = conf.client_tcp_port; debug! ("Accepting local TCP connections from P1 at {}", client_tcp_port); // End of per-port stuff // Beginning of per-connection stuff let (_shutdown_flag_tx, shutdown_flag_rx) = watch::channel (true); let task_tcp_server = { let connection = connection.clone (); let server_id = conf.server_id.clone (); let server_tcp_port = conf.server_tcp_port; let listener = TcpListener::bind (("127.0.0.1", client_tcp_port)).await?; trace! ("Accepting local TCP connections from P1 on {}", client_tcp_port); tokio::spawn (async move { forward_port ( listener, connection, ForwardingParams { client_tcp_port, server_id, server_tcp_port, }, shutdown_flag_rx, ).await?; Ok::<_, anyhow::Error> (()) }) }; if false { let task_direc_connect = { let connection = connection.clone (); tokio::spawn (async move { let cookie = protocol::p2_direc_to_p4 ( &connection, "bogus_server", ).await?; let sock = UdpSocket::bind ("0.0.0.0:0").await?; let mut interval = tokio::time::interval (Duration::from_millis (1000)); interval.set_missed_tick_behavior (tokio::time::MissedTickBehavior::Delay); loop { interval.tick ().await; sock.send_to(&cookie [..], "127.0.0.1:30379").await?; debug! ("P2 sent cookie to P3 over plain UDP"); } Ok::<_, anyhow::Error> (()) }) }; } task_tcp_server.await??; //task_direc_connect.await??; Ok (()) } } /// A filled-out config for constructing a P2 client #[derive (Clone)] pub struct Config { client_tcp_port: u16, server_tcp_port: u16, client_id: String, server_id: String, relay_addr: SocketAddr, relay_cert: Vec , } impl Opt { pub async fn into_config (self) -> anyhow::Result { let client_tcp_port = self.client_tcp_port.unwrap_or (30381); let server_tcp_port = self.server_tcp_port.unwrap_or (30382); let client_id = self.client_id.unwrap_or_else (|| "bogus_client".to_string ()); let server_id = self.server_id.unwrap_or_else (|| "bogus_server".to_string ()); let relay_addr = self.relay_addr.unwrap_or_else (|| String::from ("127.0.0.1:30380")).parse ()?; // Begin I/O let relay_cert = tokio::fs::read ("ptth_quic_output/quic_server.crt").await?; Ok (Config { client_tcp_port, server_tcp_port, client_id, server_id, relay_addr, relay_cert, }) } }