1use crate::channel::{QueuedDatagram, SimChannel};
4use rand::{rng, Rng};
5use std::net::SocketAddr;
6use std::time::{Duration, Instant};
7
8#[derive(Debug, Clone)]
10pub struct NetworkConfig {
11 pub latency: Duration,
13 pub jitter: Duration,
15 pub loss_rate: f64,
17 pub burst_loss_prob: f64,
19 pub reorder_rate: f64,
21 pub duplicate_prob: f64,
23 pub bandwidth: Option<u64>,
25 pub nat_rebind_prob: f64,
27}
28
29impl Default for NetworkConfig {
30 fn default() -> Self {
31 Self {
32 latency: Duration::from_millis(10),
33 jitter: Duration::from_millis(0),
34 loss_rate: 0.0,
35 burst_loss_prob: 0.0,
36 reorder_rate: 0.0,
37 duplicate_prob: 0.0,
38 bandwidth: None,
39 nat_rebind_prob: 0.0,
40 }
41 }
42}
43
44pub struct SimulatedNetwork {
46 config: NetworkConfig,
47 channel: SimChannel,
48 in_burst_loss: bool,
49 current_src_port_offset: u16,
50}
51
52impl SimulatedNetwork {
53 pub fn new(config: NetworkConfig) -> Self {
55 Self {
56 config,
57 channel: SimChannel::new(),
58 in_burst_loss: false,
59 current_src_port_offset: 0,
60 }
61 }
62
63 pub fn config(&self) -> &NetworkConfig {
65 &self.config
66 }
67
68 pub fn config_mut(&mut self) -> &mut NetworkConfig {
70 &mut self.config
71 }
72
73 pub fn send(&mut self, payload: Vec<u8>, mut src: SocketAddr, dst: SocketAddr, now: Instant) {
75 let mut rng = rng();
76
77 if self.in_burst_loss {
79 if rng.random::<f64>() > self.config.burst_loss_prob {
80 self.in_burst_loss = false;
81 } else {
82 return; }
84 } else if rng.random::<f64>() < self.config.loss_rate {
85 if rng.random::<f64>() < self.config.burst_loss_prob {
86 self.in_burst_loss = true;
87 }
88 return; }
90
91 let mut delay = self.config.latency;
93 if self.config.jitter > Duration::ZERO {
94 let jitter_ms = rng.random_range(0..=self.config.jitter.as_millis() as u64);
95 delay += Duration::from_millis(jitter_ms);
96 }
97
98 if let Some(bw) = self.config.bandwidth {
100 if bw > 0 {
101 let tx_nanos = (payload.len() as u64 * 1_000_000_000) / bw;
102 delay += Duration::from_nanos(tx_nanos);
103 }
104 }
105
106 if rng.random::<f64>() < self.config.reorder_rate {
108 delay += Duration::from_millis(rng.random_range(10..50));
109 }
110
111 if rng.random::<f64>() < self.config.nat_rebind_prob {
113 self.current_src_port_offset = self.current_src_port_offset.wrapping_add(1);
114 }
115
116 src.set_port(src.port().wrapping_add(self.current_src_port_offset));
117
118 let delivery_time = now + delay;
119
120 if rng.random::<f64>() < self.config.duplicate_prob {
122 self.channel.push(QueuedDatagram {
123 delivery_time: delivery_time + Duration::from_millis(1),
124 payload: payload.clone(),
125 src,
126 dst,
127 });
128 }
129
130 self.channel.push(QueuedDatagram {
131 delivery_time,
132 payload,
133 src,
134 dst,
135 });
136 }
137
138 pub fn receive(&mut self, now: Instant) -> Option<QueuedDatagram> {
140 self.channel.pop_ready(now)
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
149 fn test_latency_delay() {
150 let mut net = SimulatedNetwork::new(NetworkConfig {
151 latency: Duration::from_millis(50),
152 ..Default::default()
153 });
154
155 let src: SocketAddr = "127.0.0.1:1000".parse().unwrap();
156 let dst: SocketAddr = "127.0.0.1:2000".parse().unwrap();
157 let now = Instant::now();
158
159 net.send(vec![1, 2, 3], src, dst, now);
160
161 assert!(net.receive(now).is_none());
162 assert!(net.receive(now + Duration::from_millis(20)).is_none());
163 assert!(net.receive(now + Duration::from_millis(50)).is_some());
164 }
165
166 #[test]
167 fn test_packet_loss_dropping() {
168 let mut net = SimulatedNetwork::new(NetworkConfig {
169 loss_rate: 1.0,
170 ..Default::default()
171 });
172
173 let src: SocketAddr = "127.0.0.1:1000".parse().unwrap();
174 let dst: SocketAddr = "127.0.0.1:2000".parse().unwrap();
175 let now = Instant::now();
176
177 net.send(vec![1, 2, 3], src, dst, now);
178
179 assert!(net.receive(now + Duration::from_secs(10)).is_none());
180 }
181
182 #[test]
183 fn test_reordering() {
184 let mut net = SimulatedNetwork::new(NetworkConfig {
185 latency: Duration::from_millis(10),
186 reorder_rate: 1.0,
187 ..Default::default()
188 });
189
190 let src: SocketAddr = "127.0.0.1:1000".parse().unwrap();
191 let dst: SocketAddr = "127.0.0.1:2000".parse().unwrap();
192 let now = Instant::now();
193
194 net.send(vec![1], src, dst, now);
195
196 assert!(net.receive(now + Duration::from_millis(10)).is_none());
197 assert!(net.receive(now + Duration::from_millis(100)).is_some());
198 }
199}