1use crate::config::Config;
6use crate::connection::Transmit;
7use crate::endpoint::{ConnHandle, DatagramEvent, Endpoint};
8use std::cmp::Reverse;
9use std::collections::BinaryHeap;
10use std::net::SocketAddr;
11use std::sync::Arc;
12use std::time::{Duration, Instant};
13
14#[derive(Clone, Debug)]
16pub struct Link {
17 pub delay: Duration,
18 pub jitter: Duration,
19 pub loss_ppm: u32,
20 pub duplicate_ppm: u32,
21 pub reorder_ppm: u32,
23 pub reorder_delay: Duration,
24 pub bandwidth: Option<u64>,
26 pub queue: usize,
28 pub mtu: usize,
30}
31
32impl Default for Link {
33 fn default() -> Self {
34 Link {
35 delay: Duration::from_millis(10),
36 jitter: Duration::ZERO,
37 loss_ppm: 0,
38 duplicate_ppm: 0,
39 reorder_ppm: 0,
40 reorder_delay: Duration::ZERO,
41 bandwidth: None,
42 queue: usize::MAX,
43 mtu: 1500,
44 }
45 }
46}
47
48#[derive(Clone, Copy, Debug, Default)]
49pub struct LinkStats {
50 pub sent: u64,
51 pub delivered: u64,
52 pub dropped: u64,
53 pub duplicated: u64,
54 pub bytes: u64,
55}
56
57struct Dgram {
58 from: SocketAddr,
59 to: SocketAddr,
60 data: Vec<u8>,
61}
62
63struct Queued(Instant, u64, Dgram);
65
66impl PartialEq for Queued {
67 fn eq(&self, o: &Self) -> bool {
68 (self.0, self.1) == (o.0, o.1)
69 }
70}
71impl Eq for Queued {}
72impl PartialOrd for Queued {
73 fn partial_cmp(&self, o: &Self) -> Option<std::cmp::Ordering> {
74 Some(self.cmp(o))
75 }
76}
77impl Ord for Queued {
78 fn cmp(&self, o: &Self) -> std::cmp::Ordering {
79 (self.0, self.1).cmp(&(o.0, o.1))
80 }
81}
82
83#[derive(Clone)]
85pub struct Rng(u64);
86
87impl Rng {
88 pub fn new(seed: u64) -> Self {
89 Rng(seed.wrapping_mul(0x9e3779b97f4a7c15) | 1)
90 }
91 pub fn next(&mut self) -> u64 {
92 self.0 ^= self.0 >> 12;
93 self.0 ^= self.0 << 25;
94 self.0 ^= self.0 >> 27;
95 self.0.wrapping_mul(0x2545f4914f6cdd1d)
96 }
97 pub fn below(&mut self, n: u64) -> u64 {
98 if n == 0 {
99 0
100 } else {
101 self.next() % n
102 }
103 }
104 pub fn chance(&mut self, ppm: u32) -> bool {
105 ppm > 0 && self.below(1_000_000) < ppm as u64
106 }
107}
108
109pub struct Pair {
111 pub now: Instant,
112 pub client: Endpoint,
113 pub server: Endpoint,
114 pub client_addr: SocketAddr,
115 pub server_addr: SocketAddr,
116 pub client_aliases: Vec<SocketAddr>,
118 pub to_server: Link,
119 pub to_client: Link,
120 pub to_server_stats: LinkStats,
121 pub to_client_stats: LinkStats,
122 pub rng: Rng,
123 queue: BinaryHeap<Reverse<Queued>>,
124 seq: u64,
125 busy_until: [Instant; 2],
126 queued_bytes: [usize; 2],
127 buf: Vec<u8>,
128 resp: Vec<u8>,
129 pub accepted: Vec<ConnHandle>,
131 pub batch: usize,
133 pub tamper: Option<Box<dyn FnMut(bool, &mut Vec<u8>) -> bool>>,
135}
136
137impl Pair {
138 pub fn new(client_cfg: Arc<Config>, server_cfg: Arc<Config>, link: Link, seed: u64) -> Self {
139 let now = Instant::now();
140 Pair {
141 now,
142 client: Endpoint::new(client_cfg, false),
143 server: Endpoint::new(server_cfg, true),
144 client_addr: "10.0.0.1:5000".parse().unwrap(),
145 server_addr: "10.0.0.2:443".parse().unwrap(),
146 client_aliases: Vec::new(),
147 to_server: link.clone(),
148 to_client: link,
149 to_server_stats: LinkStats::default(),
150 to_client_stats: LinkStats::default(),
151 rng: Rng::new(seed),
152 queue: BinaryHeap::new(),
153 seq: 0,
154 busy_until: [now; 2],
155 queued_bytes: [0; 2],
156 buf: Vec::with_capacity(64 * 1024),
157 resp: Vec::new(),
158 accepted: Vec::new(),
159 batch: 8,
160 tamper: None,
161 }
162 }
163
164 pub fn connect(&mut self) -> ConnHandle {
166 let addr = self.server_addr;
167 self.client.connect(self.now, addr, "localhost", &[]).unwrap()
168 }
169
170 fn enqueue(&mut self, to_server: bool, from: SocketAddr, to: SocketAddr, mut data: Vec<u8>) {
171 let d = if to_server { 0 } else { 1 };
172 let link = if to_server { self.to_server.clone() } else { self.to_client.clone() };
173 let stats = if to_server { &mut self.to_server_stats } else { &mut self.to_client_stats };
174 stats.sent += 1;
175 if let Some(t) = self.tamper.as_mut() {
176 if !t(to_server, &mut data) {
177 stats.dropped += 1;
178 return;
179 }
180 }
181 if data.len() > link.mtu || self.rng.chance(link.loss_ppm) {
182 stats.dropped += 1;
183 return;
184 }
185 let mut depart = self.now;
187 if let Some(bw) = link.bandwidth {
188 if self.queued_bytes[d] + data.len() > link.queue && self.busy_until[d] > self.now {
189 stats.dropped += 1;
190 return;
191 }
192 let start = self.busy_until[d].max(self.now);
193 let tx = Duration::from_nanos(data.len() as u64 * 1_000_000_000 / bw);
194 self.busy_until[d] = start + tx;
195 depart = start + tx;
196 self.queued_bytes[d] += data.len();
197 }
198 let mut at = depart + link.delay;
199 if !link.jitter.is_zero() {
200 at += Duration::from_nanos(self.rng.below(link.jitter.as_nanos() as u64));
201 }
202 if self.rng.chance(link.reorder_ppm) {
203 at += Duration::from_nanos(self.rng.below(link.reorder_delay.as_nanos() as u64 + 1));
204 }
205 let dup = self.rng.chance(link.duplicate_ppm);
206 if dup {
207 stats.duplicated += 1;
208 }
209 stats.bytes += data.len() as u64;
210 let n = data.len();
211 if dup {
212 let copy = data.clone();
213 self.push(at + Duration::from_micros(50), Dgram { from, to, data: copy });
214 }
215 let _ = n;
216 self.push(at, Dgram { from, to, data });
217 }
218
219 fn push(&mut self, at: Instant, d: Dgram) {
220 self.seq += 1;
221 self.queue.push(Reverse(Queued(at, self.seq, d)));
222 }
223
224 fn flush(&mut self) {
225 loop {
226 let mut any = false;
227 while let Some((_, t)) = self.client.poll_transmit(self.now, &mut self.buf, self.batch) {
228 any = true;
229 let from = self.client_addr;
230 self.split_send(true, from, t);
231 }
232 while let Some((_, t)) = self.server.poll_transmit(self.now, &mut self.buf, self.batch) {
233 any = true;
234 let from = self.server_addr;
235 self.split_send(false, from, t);
236 }
237 if !any {
238 break;
239 }
240 }
241 }
242
243 fn split_send(&mut self, to_server: bool, from: SocketAddr, t: Transmit) {
244 let seg = t.segment_size.unwrap_or(t.size);
245 let data = std::mem::take(&mut self.buf);
246 for chunk in data[..t.size].chunks(seg) {
247 self.enqueue(to_server, from, t.destination, chunk.to_vec());
248 }
249 self.buf = data;
250 }
251
252 pub fn step(&mut self) -> bool {
255 self.step_until(None)
256 }
257
258 pub fn step_until(&mut self, limit: Option<Instant>) -> bool {
260 self.flush();
261 let next_dgram = self.queue.peek().map(|r| r.0 .0);
262 let next_timer = [self.client.poll_timeout(), self.server.poll_timeout()].into_iter().flatten().min();
263 let next = match (next_dgram, next_timer) {
264 (None, None) => return false,
265 (Some(a), None) => a,
266 (None, Some(b)) => b,
267 (Some(a), Some(b)) => a.min(b),
268 };
269 if let Some(l) = limit {
270 if next > l {
271 self.now = self.now.max(l);
272 return false;
273 }
274 }
275 if next > self.now {
276 self.now = next;
277 }
278 if next_dgram.is_some_and(|a| a <= self.now) {
279 let Reverse(Queued(_, _, mut d)) = self.queue.pop().unwrap();
280 let to_server = d.to == self.server_addr;
281 let di = if to_server { 0 } else { 1 };
282 self.queued_bytes[di] = self.queued_bytes[di].saturating_sub(d.data.len());
283 if to_server {
284 self.to_server_stats.delivered += 1;
285 let ev = self.server.recv(self.now, d.from, &mut d.data, &mut self.resp);
286 match ev {
287 DatagramEvent::NewConnection(h) => self.accepted.push(h),
288 DatagramEvent::Response(t) => {
289 let r = self.resp[..t.size].to_vec();
290 let from = self.server_addr;
291 self.enqueue(false, from, t.destination, r);
292 }
293 _ => {}
294 }
295 } else if d.to == self.client_addr || self.client_aliases.contains(&d.to) {
296 self.to_client_stats.delivered += 1;
297 let ev = self.client.recv(self.now, d.from, &mut d.data, &mut self.resp);
298 if let DatagramEvent::Response(t) = ev {
299 let r = self.resp[..t.size].to_vec();
300 let from = self.client_addr;
301 self.enqueue(true, from, t.destination, r);
302 }
303 } else {
304 self.to_client_stats.dropped += 1;
305 }
306 } else {
307 let mut touched = Vec::new();
308 self.client.handle_timeout(self.now, &mut touched);
309 self.server.handle_timeout(self.now, &mut touched);
310 }
311 true
312 }
313
314 pub fn run_until(&mut self, limit: Duration, mut cond: impl FnMut(&mut Pair) -> bool) -> bool {
316 let deadline = self.now + limit;
317 loop {
318 if cond(self) {
319 return true;
320 }
321 if self.now >= deadline || !self.step_until(Some(deadline)) {
322 return cond(self);
323 }
324 }
325 }
326
327 pub fn run_for(&mut self, limit: Duration) {
329 let deadline = self.now + limit;
330 while self.now < deadline {
331 if !self.step_until(Some(deadline)) {
332 break;
333 }
334 }
335 }
336
337 pub fn server_conn(&self) -> Option<ConnHandle> {
339 self.accepted.first().copied()
340 }
341
342 pub fn rebind_client(&mut self, addr: SocketAddr) {
344 let old = std::mem::replace(&mut self.client_addr, addr);
345 self.client_aliases.push(old);
346 }
347
348 pub fn in_flight(&self) -> usize {
350 self.queue.len()
351 }
352}