shadow_protocols/
timing.rs1use rand::Rng;
6use rand_distr::{Distribution, Normal, Exp};
7use std::time::{Duration, Instant};
8
9#[derive(Debug, Clone, Copy, PartialEq)]
11pub enum TimingPattern {
12 Constant(Duration),
14 Gaussian { mean_ms: u64, stddev_ms: u64 },
16 Exponential { rate_per_sec: f64 },
18 WebRTC,
20 HTTPS,
22 Custom,
24}
25
26pub struct TimingEngine {
28 pattern: TimingPattern,
29 last_send: Instant,
30 packet_count: u64,
31}
32
33impl TimingEngine {
34 pub fn new(pattern: TimingPattern) -> Self {
36 Self {
37 pattern,
38 last_send: Instant::now(),
39 packet_count: 0,
40 }
41 }
42
43 pub fn next_delay(&mut self) -> Duration {
45 self.packet_count += 1;
46
47 match self.pattern {
48 TimingPattern::Constant(d) => d,
49
50 TimingPattern::Gaussian { mean_ms, stddev_ms } => {
51 let mut rng = rand::thread_rng();
52 let normal = Normal::new(mean_ms as f64, stddev_ms as f64).unwrap();
53 let delay_ms = normal.sample(&mut rng).max(0.0) as u64;
54 Duration::from_millis(delay_ms)
55 }
56
57 TimingPattern::Exponential { rate_per_sec } => {
58 let mut rng = rand::thread_rng();
59 let exp = Exp::new(rate_per_sec).unwrap();
60 let delay_sec = exp.sample(&mut rng);
61 Duration::from_secs_f64(delay_sec)
62 }
63
64 TimingPattern::WebRTC => {
65 self.webrtc_timing()
66 }
67
68 TimingPattern::HTTPS => {
69 self.https_timing()
70 }
71
72 TimingPattern::Custom => {
73 Duration::from_millis(50)
75 }
76 }
77 }
78
79 fn webrtc_timing(&mut self) -> Duration {
81 let mut rng = rand::thread_rng();
82
83 let base_ms = 33;
85
86 let jitter = Normal::new(0.0, 5.0).unwrap().sample(&mut rng);
88
89 let burst = if self.packet_count % 30 == 0 {
91 rng.gen_range(0..5)
93 } else {
94 base_ms
95 };
96
97 Duration::from_millis((burst as f64 + jitter).max(1.0) as u64)
98 }
99
100 fn https_timing(&mut self) -> Duration {
102 let mut rng = rand::thread_rng();
103
104 if self.packet_count % 2 == 0 {
106 let think_time = Exp::new(0.5).unwrap().sample(&mut rng);
108 Duration::from_secs_f64(think_time)
109 } else {
110 let processing: f64 = Normal::new(50.0, 20.0).unwrap().sample(&mut rng);
112 Duration::from_millis(processing.max(10.0) as u64)
113 }
114 }
115
116 pub async fn wait_next(&mut self) {
118 let delay = self.next_delay();
119 let elapsed = self.last_send.elapsed();
120
121 if delay > elapsed {
122 tokio::time::sleep(delay - elapsed).await;
123 }
124
125 self.last_send = Instant::now();
126 }
127
128 pub fn set_pattern(&mut self, pattern: TimingPattern) {
130 self.pattern = pattern;
131 }
132
133 pub fn pattern(&self) -> TimingPattern {
135 self.pattern
136 }
137
138 pub fn reset(&mut self) {
140 self.last_send = Instant::now();
141 self.packet_count = 0;
142 }
143}
144
145pub struct BurstTiming {
147 burst_size: usize,
149 burst_delay: Duration,
151 packet_delay: Duration,
153 position: usize,
155}
156
157impl BurstTiming {
158 pub fn new(burst_size: usize, burst_delay: Duration, packet_delay: Duration) -> Self {
160 Self {
161 burst_size,
162 burst_delay,
163 packet_delay,
164 position: 0,
165 }
166 }
167
168 pub fn next_delay(&mut self) -> Duration {
170 self.position += 1;
171
172 if self.position >= self.burst_size {
173 self.position = 0;
174 self.burst_delay
175 } else {
176 self.packet_delay
177 }
178 }
179}
180
181pub struct AdaptiveTiming {
183 engine: TimingEngine,
185 rtt_samples: Vec<Duration>,
187 max_samples: usize,
189}
190
191impl AdaptiveTiming {
192 pub fn new(pattern: TimingPattern) -> Self {
194 Self {
195 engine: TimingEngine::new(pattern),
196 rtt_samples: Vec::new(),
197 max_samples: 100,
198 }
199 }
200
201 pub fn record_rtt(&mut self, rtt: Duration) {
203 self.rtt_samples.push(rtt);
204
205 if self.rtt_samples.len() > self.max_samples {
206 self.rtt_samples.remove(0);
207 }
208
209 self.adapt();
211 }
212
213 fn adapt(&mut self) {
215 if self.rtt_samples.is_empty() {
216 return;
217 }
218
219 let mean_rtt: Duration = self.rtt_samples.iter().sum::<Duration>() / self.rtt_samples.len() as u32;
221
222 if mean_rtt > Duration::from_millis(200) {
225 let current_delay = self.engine.next_delay();
227 let new_delay = current_delay + current_delay / 5;
228 self.engine.set_pattern(TimingPattern::Constant(new_delay));
229 }
230 }
231
232 pub fn next_delay(&mut self) -> Duration {
234 self.engine.next_delay()
235 }
236}
237
238#[cfg(test)]
239mod tests {
240 use super::*;
241
242 #[test]
243 fn test_constant_timing() {
244 let mut engine = TimingEngine::new(TimingPattern::Constant(Duration::from_millis(100)));
245
246 for _ in 0..10 {
247 assert_eq!(engine.next_delay(), Duration::from_millis(100));
248 }
249 }
250
251 #[test]
252 fn test_gaussian_timing() {
253 let mut engine = TimingEngine::new(TimingPattern::Gaussian {
254 mean_ms: 50,
255 stddev_ms: 10,
256 });
257
258 let mut delays = Vec::new();
259 for _ in 0..100 {
260 delays.push(engine.next_delay().as_millis());
261 }
262
263 let mean: u128 = delays.iter().sum::<u128>() / delays.len() as u128;
265 assert!((mean as i128 - 50).abs() < 15, "Mean: {}", mean);
266 }
267
268 #[test]
269 fn test_burst_timing() {
270 let mut burst = BurstTiming::new(
271 5,
272 Duration::from_millis(100),
273 Duration::from_millis(10),
274 );
275
276 for _ in 0..4 {
278 assert_eq!(burst.next_delay(), Duration::from_millis(10));
279 }
280
281 assert_eq!(burst.next_delay(), Duration::from_millis(100));
283 }
284
285 #[test]
286 fn test_pattern_switching() {
287 let mut engine = TimingEngine::new(TimingPattern::Constant(Duration::from_millis(50)));
288
289 assert_eq!(engine.next_delay(), Duration::from_millis(50));
290
291 engine.set_pattern(TimingPattern::Constant(Duration::from_millis(100)));
292
293 assert_eq!(engine.next_delay(), Duration::from_millis(100));
294 }
295}