diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..d5f96e3 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,68 @@ +use std::net::SocketAddr; + +use clap::Parser; +use tokio::{io::{AsyncReadExt, AsyncWriteExt}, net::UdpSocket}; + +#[derive(Parser)] +struct CliArgs { + server: String, +} + +#[tokio::main] +async fn main() { + let args = CliArgs::parse(); + + let dest : SocketAddr = args.server.parse().unwrap(); + + // by default bind on any interface and request OS to give us a port + let mut addr : SocketAddr = "0.0.0.0:0".parse().unwrap(); + let socket = UdpSocket::bind(addr).await.unwrap(); + + + let packet = PingPacket { id: 0, time: chrono::Utc::now().timestamp_micros() as u64 }; + let buf = packet.serialize().await.unwrap(); + + socket.send_to(&buf, dest).await.unwrap(); + + let mut buf = [0u8; 1024]; + socket.recv(&mut buf).await.unwrap(); + + let pong = PongPacket::deserialize(&buf).await.unwrap(); + + println!("{pong:#?}"); +} + +struct PingPacket { + id: i32, + time: u64, +} + +impl PingPacket { + async fn serialize(self) -> std::io::Result> { + let mut out = Vec::new(); + out.write_i32(self.id).await?; + out.write_u64(self.time).await?; + Ok(out) + } +} + + +#[derive(Debug)] +struct PongPacket { + version: u32, + time: u64, + users: i32, + max_users: i32, + bandwidth: i32, +} + +impl PongPacket { + async fn deserialize(mut data: &[u8]) -> std::io::Result { + let version = data.read_u32().await?; + let time = data.read_u64().await?; + let users = data.read_i32().await?; + let max_users = data.read_i32().await?; + let bandwidth = data.read_i32().await?; + Ok(PongPacket { version, time, users, max_users, bandwidth }) + } +}