]> git.lizzy.rs Git - mt_rudp.git/blob - src/main.rs
aadb5ccd3fccea83724ff8debd81fbbddfc8a75e
[mt_rudp.git] / src / main.rs
1 #![feature(yeet_expr)]
2 #![feature(cursor_remaining)]
3 #![feature(hash_drain_filter)]
4 mod client;
5 pub mod error;
6 mod recv_worker;
7
8 use byteorder::{BigEndian, WriteBytesExt};
9 pub use client::{connect, Sender as Client};
10 use num_enum::TryFromPrimitive;
11 use std::{
12     io::{self, Write},
13     ops,
14     sync::{mpsc, Arc},
15     thread,
16 };
17
18 pub const PROTO_ID: u32 = 0x4f457403;
19 pub const UDP_PKT_SIZE: usize = 512;
20 pub const NUM_CHANS: usize = 3;
21 pub const REL_BUFFER: usize = 0x8000;
22 pub const INIT_SEQNUM: u16 = 65500;
23 pub const TIMEOUT: u64 = 30;
24
25 pub trait UdpSender: Send + Sync + 'static {
26     fn send(&self, data: Vec<u8>) -> io::Result<()>;
27 }
28
29 pub trait UdpReceiver: Send + Sync + 'static {
30     fn recv(&self) -> io::Result<Vec<u8>>;
31 }
32
33 #[derive(Debug, Copy, Clone)]
34 pub enum PeerID {
35     Nil = 0,
36     Srv,
37     CltMin,
38 }
39
40 #[derive(Debug, Copy, Clone, PartialEq, TryFromPrimitive)]
41 #[repr(u8)]
42 pub enum PktType {
43     Ctl = 0,
44     Orig,
45     Split,
46     Rel,
47 }
48
49 #[derive(Debug, Copy, Clone, PartialEq, TryFromPrimitive)]
50 #[repr(u8)]
51 pub enum CtlType {
52     Ack = 0,
53     SetPeerID,
54     Ping,
55     Disco,
56 }
57
58 #[derive(Debug)]
59 pub struct Pkt<T> {
60     unrel: bool,
61     chan: u8,
62     data: T,
63 }
64
65 pub type Error = error::Error;
66 pub type InPkt = Result<Pkt<Vec<u8>>, Error>;
67
68 #[derive(Debug)]
69 pub struct AckChan;
70
71 #[derive(Debug)]
72 pub struct RudpShare<S: UdpSender> {
73     pub id: u16,
74     pub remote_id: u16,
75     pub chans: Vec<AckChan>,
76     udp_tx: S,
77 }
78
79 #[derive(Debug)]
80 pub struct RudpReceiver<S: UdpSender> {
81     share: Arc<RudpShare<S>>,
82     pkt_rx: mpsc::Receiver<InPkt>,
83 }
84
85 #[derive(Debug)]
86 pub struct RudpSender<S: UdpSender> {
87     share: Arc<RudpShare<S>>,
88 }
89
90 impl<S: UdpSender> RudpShare<S> {
91     pub fn send(&self, tp: PktType, pkt: Pkt<&[u8]>) -> io::Result<()> {
92         let mut buf = Vec::with_capacity(4 + 2 + 1 + 1 + pkt.data.len());
93         buf.write_u32::<BigEndian>(PROTO_ID)?;
94         buf.write_u16::<BigEndian>(self.remote_id)?;
95         buf.write_u8(pkt.chan as u8)?;
96         buf.write_u8(tp as u8)?;
97         buf.write(pkt.data)?;
98
99         self.udp_tx.send(buf)?;
100
101         Ok(())
102     }
103 }
104
105 impl<S: UdpSender> RudpSender<S> {
106     pub fn send(&self, pkt: Pkt<&[u8]>) -> io::Result<()> {
107         self.share.send(PktType::Orig, pkt) // TODO
108     }
109 }
110
111 impl<S: UdpSender> ops::Deref for RudpReceiver<S> {
112     type Target = mpsc::Receiver<InPkt>;
113
114     fn deref(&self) -> &Self::Target {
115         &self.pkt_rx
116     }
117 }
118
119 pub fn new<S: UdpSender, R: UdpReceiver>(
120     id: u16,
121     remote_id: u16,
122     udp_tx: S,
123     udp_rx: R,
124 ) -> (RudpSender<S>, RudpReceiver<S>) {
125     let (pkt_tx, pkt_rx) = mpsc::channel();
126
127     let share = Arc::new(RudpShare {
128         id,
129         remote_id,
130         udp_tx,
131         chans: (0..NUM_CHANS).map(|_| AckChan).collect(),
132     });
133     let recv_share = Arc::clone(&share);
134
135     thread::spawn(|| {
136         recv_worker::RecvWorker::new(udp_rx, recv_share, pkt_tx).run();
137     });
138
139     (
140         RudpSender {
141             share: Arc::clone(&share),
142         },
143         RudpReceiver { share, pkt_rx },
144     )
145 }
146
147 // connect
148
149 fn main() -> io::Result<()> {
150     //println!("{}", x.deep_size_of());
151     let (tx, rx) = connect("127.0.0.1:30000")?;
152
153     let mut mtpkt = vec![];
154     mtpkt.write_u16::<BigEndian>(2)?; // high level type
155     mtpkt.write_u8(29)?; // serialize ver
156     mtpkt.write_u16::<BigEndian>(0)?; // compression modes
157     mtpkt.write_u16::<BigEndian>(40)?; // MinProtoVer
158     mtpkt.write_u16::<BigEndian>(40)?; // MaxProtoVer
159     mtpkt.write_u16::<BigEndian>(3)?; // player name length
160     mtpkt.write(b"foo")?; // player name
161
162     tx.send(Pkt {
163         unrel: true,
164         chan: 1,
165         data: &mtpkt,
166     })?;
167
168     while let Ok(result) = rx.recv() {
169         match result {
170             Ok(pkt) => {
171                 io::stdout().write(pkt.data.as_slice())?;
172             }
173             Err(err) => eprintln!("Error: {}", err),
174         }
175     }
176     println!("disco");
177
178     Ok(())
179 }