webrtc_util/vnet/
chunk.rs

1#[cfg(test)]
2mod chunk_test;
3
4use std::fmt;
5use std::net::{IpAddr, SocketAddr};
6use std::ops::{BitAnd, BitOr};
7use std::str::FromStr;
8use std::sync::atomic::Ordering;
9use std::time::SystemTime;
10
11use portable_atomic::AtomicU64;
12
13use super::net::*;
14use crate::error::Result;
15
16lazy_static! {
17    static ref TAG_CTR: AtomicU64 = AtomicU64::new(0);
18}
19
20/// Encodes a u64 value to a lowercase base 36 string.
21pub fn base36(value: impl Into<u64>) -> String {
22    let mut digits: Vec<u8> = vec![];
23
24    let mut value = value.into();
25    while value > 0 {
26        let digit = (value % 36) as usize;
27        value /= 36;
28
29        digits.push(b"0123456789abcdefghijklmnopqrstuvwxyz"[digit]);
30    }
31
32    digits.reverse();
33    format!("{:0>8}", String::from_utf8(digits).unwrap())
34}
35
36// Generate a base36-encoded unique tag
37// See: https://play.golang.org/p/0ZaAID1q-HN
38fn assign_chunk_tag() -> String {
39    let n = TAG_CTR.fetch_add(1, Ordering::SeqCst);
40    base36(n)
41}
42
43#[derive(Copy, Clone, PartialEq, Debug)]
44pub(crate) struct TcpFlag(pub(crate) u8);
45
46pub(crate) const TCP_FLAG_ZERO: TcpFlag = TcpFlag(0x00);
47pub(crate) const TCP_FLAG_FIN: TcpFlag = TcpFlag(0x01);
48pub(crate) const TCP_FLAG_SYN: TcpFlag = TcpFlag(0x02);
49pub(crate) const TCP_FLAG_RST: TcpFlag = TcpFlag(0x04);
50pub(crate) const TCP_FLAG_PSH: TcpFlag = TcpFlag(0x08);
51pub(crate) const TCP_FLAG_ACK: TcpFlag = TcpFlag(0x10);
52
53impl BitOr for TcpFlag {
54    type Output = Self;
55
56    // rhs is the "right-hand side" of the expression `a | b`
57    fn bitor(self, rhs: Self) -> Self::Output {
58        Self(self.0 | rhs.0)
59    }
60}
61
62impl BitAnd for TcpFlag {
63    type Output = Self;
64
65    // rhs is the "right-hand side" of the expression `a & b`
66    fn bitand(self, rhs: Self) -> Self::Output {
67        Self(self.0 & rhs.0)
68    }
69}
70
71impl fmt::Display for TcpFlag {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        let mut sa = vec![];
74        if *self & TCP_FLAG_FIN != TCP_FLAG_ZERO {
75            sa.push("FIN");
76        }
77        if *self & TCP_FLAG_SYN != TCP_FLAG_ZERO {
78            sa.push("SYN");
79        }
80        if *self & TCP_FLAG_RST != TCP_FLAG_ZERO {
81            sa.push("RST");
82        }
83        if *self & TCP_FLAG_PSH != TCP_FLAG_ZERO {
84            sa.push("PSH");
85        }
86        if *self & TCP_FLAG_ACK != TCP_FLAG_ZERO {
87            sa.push("ACK");
88        }
89
90        write!(f, "{}", sa.join("-"))
91    }
92}
93
94// Chunk represents a packet passed around in the vnet
95pub trait Chunk: fmt::Display + fmt::Debug {
96    fn set_timestamp(&mut self) -> SystemTime; // used by router
97    fn get_timestamp(&self) -> SystemTime; // used by router
98    fn get_source_ip(&self) -> IpAddr; // used by routee
99    fn get_destination_ip(&self) -> IpAddr; // used by router
100    fn set_source_addr(&mut self, address: &str) -> Result<()>; // used by nat
101    fn set_destination_addr(&mut self, address: &str) -> Result<()>; // used by nat
102
103    fn source_addr(&self) -> SocketAddr;
104    fn destination_addr(&self) -> SocketAddr;
105    fn user_data(&self) -> Vec<u8>;
106    fn tag(&self) -> String;
107    fn network(&self) -> String; // returns "udp" or "tcp"
108    fn clone_to(&self) -> Box<dyn Chunk + Send + Sync>;
109}
110
111#[derive(PartialEq, Debug)]
112pub(crate) struct ChunkIp {
113    pub(crate) timestamp: SystemTime,
114    pub(crate) source_ip: IpAddr,
115    pub(crate) destination_ip: IpAddr,
116    pub(crate) tag: String,
117}
118
119impl ChunkIp {
120    fn set_timestamp(&mut self) -> SystemTime {
121        self.timestamp = SystemTime::now();
122        self.timestamp
123    }
124
125    fn get_timestamp(&self) -> SystemTime {
126        self.timestamp
127    }
128
129    fn get_destination_ip(&self) -> IpAddr {
130        self.destination_ip
131    }
132
133    fn get_source_ip(&self) -> IpAddr {
134        self.source_ip
135    }
136
137    fn tag(&self) -> String {
138        self.tag.clone()
139    }
140}
141
142#[derive(PartialEq, Debug)]
143pub(crate) struct ChunkUdp {
144    pub(crate) chunk_ip: ChunkIp,
145    pub(crate) source_port: u16,
146    pub(crate) destination_port: u16,
147    pub(crate) user_data: Vec<u8>,
148}
149
150impl fmt::Display for ChunkUdp {
151    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152        write!(
153            f,
154            "{} chunk {} {} => {}",
155            self.network(),
156            self.tag(),
157            self.source_addr(),
158            self.destination_addr(),
159        )
160    }
161}
162
163impl Chunk for ChunkUdp {
164    fn set_timestamp(&mut self) -> SystemTime {
165        self.chunk_ip.set_timestamp()
166    }
167
168    fn get_timestamp(&self) -> SystemTime {
169        self.chunk_ip.get_timestamp()
170    }
171
172    fn get_destination_ip(&self) -> IpAddr {
173        self.chunk_ip.get_destination_ip()
174    }
175
176    fn get_source_ip(&self) -> IpAddr {
177        self.chunk_ip.get_source_ip()
178    }
179
180    fn tag(&self) -> String {
181        self.chunk_ip.tag()
182    }
183
184    fn source_addr(&self) -> SocketAddr {
185        SocketAddr::new(self.chunk_ip.source_ip, self.source_port)
186    }
187
188    fn destination_addr(&self) -> SocketAddr {
189        SocketAddr::new(self.chunk_ip.destination_ip, self.destination_port)
190    }
191
192    fn user_data(&self) -> Vec<u8> {
193        self.user_data.clone()
194    }
195
196    fn clone_to(&self) -> Box<dyn Chunk + Send + Sync> {
197        Box::new(ChunkUdp {
198            chunk_ip: ChunkIp {
199                timestamp: self.chunk_ip.timestamp,
200                source_ip: self.chunk_ip.source_ip,
201                destination_ip: self.chunk_ip.destination_ip,
202                tag: self.chunk_ip.tag.clone(),
203            },
204            source_port: self.source_port,
205            destination_port: self.destination_port,
206            user_data: self.user_data.clone(),
207        })
208    }
209
210    fn network(&self) -> String {
211        UDP_STR.to_owned()
212    }
213
214    fn set_source_addr(&mut self, address: &str) -> Result<()> {
215        let addr = SocketAddr::from_str(address)?;
216        self.chunk_ip.source_ip = addr.ip();
217        self.source_port = addr.port();
218        Ok(())
219    }
220
221    fn set_destination_addr(&mut self, address: &str) -> Result<()> {
222        let addr = SocketAddr::from_str(address)?;
223        self.chunk_ip.destination_ip = addr.ip();
224        self.destination_port = addr.port();
225        Ok(())
226    }
227}
228
229impl ChunkUdp {
230    pub(crate) fn new(src_addr: SocketAddr, dst_addr: SocketAddr) -> Self {
231        ChunkUdp {
232            chunk_ip: ChunkIp {
233                timestamp: SystemTime::now(),
234                source_ip: src_addr.ip(),
235                destination_ip: dst_addr.ip(),
236                tag: assign_chunk_tag(),
237            },
238            source_port: src_addr.port(),
239            destination_port: dst_addr.port(),
240            user_data: vec![],
241        }
242    }
243}
244
245#[derive(PartialEq, Debug)]
246pub(crate) struct ChunkTcp {
247    chunk_ip: ChunkIp,
248    source_port: u16,
249    destination_port: u16,
250    flags: TcpFlag, // control bits
251    user_data: Vec<u8>, // only with PSH flag
252                    // seq             :u32,  // always starts with 0
253                    // ack             :u32,  // always starts with 0
254}
255
256impl fmt::Display for ChunkTcp {
257    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258        write!(
259            f,
260            "{} {} chunk {} {} => {}",
261            self.network(),
262            self.flags,
263            self.chunk_ip.tag,
264            self.source_addr(),
265            self.destination_addr(),
266        )
267    }
268}
269
270impl Chunk for ChunkTcp {
271    fn set_timestamp(&mut self) -> SystemTime {
272        self.chunk_ip.set_timestamp()
273    }
274
275    fn get_timestamp(&self) -> SystemTime {
276        self.chunk_ip.get_timestamp()
277    }
278
279    fn get_destination_ip(&self) -> IpAddr {
280        self.chunk_ip.get_destination_ip()
281    }
282
283    fn get_source_ip(&self) -> IpAddr {
284        self.chunk_ip.get_source_ip()
285    }
286
287    fn tag(&self) -> String {
288        self.chunk_ip.tag()
289    }
290
291    fn source_addr(&self) -> SocketAddr {
292        SocketAddr::new(self.chunk_ip.source_ip, self.source_port)
293    }
294
295    fn destination_addr(&self) -> SocketAddr {
296        SocketAddr::new(self.chunk_ip.destination_ip, self.destination_port)
297    }
298
299    fn user_data(&self) -> Vec<u8> {
300        self.user_data.clone()
301    }
302
303    fn clone_to(&self) -> Box<dyn Chunk + Send + Sync> {
304        Box::new(ChunkTcp {
305            chunk_ip: ChunkIp {
306                timestamp: self.chunk_ip.timestamp,
307                source_ip: self.chunk_ip.source_ip,
308                destination_ip: self.chunk_ip.destination_ip,
309                tag: self.chunk_ip.tag.clone(),
310            },
311            source_port: self.source_port,
312            destination_port: self.destination_port,
313            flags: self.flags,
314            user_data: self.user_data.clone(),
315        })
316    }
317
318    fn network(&self) -> String {
319        "tcp".to_owned()
320    }
321
322    fn set_source_addr(&mut self, address: &str) -> Result<()> {
323        let addr = SocketAddr::from_str(address)?;
324        self.chunk_ip.source_ip = addr.ip();
325        self.source_port = addr.port();
326        Ok(())
327    }
328
329    fn set_destination_addr(&mut self, address: &str) -> Result<()> {
330        let addr = SocketAddr::from_str(address)?;
331        self.chunk_ip.destination_ip = addr.ip();
332        self.destination_port = addr.port();
333        Ok(())
334    }
335}
336
337impl ChunkTcp {
338    pub(crate) fn new(src_addr: SocketAddr, dst_addr: SocketAddr, flags: TcpFlag) -> Self {
339        ChunkTcp {
340            chunk_ip: ChunkIp {
341                timestamp: SystemTime::now(),
342                source_ip: src_addr.ip(),
343                destination_ip: dst_addr.ip(),
344                tag: assign_chunk_tag(),
345            },
346            source_port: src_addr.port(),
347            destination_port: dst_addr.port(),
348            flags,
349            user_data: vec![],
350        }
351    }
352}