ipfrs_network/
quic.rs

1//! QUIC transport utilities and configuration
2//!
3//! This module provides utilities for working with QUIC transport in IPFRS network.
4//! While the actual QUIC transport is provided via libp2p-quic, this module offers
5//! additional configuration, monitoring, and utility functions.
6//!
7//! ## Features
8//!
9//! - **Configuration**: QUIC transport configuration with sensible defaults
10//! - **Connection Monitoring**: Track QUIC connection states and metrics
11//! - **Performance Tuning**: Congestion control and flow control settings
12//! - **Security**: TLS configuration and certificate management
13//! - **Statistics**: Detailed QUIC protocol statistics
14//!
15//! ## Example
16//!
17//! ```rust
18//! use ipfrs_network::quic::{QuicConfig, QuicStats, CongestionControl};
19//!
20//! // Create QUIC configuration
21//! let config = QuicConfig::default()
22//!     .with_max_idle_timeout(30_000)
23//!     .with_keep_alive(15_000)
24//!     .with_congestion_control(CongestionControl::Cubic);
25//!
26//! assert_eq!(config.max_idle_timeout_ms, 30_000);
27//! ```
28
29use 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/// QUIC configuration
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct QuicConfig {
39    /// Maximum idle timeout in milliseconds (0 = no timeout)
40    pub max_idle_timeout_ms: u64,
41
42    /// Keep-alive interval in milliseconds (0 = disabled)
43    pub keep_alive_interval_ms: u64,
44
45    /// Maximum concurrent bidirectional streams
46    pub max_concurrent_bidi_streams: u64,
47
48    /// Maximum concurrent unidirectional streams
49    pub max_concurrent_uni_streams: u64,
50
51    /// Initial maximum data (connection-level flow control)
52    pub initial_max_data: u64,
53
54    /// Maximum data per stream
55    pub max_stream_data: u64,
56
57    /// Maximum UDP payload size
58    pub max_udp_payload_size: u16,
59
60    /// Congestion control algorithm
61    pub congestion_control: CongestionControl,
62
63    /// Enable 0-RTT (faster reconnections)
64    pub enable_0rtt: bool,
65
66    /// Enable datagram support
67    pub enable_datagrams: bool,
68
69    /// Datagram receive buffer size
70    pub datagram_recv_buffer_size: usize,
71
72    /// Datagram send buffer size
73    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,    // 60 seconds
80            keep_alive_interval_ms: 15_000, // 15 seconds
81            max_concurrent_bidi_streams: 100,
82            max_concurrent_uni_streams: 100,
83            initial_max_data: 10_000_000, // 10 MB
84            max_stream_data: 1_000_000,   // 1 MB
85            max_udp_payload_size: 1452,   // Standard MTU minus headers
86            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    /// Create configuration optimized for low latency
97    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    /// Create configuration optimized for high throughput
115    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, // 256 KB
128            datagram_send_buffer_size: 262144,
129        }
130    }
131
132    /// Create configuration optimized for mobile/unreliable networks
133    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, // Disable to reduce overhead
145            datagram_recv_buffer_size: 16384,
146            datagram_send_buffer_size: 16384,
147        }
148    }
149
150    /// Builder pattern: set max idle timeout
151    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    /// Builder pattern: set keep-alive interval
157    pub fn with_keep_alive(mut self, interval_ms: u64) -> Self {
158        self.keep_alive_interval_ms = interval_ms;
159        self
160    }
161
162    /// Builder pattern: set congestion control
163    pub fn with_congestion_control(mut self, cc: CongestionControl) -> Self {
164        self.congestion_control = cc;
165        self
166    }
167
168    /// Builder pattern: enable/disable 0-RTT
169    pub fn with_0rtt(mut self, enable: bool) -> Self {
170        self.enable_0rtt = enable;
171        self
172    }
173
174    /// Builder pattern: enable/disable datagrams
175    pub fn with_datagrams(mut self, enable: bool) -> Self {
176        self.enable_datagrams = enable;
177        self
178    }
179}
180
181/// Congestion control algorithm
182#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
183pub enum CongestionControl {
184    /// CUBIC congestion control (default, good for high-bandwidth links)
185    Cubic,
186    /// BBR congestion control (better for varying network conditions)
187    Bbr,
188    /// NewReno congestion control (conservative, compatible)
189    NewReno,
190}
191
192/// QUIC connection state
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
194pub enum QuicConnectionState {
195    /// Handshake in progress
196    Handshaking,
197    /// Connection established
198    Established,
199    /// Connection closing
200    Closing,
201    /// Connection closed
202    Closed,
203    /// Connection failed
204    Failed,
205}
206
207/// Information about a QUIC connection
208#[derive(Debug, Clone)]
209pub struct QuicConnectionInfo {
210    /// Remote socket address
211    pub remote_addr: SocketAddr,
212    /// Connection state
213    pub state: QuicConnectionState,
214    /// Time when connection was established
215    pub established_at: Option<Instant>,
216    /// Round-trip time (RTT)
217    pub rtt: Option<Duration>,
218    /// Congestion window size
219    pub congestion_window: u64,
220    /// Bytes sent
221    pub bytes_sent: u64,
222    /// Bytes received
223    pub bytes_received: u64,
224    /// Active bidirectional streams
225    pub active_bidi_streams: u64,
226    /// Active unidirectional streams
227    pub active_uni_streams: u64,
228    /// Lost packets
229    pub lost_packets: u64,
230    /// Connection migration count
231    pub migration_count: u32,
232}
233
234/// QUIC statistics
235#[derive(Debug, Clone, Default, Serialize, Deserialize)]
236pub struct QuicStats {
237    /// Total connections established
238    pub connections_established: u64,
239    /// Total connections closed
240    pub connections_closed: u64,
241    /// Total connections failed
242    pub connections_failed: u64,
243    /// Currently active connections
244    pub active_connections: u64,
245    /// Total bytes sent across all connections
246    pub total_bytes_sent: u64,
247    /// Total bytes received across all connections
248    pub total_bytes_received: u64,
249    /// Total packets lost
250    pub total_packets_lost: u64,
251    /// Total connection migrations
252    pub total_migrations: u64,
253    /// Total 0-RTT connections
254    pub zero_rtt_connections: u64,
255    /// Average RTT (milliseconds)
256    pub avg_rtt_ms: f64,
257}
258
259/// QUIC connection monitor
260#[derive(Debug)]
261pub struct QuicMonitor {
262    /// Configuration
263    config: QuicConfig,
264    /// Active connections
265    connections: Arc<RwLock<HashMap<SocketAddr, QuicConnectionInfo>>>,
266    /// Statistics
267    stats: Arc<RwLock<QuicStats>>,
268}
269
270impl QuicMonitor {
271    /// Create a new QUIC monitor
272    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    /// Get configuration
281    pub fn config(&self) -> &QuicConfig {
282        &self.config
283    }
284
285    /// Record connection established
286    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    /// Record connection closed
314    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    /// Record connection failed
328    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    /// Update connection RTT
338    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        // Update average RTT
345        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            // Exponential moving average
351            stats.avg_rtt_ms = stats.avg_rtt_ms * 0.9 + new_rtt_ms * 0.1;
352        }
353    }
354
355    /// Update connection bytes
356    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    /// Update stream counts
365    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    /// Record connection migration
374    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    /// Get connection info
382    pub fn get_connection(&self, remote_addr: &SocketAddr) -> Option<QuicConnectionInfo> {
383        self.connections.read().get(remote_addr).cloned()
384    }
385
386    /// Get all active connections
387    pub fn get_active_connections(&self) -> Vec<QuicConnectionInfo> {
388        self.connections.read().values().cloned().collect()
389    }
390
391    /// Get statistics
392    pub fn stats(&self) -> QuicStats {
393        self.stats.read().clone()
394    }
395
396    /// Get number of active connections
397    pub fn active_connection_count(&self) -> usize {
398        self.connections.read().len()
399    }
400
401    /// Clear all statistics
402    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); // Disabled for mobile
448        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        // Establish connection
480        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        // Close connection
486        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        // First RTT
600        monitor.update_rtt(&addr, Duration::from_millis(100));
601        assert_eq!(monitor.stats().avg_rtt_ms, 100.0);
602
603        // Second RTT (exponential moving average)
604        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}