1use parking_lot::RwLock;
30use serde::{Deserialize, Serialize};
31use std::collections::HashMap;
32use std::net::SocketAddr;
33use std::sync::Arc;
34use std::time::{Duration, Instant};
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct QuicConfig {
39 pub max_idle_timeout_ms: u64,
41
42 pub keep_alive_interval_ms: u64,
44
45 pub max_concurrent_bidi_streams: u64,
47
48 pub max_concurrent_uni_streams: u64,
50
51 pub initial_max_data: u64,
53
54 pub max_stream_data: u64,
56
57 pub max_udp_payload_size: u16,
59
60 pub congestion_control: CongestionControl,
62
63 pub enable_0rtt: bool,
65
66 pub enable_datagrams: bool,
68
69 pub datagram_recv_buffer_size: usize,
71
72 pub datagram_send_buffer_size: usize,
74}
75
76impl Default for QuicConfig {
77 fn default() -> Self {
78 Self {
79 max_idle_timeout_ms: 60_000, keep_alive_interval_ms: 15_000, max_concurrent_bidi_streams: 100,
82 max_concurrent_uni_streams: 100,
83 initial_max_data: 10_000_000, max_stream_data: 1_000_000, max_udp_payload_size: 1452, congestion_control: CongestionControl::Cubic,
87 enable_0rtt: true,
88 enable_datagrams: true,
89 datagram_recv_buffer_size: 65536,
90 datagram_send_buffer_size: 65536,
91 }
92 }
93}
94
95impl QuicConfig {
96 pub fn low_latency() -> Self {
98 Self {
99 max_idle_timeout_ms: 30_000,
100 keep_alive_interval_ms: 10_000,
101 max_concurrent_bidi_streams: 50,
102 max_concurrent_uni_streams: 50,
103 initial_max_data: 5_000_000,
104 max_stream_data: 500_000,
105 max_udp_payload_size: 1200,
106 congestion_control: CongestionControl::Bbr,
107 enable_0rtt: true,
108 enable_datagrams: true,
109 datagram_recv_buffer_size: 32768,
110 datagram_send_buffer_size: 32768,
111 }
112 }
113
114 pub fn high_throughput() -> Self {
116 Self {
117 max_idle_timeout_ms: 120_000,
118 keep_alive_interval_ms: 30_000,
119 max_concurrent_bidi_streams: 500,
120 max_concurrent_uni_streams: 500,
121 initial_max_data: 50_000_000,
122 max_stream_data: 10_000_000,
123 max_udp_payload_size: 1452,
124 congestion_control: CongestionControl::Cubic,
125 enable_0rtt: true,
126 enable_datagrams: true,
127 datagram_recv_buffer_size: 262144, datagram_send_buffer_size: 262144,
129 }
130 }
131
132 pub fn mobile() -> Self {
134 Self {
135 max_idle_timeout_ms: 90_000,
136 keep_alive_interval_ms: 20_000,
137 max_concurrent_bidi_streams: 30,
138 max_concurrent_uni_streams: 30,
139 initial_max_data: 2_000_000,
140 max_stream_data: 200_000,
141 max_udp_payload_size: 1200,
142 congestion_control: CongestionControl::Bbr,
143 enable_0rtt: true,
144 enable_datagrams: false, datagram_recv_buffer_size: 16384,
146 datagram_send_buffer_size: 16384,
147 }
148 }
149
150 pub fn with_max_idle_timeout(mut self, timeout_ms: u64) -> Self {
152 self.max_idle_timeout_ms = timeout_ms;
153 self
154 }
155
156 pub fn with_keep_alive(mut self, interval_ms: u64) -> Self {
158 self.keep_alive_interval_ms = interval_ms;
159 self
160 }
161
162 pub fn with_congestion_control(mut self, cc: CongestionControl) -> Self {
164 self.congestion_control = cc;
165 self
166 }
167
168 pub fn with_0rtt(mut self, enable: bool) -> Self {
170 self.enable_0rtt = enable;
171 self
172 }
173
174 pub fn with_datagrams(mut self, enable: bool) -> Self {
176 self.enable_datagrams = enable;
177 self
178 }
179}
180
181#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
183pub enum CongestionControl {
184 Cubic,
186 Bbr,
188 NewReno,
190}
191
192#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
194pub enum QuicConnectionState {
195 Handshaking,
197 Established,
199 Closing,
201 Closed,
203 Failed,
205}
206
207#[derive(Debug, Clone)]
209pub struct QuicConnectionInfo {
210 pub remote_addr: SocketAddr,
212 pub state: QuicConnectionState,
214 pub established_at: Option<Instant>,
216 pub rtt: Option<Duration>,
218 pub congestion_window: u64,
220 pub bytes_sent: u64,
222 pub bytes_received: u64,
224 pub active_bidi_streams: u64,
226 pub active_uni_streams: u64,
228 pub lost_packets: u64,
230 pub migration_count: u32,
232}
233
234#[derive(Debug, Clone, Default, Serialize, Deserialize)]
236pub struct QuicStats {
237 pub connections_established: u64,
239 pub connections_closed: u64,
241 pub connections_failed: u64,
243 pub active_connections: u64,
245 pub total_bytes_sent: u64,
247 pub total_bytes_received: u64,
249 pub total_packets_lost: u64,
251 pub total_migrations: u64,
253 pub zero_rtt_connections: u64,
255 pub avg_rtt_ms: f64,
257}
258
259#[derive(Debug)]
261pub struct QuicMonitor {
262 config: QuicConfig,
264 connections: Arc<RwLock<HashMap<SocketAddr, QuicConnectionInfo>>>,
266 stats: Arc<RwLock<QuicStats>>,
268}
269
270impl QuicMonitor {
271 pub fn new(config: QuicConfig) -> Self {
273 Self {
274 config,
275 connections: Arc::new(RwLock::new(HashMap::new())),
276 stats: Arc::new(RwLock::new(QuicStats::default())),
277 }
278 }
279
280 pub fn config(&self) -> &QuicConfig {
282 &self.config
283 }
284
285 pub fn record_connection_established(&self, remote_addr: SocketAddr, used_0rtt: bool) {
287 let mut connections = self.connections.write();
288 connections.insert(
289 remote_addr,
290 QuicConnectionInfo {
291 remote_addr,
292 state: QuicConnectionState::Established,
293 established_at: Some(Instant::now()),
294 rtt: None,
295 congestion_window: self.config.initial_max_data,
296 bytes_sent: 0,
297 bytes_received: 0,
298 active_bidi_streams: 0,
299 active_uni_streams: 0,
300 lost_packets: 0,
301 migration_count: 0,
302 },
303 );
304
305 let mut stats = self.stats.write();
306 stats.connections_established += 1;
307 stats.active_connections += 1;
308 if used_0rtt {
309 stats.zero_rtt_connections += 1;
310 }
311 }
312
313 pub fn record_connection_closed(&self, remote_addr: &SocketAddr) {
315 let mut connections = self.connections.write();
316 if let Some(info) = connections.remove(remote_addr) {
317 let mut stats = self.stats.write();
318 stats.connections_closed += 1;
319 stats.active_connections = stats.active_connections.saturating_sub(1);
320 stats.total_bytes_sent += info.bytes_sent;
321 stats.total_bytes_received += info.bytes_received;
322 stats.total_packets_lost += info.lost_packets;
323 stats.total_migrations += info.migration_count as u64;
324 }
325 }
326
327 pub fn record_connection_failed(&self, remote_addr: &SocketAddr) {
329 let mut connections = self.connections.write();
330 if connections.remove(remote_addr).is_some() {
331 let mut stats = self.stats.write();
332 stats.connections_failed += 1;
333 stats.active_connections = stats.active_connections.saturating_sub(1);
334 }
335 }
336
337 pub fn update_rtt(&self, remote_addr: &SocketAddr, rtt: Duration) {
339 let mut connections = self.connections.write();
340 if let Some(info) = connections.get_mut(remote_addr) {
341 info.rtt = Some(rtt);
342 }
343
344 let mut stats = self.stats.write();
346 let new_rtt_ms = rtt.as_millis() as f64;
347 if stats.avg_rtt_ms == 0.0 {
348 stats.avg_rtt_ms = new_rtt_ms;
349 } else {
350 stats.avg_rtt_ms = stats.avg_rtt_ms * 0.9 + new_rtt_ms * 0.1;
352 }
353 }
354
355 pub fn update_bytes(&self, remote_addr: &SocketAddr, sent: u64, received: u64) {
357 let mut connections = self.connections.write();
358 if let Some(info) = connections.get_mut(remote_addr) {
359 info.bytes_sent = sent;
360 info.bytes_received = received;
361 }
362 }
363
364 pub fn update_streams(&self, remote_addr: &SocketAddr, bidi: u64, uni: u64) {
366 let mut connections = self.connections.write();
367 if let Some(info) = connections.get_mut(remote_addr) {
368 info.active_bidi_streams = bidi;
369 info.active_uni_streams = uni;
370 }
371 }
372
373 pub fn record_migration(&self, remote_addr: &SocketAddr) {
375 let mut connections = self.connections.write();
376 if let Some(info) = connections.get_mut(remote_addr) {
377 info.migration_count += 1;
378 }
379 }
380
381 pub fn get_connection(&self, remote_addr: &SocketAddr) -> Option<QuicConnectionInfo> {
383 self.connections.read().get(remote_addr).cloned()
384 }
385
386 pub fn get_active_connections(&self) -> Vec<QuicConnectionInfo> {
388 self.connections.read().values().cloned().collect()
389 }
390
391 pub fn stats(&self) -> QuicStats {
393 self.stats.read().clone()
394 }
395
396 pub fn active_connection_count(&self) -> usize {
398 self.connections.read().len()
399 }
400
401 pub fn reset_stats(&self) {
403 *self.stats.write() = QuicStats::default();
404 }
405}
406
407impl Default for QuicMonitor {
408 fn default() -> Self {
409 Self::new(QuicConfig::default())
410 }
411}
412
413#[cfg(test)]
414mod tests {
415 use super::*;
416 use std::net::{IpAddr, Ipv4Addr};
417
418 #[test]
419 fn test_quic_config_default() {
420 let config = QuicConfig::default();
421 assert_eq!(config.max_idle_timeout_ms, 60_000);
422 assert_eq!(config.keep_alive_interval_ms, 15_000);
423 assert!(config.enable_0rtt);
424 assert!(config.enable_datagrams);
425 }
426
427 #[test]
428 fn test_quic_config_low_latency() {
429 let config = QuicConfig::low_latency();
430 assert_eq!(config.congestion_control, CongestionControl::Bbr);
431 assert_eq!(config.max_idle_timeout_ms, 30_000);
432 assert!(config.max_concurrent_bidi_streams < 100);
433 }
434
435 #[test]
436 fn test_quic_config_high_throughput() {
437 let config = QuicConfig::high_throughput();
438 assert_eq!(config.congestion_control, CongestionControl::Cubic);
439 assert!(config.max_concurrent_bidi_streams >= 500);
440 assert!(config.initial_max_data >= 50_000_000);
441 }
442
443 #[test]
444 fn test_quic_config_mobile() {
445 let config = QuicConfig::mobile();
446 assert_eq!(config.congestion_control, CongestionControl::Bbr);
447 assert!(!config.enable_datagrams); assert!(config.max_udp_payload_size <= 1200);
449 }
450
451 #[test]
452 fn test_quic_config_builder() {
453 let config = QuicConfig::default()
454 .with_max_idle_timeout(30_000)
455 .with_keep_alive(10_000)
456 .with_congestion_control(CongestionControl::Bbr)
457 .with_0rtt(false)
458 .with_datagrams(false);
459
460 assert_eq!(config.max_idle_timeout_ms, 30_000);
461 assert_eq!(config.keep_alive_interval_ms, 10_000);
462 assert_eq!(config.congestion_control, CongestionControl::Bbr);
463 assert!(!config.enable_0rtt);
464 assert!(!config.enable_datagrams);
465 }
466
467 #[test]
468 fn test_quic_monitor_new() {
469 let monitor = QuicMonitor::default();
470 assert_eq!(monitor.active_connection_count(), 0);
471 assert_eq!(monitor.stats().active_connections, 0);
472 }
473
474 #[test]
475 fn test_quic_monitor_connection_lifecycle() {
476 let monitor = QuicMonitor::default();
477 let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
478
479 monitor.record_connection_established(addr, false);
481 assert_eq!(monitor.active_connection_count(), 1);
482 assert_eq!(monitor.stats().connections_established, 1);
483 assert_eq!(monitor.stats().active_connections, 1);
484
485 monitor.record_connection_closed(&addr);
487 assert_eq!(monitor.active_connection_count(), 0);
488 assert_eq!(monitor.stats().connections_closed, 1);
489 assert_eq!(monitor.stats().active_connections, 0);
490 }
491
492 #[test]
493 fn test_quic_monitor_0rtt() {
494 let monitor = QuicMonitor::default();
495 let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
496
497 monitor.record_connection_established(addr, true);
498 assert_eq!(monitor.stats().zero_rtt_connections, 1);
499 }
500
501 #[test]
502 fn test_quic_monitor_failed_connection() {
503 let monitor = QuicMonitor::default();
504 let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
505
506 monitor.record_connection_established(addr, false);
507 monitor.record_connection_failed(&addr);
508
509 assert_eq!(monitor.active_connection_count(), 0);
510 assert_eq!(monitor.stats().connections_failed, 1);
511 assert_eq!(monitor.stats().active_connections, 0);
512 }
513
514 #[test]
515 fn test_quic_monitor_rtt_update() {
516 let monitor = QuicMonitor::default();
517 let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
518
519 monitor.record_connection_established(addr, false);
520 monitor.update_rtt(&addr, Duration::from_millis(50));
521
522 let info = monitor.get_connection(&addr).unwrap();
523 assert_eq!(info.rtt, Some(Duration::from_millis(50)));
524 assert_eq!(monitor.stats().avg_rtt_ms, 50.0);
525 }
526
527 #[test]
528 fn test_quic_monitor_bytes_update() {
529 let monitor = QuicMonitor::default();
530 let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
531
532 monitor.record_connection_established(addr, false);
533 monitor.update_bytes(&addr, 1000, 2000);
534
535 let info = monitor.get_connection(&addr).unwrap();
536 assert_eq!(info.bytes_sent, 1000);
537 assert_eq!(info.bytes_received, 2000);
538 }
539
540 #[test]
541 fn test_quic_monitor_streams_update() {
542 let monitor = QuicMonitor::default();
543 let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
544
545 monitor.record_connection_established(addr, false);
546 monitor.update_streams(&addr, 5, 3);
547
548 let info = monitor.get_connection(&addr).unwrap();
549 assert_eq!(info.active_bidi_streams, 5);
550 assert_eq!(info.active_uni_streams, 3);
551 }
552
553 #[test]
554 fn test_quic_monitor_migration() {
555 let monitor = QuicMonitor::default();
556 let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
557
558 monitor.record_connection_established(addr, false);
559 monitor.record_migration(&addr);
560 monitor.record_migration(&addr);
561
562 let info = monitor.get_connection(&addr).unwrap();
563 assert_eq!(info.migration_count, 2);
564 }
565
566 #[test]
567 fn test_quic_monitor_get_active_connections() {
568 let monitor = QuicMonitor::default();
569 let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
570 let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081);
571
572 monitor.record_connection_established(addr1, false);
573 monitor.record_connection_established(addr2, true);
574
575 let connections = monitor.get_active_connections();
576 assert_eq!(connections.len(), 2);
577 }
578
579 #[test]
580 fn test_quic_monitor_reset_stats() {
581 let monitor = QuicMonitor::default();
582 let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
583
584 monitor.record_connection_established(addr, false);
585 monitor.reset_stats();
586
587 let stats = monitor.stats();
588 assert_eq!(stats.connections_established, 0);
589 assert_eq!(stats.active_connections, 0);
590 }
591
592 #[test]
593 fn test_quic_monitor_avg_rtt_calculation() {
594 let monitor = QuicMonitor::default();
595 let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
596
597 monitor.record_connection_established(addr, false);
598
599 monitor.update_rtt(&addr, Duration::from_millis(100));
601 assert_eq!(monitor.stats().avg_rtt_ms, 100.0);
602
603 monitor.update_rtt(&addr, Duration::from_millis(50));
605 let avg = monitor.stats().avg_rtt_ms;
606 assert!(avg > 50.0 && avg < 100.0);
607 }
608
609 #[test]
610 fn test_congestion_control_variants() {
611 let cubic = CongestionControl::Cubic;
612 let bbr = CongestionControl::Bbr;
613 let newreno = CongestionControl::NewReno;
614
615 assert_ne!(cubic, bbr);
616 assert_ne!(bbr, newreno);
617 assert_ne!(cubic, newreno);
618 }
619
620 #[test]
621 fn test_connection_state_variants() {
622 let states = [
623 QuicConnectionState::Handshaking,
624 QuicConnectionState::Established,
625 QuicConnectionState::Closing,
626 QuicConnectionState::Closed,
627 QuicConnectionState::Failed,
628 ];
629
630 for (i, state1) in states.iter().enumerate() {
631 for (j, state2) in states.iter().enumerate() {
632 if i == j {
633 assert_eq!(state1, state2);
634 } else {
635 assert_ne!(state1, state2);
636 }
637 }
638 }
639 }
640}