use std::{fs, net::SocketAddr, path::PathBuf}; use anyhow::{Context, Result}; use clap::Parser; use lanparty_client_core::{ClientSessionConfig, connect_client}; use lanparty_ctrl::RoomCode; use lanparty_proto::MacAddr; #[derive(Debug, Parser)] #[command( name = "lanparty-client-win", about = "Windows TAP client for the LAN party L2 tunnel" )] struct ClientArgs { /// Relay UDP socket address, for example 203.0.113.10:443. #[arg(long)] relay: SocketAddr, /// TLS server name expected in the relay certificate. #[arg(long, default_value = "lanparty-relay.local")] server_name: String, /// DER-encoded relay CA/certificate to trust. #[arg(long, value_name = "PATH")] relay_ca_cert: PathBuf, /// Room code to join as a remote client. #[arg(long)] room: RoomCode, /// Locally administered unicast MAC address assigned to the TAP adapter. #[arg(long)] virtual_mac: MacAddr, /// Client's advertised QUIC datagram budget before relay clamping. #[arg(long, default_value_t = 1400)] max_datagram_size: u16, } impl ClientArgs { fn into_config(self) -> Result { let relay_ca_cert = fs::read(&self.relay_ca_cert).with_context(|| { format!( "failed to read relay CA certificate {}", self.relay_ca_cert.display() ) })?; ClientSessionConfig::new( self.relay, self.server_name, relay_ca_cert, self.room, self.virtual_mac, self.max_datagram_size, ) } } #[tokio::main] async fn main() -> Result<()> { let config = ClientArgs::parse().into_config()?; println!( "lanparty-client-win connecting virtual MAC {} to relay {} room {}", config.virtual_mac(), config.relay_addr(), config.room() ); let session = connect_client(config).await?; println!( "lanparty-client-win connected as peer {} in room id {} with TAP MTU {}", session.welcome().peer_id(), session.welcome().room_id(), session.welcome().effective_tap_mtu() ); println!("Windows TAP binding and route pinning are not wired yet; press Ctrl-C to stop"); tokio::signal::ctrl_c() .await .context("failed to wait for Ctrl-C")?; session.shutdown("client shutting down").await; Ok(()) }