#![feature(yeet_expr)] #![feature(cursor_remaining)] use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use num_enum::{TryFromPrimitive, TryFromPrimitiveError}; use std::{ cell::Cell, fmt, io::{self, Write}, net, sync::{mpsc, Arc}, thread, }; pub const PROTO_ID: u32 = 0x4f457403; pub const UDP_PKT_SIZE: usize = 512; pub const NUM_CHANNELS: usize = 3; pub const REL_BUFFER: usize = 0x8000; pub const INIT_SEQNUM: u16 = 65500; #[derive(Debug, Copy, Clone, PartialEq)] pub enum PeerID { Nil = 0, Srv, CltMin, } #[derive(Debug, Copy, Clone, PartialEq, TryFromPrimitive)] #[repr(u8)] pub enum PktType { Ctl = 0, Orig, Split, Rel, } #[derive(Debug)] pub struct Pkt { unrel: bool, chan: u8, data: T, } #[derive(Debug)] pub enum Error { IoError(io::Error), InvalidProtoId(u32), InvalidPeerID, InvalidChannel(u8), InvalidType(u8), LocalHangup, } impl From for Error { fn from(err: io::Error) -> Self { Self::IoError(err) } } impl From> for Error { fn from(err: TryFromPrimitiveError) -> Self { Self::InvalidType(err.number) } } impl From> for Error { fn from(err: mpsc::SendError) -> Self { Self::LocalHangup } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use Error::*; write!(f, "RUDP Error: ")?; match self { IoError(err) => write!(f, "IO Error: {}", err), InvalidProtoId(id) => write!(f, "Invalid Protocol ID: {id}"), InvalidPeerID => write!(f, "Invalid Peer ID"), InvalidChannel(ch) => write!(f, "Invalid Channel: {ch}"), InvalidType(tp) => write!(f, "Invalid Type: {tp}"), LocalHangup => write!(f, "Local packet receiver hung up"), } } } #[derive(Debug)] struct Channel {} #[derive(Debug)] struct RecvChannel<'a> { packets: Vec>>, // used to be called char ** seqnum: u16, chan: &'a Channel, } pub type PktResult = Result>, Error>; type PktSender = mpsc::Sender; #[derive(Debug)] struct ConnInner { sock: net::UdpSocket, id: u16, remote_id: u16, chans: Vec, } impl ConnInner { pub fn send(&self, pkt: Pkt<&[u8]>) -> io::Result<()> { let mut buf = Vec::with_capacity(4 + 2 + 1 + 1 + pkt.data.len()); buf.write_u32::(PROTO_ID)?; buf.write_u16::(self.remote_id)?; buf.write_u8(pkt.chan as u8)?; buf.write_u8(PktType::Orig as u8)?; buf.write(pkt.data)?; self.sock.send(&buf)?; Ok(()) } fn recv_loop(&self, tx: PktSender) { let mut inbox = [0; UDP_PKT_SIZE]; let mut recv_chans = self.channels.map(|chan| RecvChannel { chan, packets: (0..REL_BUFFER).map(|_| Cell::new(None)), seqnum: INIT_SEQNUM, }); loop { if let Err(err) = self.recv_pkt(&mut inbox, &mut recv_chans, &tx) { if !tx.send(Err(err)).is_ok() { break; } } } } fn recv_pkt( &self, buffer: &mut [u8], chans: &mut Vec, tx: &PktSender, ) -> Result<(), Error> { use Error::*; use PktType::*; // todo: reset timeout let len = self.sock.recv(buffer)?; let mut cursor = io::Cursor::new(&buffer[..len]); let proto_id = cursor.read_u32::()?; if proto_id != PROTO_ID { do yeet InvalidProtoId(proto_id); } let peer_id = cursor.read_u16::()?; let n_channel = cursor.read_u8()?; let mut channel = self .chans .get_mut(n_channel as usize) .ok_or(InvalidChannel(n_channel))?; self.process_pkt(cursor, channel); } fn process_pkt( &self, mut cursor: io::Cursor<&[u8]>, chan: &mut RecvChannel, ) -> Result<(), Error> { match cursor.read_u8()?.try_into()? { Ctl => { dbg!(cursor.remaining_slice()); } Orig => { tx.send(Ok(Pkt { chan: n_channel, unrel: true, data: cursor.remaining_slice().into(), }))?; } Split => { dbg!(cursor.remaining_slice()); } Rel => { let seqnum = cursor.read_u16::()?; chan.packets[seqnum].set(cursor.remaining_slice().into()); while Some(pkt) = chan.packets[chan.seqnum].take() { self.process_pkt(io::Cursor::new(&pkt), chan)?; chan.seqnum.overflowing_add(1); } } } Ok(()) } } #[derive(Debug)] pub struct Conn { inner: Arc, rx: mpsc::Receiver, } impl Conn { pub fn connect(addr: &str) -> io::Result { let (tx, rx) = mpsc::channel(); let inner = Arc::new(ConnInner { sock: net::UdpSocket::bind("0.0.0.0:0")?, id: PeerID::Srv as u16, remote_id: PeerID::Nil as u16, chans: (0..NUM_CHANNELS).map(|_| Channel {}).collect(), }); inner.sock.connect(addr)?; let recv_inner = Arc::clone(&inner); thread::spawn(move || { recv_inner.recv_loop(tx); }); Ok(Conn { inner, rx }) } pub fn send(&self, pkt: Pkt<&[u8]>) -> io::Result<()> { self.inner.send(pkt) } pub fn recv(&self) -> Result { self.rx.recv() } } fn main() { //println!("{}", x.deep_size_of()); let conn = Conn::connect("127.0.0.1:30000").expect("the spanish inquisition"); let mut mtpkt = vec![]; mtpkt.write_u16::(2).unwrap(); // high level type mtpkt.write_u8(29).unwrap(); // serialize ver mtpkt.write_u16::(0).unwrap(); // compression modes mtpkt.write_u16::(40).unwrap(); // MinProtoVer mtpkt.write_u16::(40).unwrap(); // MaxProtoVer mtpkt.write_u16::(3).unwrap(); // player name length mtpkt.write(b"foo").unwrap(); // player name conn.send(Pkt { unrel: true, chan: 1, data: &mtpkt, }) .unwrap(); while let Ok(result) = conn.recv() { match result { Ok(pkt) => { io::stdout().write(pkt.data.as_slice()).unwrap(); } Err(err) => eprintln!("Error: {}", err), } } }