quiche/recovery/
mod.rs

1// Copyright (C) 2018-2019, Cloudflare, Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright notice,
9//       this list of conditions and the following disclaimer.
10//
11//     * Redistributions in binary form must reproduce the above copyright
12//       notice, this list of conditions and the following disclaimer in the
13//       documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27use std::str::FromStr;
28use std::time::Duration;
29use std::time::Instant;
30
31use crate::frame;
32use crate::packet;
33use crate::ranges::RangeSet;
34use crate::Config;
35
36#[cfg(feature = "qlog")]
37use qlog::events::EventData;
38
39use smallvec::SmallVec;
40
41use self::congestion::recovery::LegacyRecovery;
42use self::gcongestion::GRecovery;
43pub use gcongestion::BbrBwLoReductionStrategy;
44pub use gcongestion::BbrParams;
45
46// Loss Recovery
47const INITIAL_PACKET_THRESHOLD: u64 = 3;
48
49const MAX_PACKET_THRESHOLD: u64 = 20;
50
51const INITIAL_TIME_THRESHOLD: f64 = 9.0 / 8.0;
52
53const GRANULARITY: Duration = Duration::from_millis(1);
54
55const MAX_PTO_PROBES_COUNT: usize = 2;
56
57const MINIMUM_WINDOW_PACKETS: usize = 2;
58
59const LOSS_REDUCTION_FACTOR: f64 = 0.5;
60
61// How many non ACK eliciting packets we send before including a PING to solicit
62// an ACK.
63pub(super) const MAX_OUTSTANDING_NON_ACK_ELICITING: usize = 24;
64
65#[derive(Default)]
66struct LossDetectionTimer {
67    time: Option<Instant>,
68}
69
70impl LossDetectionTimer {
71    fn update(&mut self, timeout: Instant) {
72        self.time = Some(timeout);
73    }
74
75    fn clear(&mut self) {
76        self.time = None;
77    }
78}
79
80impl std::fmt::Debug for LossDetectionTimer {
81    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
82        match self.time {
83            Some(v) => {
84                let now = Instant::now();
85                if v > now {
86                    let d = v.duration_since(now);
87                    write!(f, "{d:?}")
88                } else {
89                    write!(f, "exp")
90                }
91            },
92            None => write!(f, "none"),
93        }
94    }
95}
96
97#[derive(Clone, Copy, PartialEq)]
98pub struct RecoveryConfig {
99    pub max_send_udp_payload_size: usize,
100    pub max_ack_delay: Duration,
101    pub cc_algorithm: CongestionControlAlgorithm,
102    pub custom_bbr_params: Option<BbrParams>,
103    pub hystart: bool,
104    pub pacing: bool,
105    pub max_pacing_rate: Option<u64>,
106    pub initial_congestion_window_packets: usize,
107}
108
109impl RecoveryConfig {
110    pub fn from_config(config: &Config) -> Self {
111        Self {
112            max_send_udp_payload_size: config.max_send_udp_payload_size,
113            max_ack_delay: Duration::ZERO,
114            cc_algorithm: config.cc_algorithm,
115            custom_bbr_params: config.custom_bbr_params,
116            hystart: config.hystart,
117            pacing: config.pacing,
118            max_pacing_rate: config.max_pacing_rate,
119            initial_congestion_window_packets: config
120                .initial_congestion_window_packets,
121        }
122    }
123}
124
125#[enum_dispatch::enum_dispatch(RecoveryOps)]
126#[allow(clippy::large_enum_variant)]
127#[derive(Debug)]
128pub(crate) enum Recovery {
129    Legacy(LegacyRecovery),
130    GCongestion(GRecovery),
131}
132
133#[enum_dispatch::enum_dispatch]
134/// Api for the Recovery implementation
135pub trait RecoveryOps {
136    fn lost_count(&self) -> usize;
137    fn bytes_lost(&self) -> u64;
138
139    /// Returns whether or not we should elicit an ACK even if we wouldn't
140    /// otherwise have constructed an ACK eliciting packet.
141    fn should_elicit_ack(&self, epoch: packet::Epoch) -> bool;
142
143    fn get_acked_frames(&mut self, epoch: packet::Epoch) -> Vec<frame::Frame>;
144
145    fn get_lost_frames(&mut self, epoch: packet::Epoch) -> Vec<frame::Frame>;
146
147    fn get_largest_acked_on_epoch(&self, epoch: packet::Epoch) -> Option<u64>;
148    fn has_lost_frames(&self, epoch: packet::Epoch) -> bool;
149    fn loss_probes(&self, epoch: packet::Epoch) -> usize;
150    #[cfg(test)]
151    fn inc_loss_probes(&mut self, epoch: packet::Epoch);
152
153    fn ping_sent(&mut self, epoch: packet::Epoch);
154
155    fn on_packet_sent(
156        &mut self, pkt: Sent, epoch: packet::Epoch,
157        handshake_status: HandshakeStatus, now: Instant, trace_id: &str,
158    );
159    fn get_packet_send_time(&self) -> Instant;
160
161    fn on_ack_received(
162        &mut self, ranges: &RangeSet, ack_delay: u64, epoch: packet::Epoch,
163        handshake_status: HandshakeStatus, now: Instant, trace_id: &str,
164    ) -> (usize, usize, usize);
165
166    fn on_loss_detection_timeout(
167        &mut self, handshake_status: HandshakeStatus, now: Instant,
168        trace_id: &str,
169    ) -> (usize, usize);
170    fn on_pkt_num_space_discarded(
171        &mut self, epoch: packet::Epoch, handshake_status: HandshakeStatus,
172        now: Instant,
173    );
174    fn on_path_change(
175        &mut self, epoch: packet::Epoch, now: Instant, _trace_id: &str,
176    ) -> (usize, usize);
177    fn loss_detection_timer(&self) -> Option<Instant>;
178    fn cwnd(&self) -> usize;
179    fn cwnd_available(&self) -> usize;
180    fn rtt(&self) -> Duration;
181
182    fn min_rtt(&self) -> Option<Duration>;
183
184    fn rttvar(&self) -> Duration;
185
186    fn pto(&self) -> Duration;
187
188    fn delivery_rate(&self) -> u64;
189
190    fn max_datagram_size(&self) -> usize;
191
192    fn pmtud_update_max_datagram_size(&mut self, new_max_datagram_size: usize);
193
194    fn update_max_datagram_size(&mut self, new_max_datagram_size: usize);
195
196    fn on_app_limited(&mut self);
197
198    #[cfg(test)]
199    fn app_limited(&self) -> bool;
200
201    #[cfg(test)]
202    fn sent_packets_len(&self, epoch: packet::Epoch) -> usize;
203
204    #[cfg(test)]
205    fn bytes_in_flight(&self) -> usize;
206
207    #[cfg(test)]
208    fn in_flight_count(&self, epoch: packet::Epoch) -> usize;
209
210    #[cfg(test)]
211    fn pacing_rate(&self) -> u64;
212
213    #[cfg(test)]
214    fn pto_count(&self) -> u32;
215
216    #[cfg(test)]
217    fn pkt_thresh(&self) -> u64;
218
219    #[cfg(test)]
220    fn lost_spurious_count(&self) -> usize;
221
222    #[cfg(test)]
223    fn detect_lost_packets_for_test(
224        &mut self, epoch: packet::Epoch, now: Instant,
225    ) -> (usize, usize);
226
227    fn update_app_limited(&mut self, v: bool);
228
229    fn delivery_rate_update_app_limited(&mut self, v: bool);
230
231    fn update_max_ack_delay(&mut self, max_ack_delay: Duration);
232
233    #[cfg(feature = "qlog")]
234    fn maybe_qlog(&mut self) -> Option<EventData>;
235    fn send_quantum(&self) -> usize;
236
237    fn get_next_release_time(&self) -> ReleaseDecision;
238
239    fn gcongestion_enabled(&self) -> bool;
240}
241
242impl Recovery {
243    pub fn new_with_config(recovery_config: &RecoveryConfig) -> Self {
244        let grecovery = GRecovery::new(recovery_config);
245        if let Some(grecovery) = grecovery {
246            Recovery::from(grecovery)
247        } else {
248            Recovery::from(LegacyRecovery::new_with_config(recovery_config))
249        }
250    }
251
252    #[cfg(test)]
253    pub fn new(config: &crate::Config) -> Self {
254        Self::new_with_config(&RecoveryConfig::from_config(config))
255    }
256}
257
258/// Available congestion control algorithms.
259///
260/// This enum provides currently available list of congestion control
261/// algorithms.
262#[derive(Debug, Copy, Clone, PartialEq, Eq)]
263#[repr(C)]
264pub enum CongestionControlAlgorithm {
265    /// Reno congestion control algorithm. `reno` in a string form.
266    Reno            = 0,
267    /// CUBIC congestion control algorithm (default). `cubic` in a string form.
268    CUBIC           = 1,
269    /// BBR congestion control algorithm. `bbr` in a string form.
270    BBR             = 2,
271    /// BBRv2 congestion control algorithm. `bbr2` in a string form.
272    BBR2            = 3,
273    /// BBRv2 congestion control algorithm implementation from gcongestion
274    /// branch. `bbr2_gcongestion` in a string form.
275    Bbr2Gcongestion = 4,
276}
277
278impl FromStr for CongestionControlAlgorithm {
279    type Err = crate::Error;
280
281    /// Converts a string to `CongestionControlAlgorithm`.
282    ///
283    /// If `name` is not valid, `Error::CongestionControl` is returned.
284    fn from_str(name: &str) -> std::result::Result<Self, Self::Err> {
285        match name {
286            "reno" => Ok(CongestionControlAlgorithm::Reno),
287            "cubic" => Ok(CongestionControlAlgorithm::CUBIC),
288            "bbr" => Ok(CongestionControlAlgorithm::BBR),
289            #[cfg(not(feature = "gcongestion"))]
290            "bbr2" => Ok(CongestionControlAlgorithm::BBR2),
291            #[cfg(feature = "gcongestion")]
292            "bbr2" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
293            "bbr2_gcongestion" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
294            _ => Err(crate::Error::CongestionControl),
295        }
296    }
297}
298
299#[derive(Clone)]
300pub struct Sent {
301    pub pkt_num: u64,
302
303    pub frames: SmallVec<[frame::Frame; 1]>,
304
305    pub time_sent: Instant,
306
307    pub time_acked: Option<Instant>,
308
309    pub time_lost: Option<Instant>,
310
311    pub size: usize,
312
313    pub ack_eliciting: bool,
314
315    pub in_flight: bool,
316
317    pub delivered: usize,
318
319    pub delivered_time: Instant,
320
321    pub first_sent_time: Instant,
322
323    pub is_app_limited: bool,
324
325    pub tx_in_flight: usize,
326
327    pub lost: u64,
328
329    pub has_data: bool,
330
331    pub pmtud: bool,
332}
333
334impl std::fmt::Debug for Sent {
335    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
336        write!(f, "pkt_num={:?} ", self.pkt_num)?;
337        write!(f, "pkt_sent_time={:?} ", self.time_sent)?;
338        write!(f, "pkt_size={:?} ", self.size)?;
339        write!(f, "delivered={:?} ", self.delivered)?;
340        write!(f, "delivered_time={:?} ", self.delivered_time)?;
341        write!(f, "first_sent_time={:?} ", self.first_sent_time)?;
342        write!(f, "is_app_limited={} ", self.is_app_limited)?;
343        write!(f, "tx_in_flight={} ", self.tx_in_flight)?;
344        write!(f, "lost={} ", self.lost)?;
345        write!(f, "has_data={} ", self.has_data)?;
346        write!(f, "pmtud={}", self.pmtud)?;
347
348        Ok(())
349    }
350}
351
352#[derive(Clone, Copy, Debug)]
353pub struct HandshakeStatus {
354    pub has_handshake_keys: bool,
355
356    pub peer_verified_address: bool,
357
358    pub completed: bool,
359}
360
361#[cfg(test)]
362impl Default for HandshakeStatus {
363    fn default() -> HandshakeStatus {
364        HandshakeStatus {
365            has_handshake_keys: true,
366
367            peer_verified_address: true,
368
369            completed: true,
370        }
371    }
372}
373
374// We don't need to log all qlog metrics every time there is a recovery event.
375// Instead, we can log only the MetricsUpdated event data fields that we care
376// about, only when they change. To support this, the QLogMetrics structure
377// keeps a running picture of the fields.
378#[derive(Default)]
379#[cfg(feature = "qlog")]
380struct QlogMetrics {
381    min_rtt: Duration,
382    smoothed_rtt: Duration,
383    latest_rtt: Duration,
384    rttvar: Duration,
385    cwnd: u64,
386    bytes_in_flight: u64,
387    ssthresh: Option<u64>,
388    pacing_rate: u64,
389}
390
391#[cfg(feature = "qlog")]
392impl QlogMetrics {
393    // Make a qlog event if the latest instance of QlogMetrics is different.
394    //
395    // This function diffs each of the fields. A qlog MetricsUpdated event is
396    // only generated if at least one field is different. Where fields are
397    // different, the qlog event contains the latest value.
398    fn maybe_update(&mut self, latest: Self) -> Option<EventData> {
399        let mut emit_event = false;
400
401        let new_min_rtt = if self.min_rtt != latest.min_rtt {
402            self.min_rtt = latest.min_rtt;
403            emit_event = true;
404            Some(latest.min_rtt.as_secs_f32() * 1000.0)
405        } else {
406            None
407        };
408
409        let new_smoothed_rtt = if self.smoothed_rtt != latest.smoothed_rtt {
410            self.smoothed_rtt = latest.smoothed_rtt;
411            emit_event = true;
412            Some(latest.smoothed_rtt.as_secs_f32() * 1000.0)
413        } else {
414            None
415        };
416
417        let new_latest_rtt = if self.latest_rtt != latest.latest_rtt {
418            self.latest_rtt = latest.latest_rtt;
419            emit_event = true;
420            Some(latest.latest_rtt.as_secs_f32() * 1000.0)
421        } else {
422            None
423        };
424
425        let new_rttvar = if self.rttvar != latest.rttvar {
426            self.rttvar = latest.rttvar;
427            emit_event = true;
428            Some(latest.rttvar.as_secs_f32() * 1000.0)
429        } else {
430            None
431        };
432
433        let new_cwnd = if self.cwnd != latest.cwnd {
434            self.cwnd = latest.cwnd;
435            emit_event = true;
436            Some(latest.cwnd)
437        } else {
438            None
439        };
440
441        let new_bytes_in_flight =
442            if self.bytes_in_flight != latest.bytes_in_flight {
443                self.bytes_in_flight = latest.bytes_in_flight;
444                emit_event = true;
445                Some(latest.bytes_in_flight)
446            } else {
447                None
448            };
449
450        let new_ssthresh = if self.ssthresh != latest.ssthresh {
451            self.ssthresh = latest.ssthresh;
452            emit_event = true;
453            latest.ssthresh
454        } else {
455            None
456        };
457
458        let new_pacing_rate = if self.pacing_rate != latest.pacing_rate {
459            self.pacing_rate = latest.pacing_rate;
460            emit_event = true;
461            Some(latest.pacing_rate)
462        } else {
463            None
464        };
465
466        if emit_event {
467            // QVis can't use all these fields and they can be large.
468            return Some(EventData::MetricsUpdated(
469                qlog::events::quic::MetricsUpdated {
470                    min_rtt: new_min_rtt,
471                    smoothed_rtt: new_smoothed_rtt,
472                    latest_rtt: new_latest_rtt,
473                    rtt_variance: new_rttvar,
474                    congestion_window: new_cwnd,
475                    bytes_in_flight: new_bytes_in_flight,
476                    ssthresh: new_ssthresh,
477                    pacing_rate: new_pacing_rate,
478                    ..Default::default()
479                },
480            ));
481        }
482
483        None
484    }
485}
486
487/// When the pacer thinks is a good time to release the next packet
488#[derive(Debug, Clone, Copy, PartialEq, Eq)]
489pub enum ReleaseTime {
490    Immediate,
491    At(Instant),
492}
493
494/// When the next packet should be release and if it can be part of a burst
495#[derive(Clone, Copy, Debug, PartialEq, Eq)]
496pub struct ReleaseDecision {
497    time: ReleaseTime,
498    allow_burst: bool,
499}
500
501impl ReleaseTime {
502    /// Add the specific delay to the current time
503    #[allow(dead_code)]
504    fn inc(&mut self, delay: Duration) {
505        match self {
506            ReleaseTime::Immediate => {},
507            ReleaseTime::At(time) => *time += delay,
508        }
509    }
510
511    /// Set the time to the later of two times
512    #[allow(dead_code)]
513    fn set_max(&mut self, other: Instant) {
514        match self {
515            ReleaseTime::Immediate => *self = ReleaseTime::At(other),
516            ReleaseTime::At(time) => *self = ReleaseTime::At(other.max(*time)),
517        }
518    }
519}
520
521impl ReleaseDecision {
522    pub(crate) const EQUAL_THRESHOLD: Duration = Duration::from_micros(50);
523
524    /// Get the [`Instant`] the next packet should be released. It will never be
525    /// in the past.
526    #[allow(dead_code)]
527    #[inline]
528    pub fn time(&self, now: Instant) -> Option<Instant> {
529        match self.time {
530            ReleaseTime::Immediate => None,
531            ReleaseTime::At(other) => other.gt(&now).then_some(other),
532        }
533    }
534
535    /// Can this packet be appended to a previous burst
536    #[allow(dead_code)]
537    #[inline]
538    pub fn can_burst(&self) -> bool {
539        self.allow_burst
540    }
541
542    /// Check if the two packets can be released at the same time
543    #[allow(dead_code)]
544    #[inline]
545    pub fn time_eq(&self, other: &Self, now: Instant) -> bool {
546        let delta = match (self.time(now), other.time(now)) {
547            (None, None) => Duration::ZERO,
548            (Some(t), None) | (None, Some(t)) => t.duration_since(now),
549            (Some(t1), Some(t2)) if t1 < t2 => t2.duration_since(t1),
550            (Some(t1), Some(t2)) => t1.duration_since(t2),
551        };
552
553        delta <= Self::EQUAL_THRESHOLD
554    }
555}
556
557#[cfg(test)]
558mod tests {
559    use super::*;
560    use crate::packet;
561    use crate::ranges;
562    use crate::recovery::congestion::PACING_MULTIPLIER;
563    use crate::CongestionControlAlgorithm;
564    use smallvec::smallvec;
565    use std::str::FromStr;
566
567    fn recovery_for_alg(algo: CongestionControlAlgorithm) -> Recovery {
568        let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
569        cfg.set_cc_algorithm(algo);
570        Recovery::new(&cfg)
571    }
572
573    #[test]
574    fn lookup_cc_algo_ok() {
575        let algo = CongestionControlAlgorithm::from_str("reno").unwrap();
576        assert_eq!(algo, CongestionControlAlgorithm::Reno);
577        assert!(!recovery_for_alg(algo).gcongestion_enabled());
578
579        let algo = CongestionControlAlgorithm::from_str("cubic").unwrap();
580        assert_eq!(algo, CongestionControlAlgorithm::CUBIC);
581        assert!(!recovery_for_alg(algo).gcongestion_enabled());
582
583        let algo = CongestionControlAlgorithm::from_str("bbr").unwrap();
584        assert_eq!(algo, CongestionControlAlgorithm::BBR);
585        assert!(!recovery_for_alg(algo).gcongestion_enabled());
586
587        let algo = CongestionControlAlgorithm::from_str("bbr2").unwrap();
588        #[cfg(not(feature = "gcongestion"))]
589        {
590            assert_eq!(algo, CongestionControlAlgorithm::BBR2);
591            assert!(!recovery_for_alg(algo).gcongestion_enabled());
592        }
593        #[cfg(feature = "gcongestion")]
594        {
595            assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
596            assert!(recovery_for_alg(algo).gcongestion_enabled());
597        }
598
599        let algo =
600            CongestionControlAlgorithm::from_str("bbr2_gcongestion").unwrap();
601        assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
602        assert!(recovery_for_alg(algo).gcongestion_enabled());
603    }
604
605    #[test]
606    fn lookup_cc_algo_bad() {
607        assert_eq!(
608            CongestionControlAlgorithm::from_str("???"),
609            Err(crate::Error::CongestionControl)
610        );
611    }
612
613    #[test]
614    fn loss_on_pto() {
615        let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
616        cfg.set_cc_algorithm(CongestionControlAlgorithm::Reno);
617
618        let mut r = Recovery::new(&cfg);
619
620        let mut now = Instant::now();
621
622        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
623
624        // Start by sending a few packets.
625        let p = Sent {
626            pkt_num: 0,
627            frames: smallvec![],
628            time_sent: now,
629            time_acked: None,
630            time_lost: None,
631            size: 1000,
632            ack_eliciting: true,
633            in_flight: true,
634            delivered: 0,
635            delivered_time: now,
636            first_sent_time: now,
637            is_app_limited: false,
638            tx_in_flight: 0,
639            lost: 0,
640            has_data: false,
641            pmtud: false,
642        };
643
644        r.on_packet_sent(
645            p,
646            packet::Epoch::Application,
647            HandshakeStatus::default(),
648            now,
649            "",
650        );
651
652        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
653        assert_eq!(r.bytes_in_flight(), 1000);
654
655        let p = Sent {
656            pkt_num: 1,
657            frames: smallvec![],
658            time_sent: now,
659            time_acked: None,
660            time_lost: None,
661            size: 1000,
662            ack_eliciting: true,
663            in_flight: true,
664            delivered: 0,
665            delivered_time: now,
666            first_sent_time: now,
667            is_app_limited: false,
668            tx_in_flight: 0,
669            lost: 0,
670            has_data: false,
671            pmtud: false,
672        };
673
674        r.on_packet_sent(
675            p,
676            packet::Epoch::Application,
677            HandshakeStatus::default(),
678            now,
679            "",
680        );
681
682        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
683        assert_eq!(r.bytes_in_flight(), 2000);
684
685        let p = Sent {
686            pkt_num: 2,
687            frames: smallvec![],
688            time_sent: now,
689            time_acked: None,
690            time_lost: None,
691            size: 1000,
692            ack_eliciting: true,
693            in_flight: true,
694            delivered: 0,
695            delivered_time: now,
696            first_sent_time: now,
697            is_app_limited: false,
698            tx_in_flight: 0,
699            lost: 0,
700            has_data: false,
701            pmtud: false,
702        };
703
704        r.on_packet_sent(
705            p,
706            packet::Epoch::Application,
707            HandshakeStatus::default(),
708            now,
709            "",
710        );
711        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
712        assert_eq!(r.bytes_in_flight(), 3000);
713
714        let p = Sent {
715            pkt_num: 3,
716            frames: smallvec![],
717            time_sent: now,
718            time_acked: None,
719            time_lost: None,
720            size: 1000,
721            ack_eliciting: true,
722            in_flight: true,
723            delivered: 0,
724            delivered_time: now,
725            first_sent_time: now,
726            is_app_limited: false,
727            tx_in_flight: 0,
728            lost: 0,
729            has_data: false,
730            pmtud: false,
731        };
732
733        r.on_packet_sent(
734            p,
735            packet::Epoch::Application,
736            HandshakeStatus::default(),
737            now,
738            "",
739        );
740        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
741        assert_eq!(r.bytes_in_flight(), 4000);
742
743        // Wait for 10ms.
744        now += Duration::from_millis(10);
745
746        // Only the first 2 packets are acked.
747        let mut acked = ranges::RangeSet::default();
748        acked.insert(0..2);
749
750        assert_eq!(
751            r.on_ack_received(
752                &acked,
753                25,
754                packet::Epoch::Application,
755                HandshakeStatus::default(),
756                now,
757                "",
758            ),
759            (0, 0, 2 * 1000)
760        );
761
762        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
763        assert_eq!(r.bytes_in_flight(), 2000);
764        assert_eq!(r.lost_count(), 0);
765
766        // Wait until loss detection timer expires.
767        now = r.loss_detection_timer().unwrap();
768
769        // PTO.
770        r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
771        assert_eq!(r.loss_probes(packet::Epoch::Application), 1);
772        assert_eq!(r.lost_count(), 0);
773        assert_eq!(r.pto_count(), 1);
774
775        let p = Sent {
776            pkt_num: 4,
777            frames: smallvec![],
778            time_sent: now,
779            time_acked: None,
780            time_lost: None,
781            size: 1000,
782            ack_eliciting: true,
783            in_flight: true,
784            delivered: 0,
785            delivered_time: now,
786            first_sent_time: now,
787            is_app_limited: false,
788            tx_in_flight: 0,
789            lost: 0,
790            has_data: false,
791            pmtud: false,
792        };
793
794        r.on_packet_sent(
795            p,
796            packet::Epoch::Application,
797            HandshakeStatus::default(),
798            now,
799            "",
800        );
801        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
802        assert_eq!(r.bytes_in_flight(), 3000);
803
804        let p = Sent {
805            pkt_num: 5,
806            frames: smallvec![],
807            time_sent: now,
808            time_acked: None,
809            time_lost: None,
810            size: 1000,
811            ack_eliciting: true,
812            in_flight: true,
813            delivered: 0,
814            delivered_time: now,
815            first_sent_time: now,
816            is_app_limited: false,
817            tx_in_flight: 0,
818            lost: 0,
819            has_data: false,
820            pmtud: false,
821        };
822
823        r.on_packet_sent(
824            p,
825            packet::Epoch::Application,
826            HandshakeStatus::default(),
827            now,
828            "",
829        );
830        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
831        assert_eq!(r.bytes_in_flight(), 4000);
832        assert_eq!(r.lost_count(), 0);
833
834        // Wait for 10ms.
835        now += Duration::from_millis(10);
836
837        // PTO packets are acked.
838        let mut acked = ranges::RangeSet::default();
839        acked.insert(4..6);
840
841        assert_eq!(
842            r.on_ack_received(
843                &acked,
844                25,
845                packet::Epoch::Application,
846                HandshakeStatus::default(),
847                now,
848                "",
849            ),
850            (2, 2000, 2 * 1000)
851        );
852
853        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
854        assert_eq!(r.bytes_in_flight(), 0);
855
856        assert_eq!(r.lost_count(), 2);
857
858        // Wait 1 RTT.
859        now += r.rtt();
860
861        assert_eq!(
862            r.detect_lost_packets_for_test(packet::Epoch::Application, now),
863            (0, 0)
864        );
865
866        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
867    }
868
869    #[test]
870    fn loss_on_timer() {
871        let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
872        cfg.set_cc_algorithm(CongestionControlAlgorithm::Reno);
873
874        let mut r = Recovery::new(&cfg);
875
876        let mut now = Instant::now();
877
878        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
879
880        // Start by sending a few packets.
881        let p = Sent {
882            pkt_num: 0,
883            frames: smallvec![],
884            time_sent: now,
885            time_acked: None,
886            time_lost: None,
887            size: 1000,
888            ack_eliciting: true,
889            in_flight: true,
890            delivered: 0,
891            delivered_time: now,
892            first_sent_time: now,
893            is_app_limited: false,
894            tx_in_flight: 0,
895            lost: 0,
896            has_data: false,
897            pmtud: false,
898        };
899
900        r.on_packet_sent(
901            p,
902            packet::Epoch::Application,
903            HandshakeStatus::default(),
904            now,
905            "",
906        );
907        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
908        assert_eq!(r.bytes_in_flight(), 1000);
909
910        let p = Sent {
911            pkt_num: 1,
912            frames: smallvec![],
913            time_sent: now,
914            time_acked: None,
915            time_lost: None,
916            size: 1000,
917            ack_eliciting: true,
918            in_flight: true,
919            delivered: 0,
920            delivered_time: now,
921            first_sent_time: now,
922            is_app_limited: false,
923            tx_in_flight: 0,
924            lost: 0,
925            has_data: false,
926            pmtud: false,
927        };
928
929        r.on_packet_sent(
930            p,
931            packet::Epoch::Application,
932            HandshakeStatus::default(),
933            now,
934            "",
935        );
936        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
937        assert_eq!(r.bytes_in_flight(), 2000);
938
939        let p = Sent {
940            pkt_num: 2,
941            frames: smallvec![],
942            time_sent: now,
943            time_acked: None,
944            time_lost: None,
945            size: 1000,
946            ack_eliciting: true,
947            in_flight: true,
948            delivered: 0,
949            delivered_time: now,
950            first_sent_time: now,
951            is_app_limited: false,
952            tx_in_flight: 0,
953            lost: 0,
954            has_data: false,
955            pmtud: false,
956        };
957
958        r.on_packet_sent(
959            p,
960            packet::Epoch::Application,
961            HandshakeStatus::default(),
962            now,
963            "",
964        );
965        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
966        assert_eq!(r.bytes_in_flight(), 3000);
967
968        let p = Sent {
969            pkt_num: 3,
970            frames: smallvec![],
971            time_sent: now,
972            time_acked: None,
973            time_lost: None,
974            size: 1000,
975            ack_eliciting: true,
976            in_flight: true,
977            delivered: 0,
978            delivered_time: now,
979            first_sent_time: now,
980            is_app_limited: false,
981            tx_in_flight: 0,
982            lost: 0,
983            has_data: false,
984            pmtud: false,
985        };
986
987        r.on_packet_sent(
988            p,
989            packet::Epoch::Application,
990            HandshakeStatus::default(),
991            now,
992            "",
993        );
994        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
995        assert_eq!(r.bytes_in_flight(), 4000);
996
997        // Wait for 10ms.
998        now += Duration::from_millis(10);
999
1000        // Only the first 2 packets and the last one are acked.
1001        let mut acked = ranges::RangeSet::default();
1002        acked.insert(0..2);
1003        acked.insert(3..4);
1004
1005        assert_eq!(
1006            r.on_ack_received(
1007                &acked,
1008                25,
1009                packet::Epoch::Application,
1010                HandshakeStatus::default(),
1011                now,
1012                "",
1013            ),
1014            (0, 0, 3 * 1000)
1015        );
1016
1017        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1018        assert_eq!(r.bytes_in_flight(), 1000);
1019        assert_eq!(r.lost_count(), 0);
1020
1021        // Wait until loss detection timer expires.
1022        now = r.loss_detection_timer().unwrap();
1023
1024        // Packet is declared lost.
1025        r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
1026        assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
1027
1028        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1029        assert_eq!(r.bytes_in_flight(), 0);
1030
1031        assert_eq!(r.lost_count(), 1);
1032
1033        // Wait 1 RTT.
1034        now += r.rtt();
1035
1036        assert_eq!(
1037            r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1038            (0, 0)
1039        );
1040
1041        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1042    }
1043
1044    #[test]
1045    fn loss_on_reordering() {
1046        let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
1047        cfg.set_cc_algorithm(CongestionControlAlgorithm::Reno);
1048
1049        let mut r = Recovery::new(&cfg);
1050
1051        let mut now = Instant::now();
1052
1053        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1054
1055        // Start by sending a few packets.
1056        let p = Sent {
1057            pkt_num: 0,
1058            frames: smallvec![],
1059            time_sent: now,
1060            time_acked: None,
1061            time_lost: None,
1062            size: 1000,
1063            ack_eliciting: true,
1064            in_flight: true,
1065            delivered: 0,
1066            delivered_time: now,
1067            first_sent_time: now,
1068            is_app_limited: false,
1069            tx_in_flight: 0,
1070            lost: 0,
1071            has_data: false,
1072            pmtud: false,
1073        };
1074
1075        r.on_packet_sent(
1076            p,
1077            packet::Epoch::Application,
1078            HandshakeStatus::default(),
1079            now,
1080            "",
1081        );
1082        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1083        assert_eq!(r.bytes_in_flight(), 1000);
1084
1085        let p = Sent {
1086            pkt_num: 1,
1087            frames: smallvec![],
1088            time_sent: now,
1089            time_acked: None,
1090            time_lost: None,
1091            size: 1000,
1092            ack_eliciting: true,
1093            in_flight: true,
1094            delivered: 0,
1095            delivered_time: now,
1096            first_sent_time: now,
1097            is_app_limited: false,
1098            tx_in_flight: 0,
1099            lost: 0,
1100            has_data: false,
1101            pmtud: false,
1102        };
1103
1104        r.on_packet_sent(
1105            p,
1106            packet::Epoch::Application,
1107            HandshakeStatus::default(),
1108            now,
1109            "",
1110        );
1111        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1112        assert_eq!(r.bytes_in_flight(), 2000);
1113
1114        let p = Sent {
1115            pkt_num: 2,
1116            frames: smallvec![],
1117            time_sent: now,
1118            time_acked: None,
1119            time_lost: None,
1120            size: 1000,
1121            ack_eliciting: true,
1122            in_flight: true,
1123            delivered: 0,
1124            delivered_time: now,
1125            first_sent_time: now,
1126            is_app_limited: false,
1127            tx_in_flight: 0,
1128            lost: 0,
1129            has_data: false,
1130            pmtud: false,
1131        };
1132
1133        r.on_packet_sent(
1134            p,
1135            packet::Epoch::Application,
1136            HandshakeStatus::default(),
1137            now,
1138            "",
1139        );
1140        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1141        assert_eq!(r.bytes_in_flight(), 3000);
1142
1143        let p = Sent {
1144            pkt_num: 3,
1145            frames: smallvec![],
1146            time_sent: now,
1147            time_acked: None,
1148            time_lost: None,
1149            size: 1000,
1150            ack_eliciting: true,
1151            in_flight: true,
1152            delivered: 0,
1153            delivered_time: now,
1154            first_sent_time: now,
1155            is_app_limited: false,
1156            tx_in_flight: 0,
1157            lost: 0,
1158            has_data: false,
1159            pmtud: false,
1160        };
1161
1162        r.on_packet_sent(
1163            p,
1164            packet::Epoch::Application,
1165            HandshakeStatus::default(),
1166            now,
1167            "",
1168        );
1169        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1170        assert_eq!(r.bytes_in_flight(), 4000);
1171
1172        // Wait for 10ms.
1173        now += Duration::from_millis(10);
1174
1175        // ACKs are reordered.
1176        let mut acked = ranges::RangeSet::default();
1177        acked.insert(2..4);
1178
1179        assert_eq!(
1180            r.on_ack_received(
1181                &acked,
1182                25,
1183                packet::Epoch::Application,
1184                HandshakeStatus::default(),
1185                now,
1186                "",
1187            ),
1188            (1, 1000, 1000 * 2)
1189        );
1190
1191        now += Duration::from_millis(10);
1192
1193        let mut acked = ranges::RangeSet::default();
1194        acked.insert(0..2);
1195
1196        assert_eq!(r.pkt_thresh(), INITIAL_PACKET_THRESHOLD);
1197
1198        assert_eq!(
1199            r.on_ack_received(
1200                &acked,
1201                25,
1202                packet::Epoch::Application,
1203                HandshakeStatus::default(),
1204                now,
1205                "",
1206            ),
1207            (0, 0, 1000)
1208        );
1209
1210        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1211        assert_eq!(r.bytes_in_flight(), 0);
1212
1213        // Spurious loss.
1214        assert_eq!(r.lost_count(), 1);
1215        assert_eq!(r.lost_spurious_count(), 1);
1216
1217        // Packet threshold was increased.
1218        assert_eq!(r.pkt_thresh(), 4);
1219
1220        // Wait 1 RTT.
1221        now += r.rtt();
1222
1223        assert_eq!(
1224            r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1225            (0, 0)
1226        );
1227
1228        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1229    }
1230
1231    #[test]
1232    fn pacing() {
1233        let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
1234        cfg.set_cc_algorithm(CongestionControlAlgorithm::CUBIC);
1235
1236        let mut r = Recovery::new(&cfg);
1237
1238        let mut now = Instant::now();
1239
1240        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1241
1242        // send out first packet (a full initcwnd).
1243        let p = Sent {
1244            pkt_num: 0,
1245            frames: smallvec![],
1246            time_sent: now,
1247            time_acked: None,
1248            time_lost: None,
1249            size: 12000,
1250            ack_eliciting: true,
1251            in_flight: true,
1252            delivered: 0,
1253            delivered_time: now,
1254            first_sent_time: now,
1255            is_app_limited: false,
1256            tx_in_flight: 0,
1257            lost: 0,
1258            has_data: false,
1259            pmtud: false,
1260        };
1261
1262        r.on_packet_sent(
1263            p,
1264            packet::Epoch::Application,
1265            HandshakeStatus::default(),
1266            now,
1267            "",
1268        );
1269
1270        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1271        assert_eq!(r.bytes_in_flight(), 12000);
1272
1273        // First packet will be sent out immediately.
1274        assert_eq!(r.pacing_rate(), 0);
1275        assert_eq!(r.get_packet_send_time(), now);
1276
1277        // Wait 50ms for ACK.
1278        now += Duration::from_millis(50);
1279
1280        let mut acked = ranges::RangeSet::default();
1281        acked.insert(0..1);
1282
1283        assert_eq!(
1284            r.on_ack_received(
1285                &acked,
1286                10,
1287                packet::Epoch::Application,
1288                HandshakeStatus::default(),
1289                now,
1290                "",
1291            ),
1292            (0, 0, 12000)
1293        );
1294
1295        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1296        assert_eq!(r.bytes_in_flight(), 0);
1297        assert_eq!(r.rtt(), Duration::from_millis(50));
1298
1299        // 1 MSS increased.
1300        assert_eq!(r.cwnd(), 12000 + 1200);
1301
1302        // Send out second packet.
1303        let p = Sent {
1304            pkt_num: 1,
1305            frames: smallvec![],
1306            time_sent: now,
1307            time_acked: None,
1308            time_lost: None,
1309            size: 6000,
1310            ack_eliciting: true,
1311            in_flight: true,
1312            delivered: 0,
1313            delivered_time: now,
1314            first_sent_time: now,
1315            is_app_limited: false,
1316            tx_in_flight: 0,
1317            lost: 0,
1318            has_data: false,
1319            pmtud: false,
1320        };
1321
1322        r.on_packet_sent(
1323            p,
1324            packet::Epoch::Application,
1325            HandshakeStatus::default(),
1326            now,
1327            "",
1328        );
1329
1330        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1331        assert_eq!(r.bytes_in_flight(), 6000);
1332
1333        // Pacing is not done during initial phase of connection.
1334        assert_eq!(r.get_packet_send_time(), now);
1335
1336        // Send the third packet out.
1337        let p = Sent {
1338            pkt_num: 2,
1339            frames: smallvec![],
1340            time_sent: now,
1341            time_acked: None,
1342            time_lost: None,
1343            size: 6000,
1344            ack_eliciting: true,
1345            in_flight: true,
1346            delivered: 0,
1347            delivered_time: now,
1348            first_sent_time: now,
1349            is_app_limited: false,
1350            tx_in_flight: 0,
1351            lost: 0,
1352            has_data: false,
1353            pmtud: false,
1354        };
1355
1356        r.on_packet_sent(
1357            p,
1358            packet::Epoch::Application,
1359            HandshakeStatus::default(),
1360            now,
1361            "",
1362        );
1363
1364        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1365        assert_eq!(r.bytes_in_flight(), 12000);
1366
1367        // Send the third packet out.
1368        let p = Sent {
1369            pkt_num: 3,
1370            frames: smallvec![],
1371            time_sent: now,
1372            time_acked: None,
1373            time_lost: None,
1374            size: 1000,
1375            ack_eliciting: true,
1376            in_flight: true,
1377            delivered: 0,
1378            delivered_time: now,
1379            first_sent_time: now,
1380            is_app_limited: false,
1381            tx_in_flight: 0,
1382            lost: 0,
1383            has_data: false,
1384            pmtud: false,
1385        };
1386
1387        r.on_packet_sent(
1388            p,
1389            packet::Epoch::Application,
1390            HandshakeStatus::default(),
1391            now,
1392            "",
1393        );
1394
1395        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1396        assert_eq!(r.bytes_in_flight(), 13000);
1397
1398        // We pace this outgoing packet. as all conditions for pacing
1399        // are passed.
1400        let pacing_rate = (r.cwnd() as f64 * PACING_MULTIPLIER / 0.05) as u64;
1401        assert_eq!(r.pacing_rate(), pacing_rate);
1402
1403        assert_eq!(
1404            r.get_packet_send_time(),
1405            now + Duration::from_secs_f64(12000.0 / pacing_rate as f64)
1406        );
1407    }
1408
1409    #[test]
1410    fn pmtud_loss_on_timer() {
1411        let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
1412        cfg.set_cc_algorithm(CongestionControlAlgorithm::Reno);
1413
1414        let mut r = Recovery::new(&cfg);
1415
1416        let mut now = Instant::now();
1417
1418        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1419
1420        // Start by sending a few packets.
1421        let p = Sent {
1422            pkt_num: 0,
1423            frames: smallvec![],
1424            time_sent: now,
1425            time_acked: None,
1426            time_lost: None,
1427            size: 1000,
1428            ack_eliciting: true,
1429            in_flight: true,
1430            delivered: 0,
1431            delivered_time: now,
1432            first_sent_time: now,
1433            is_app_limited: false,
1434            tx_in_flight: 0,
1435            lost: 0,
1436            has_data: false,
1437            pmtud: false,
1438        };
1439
1440        r.on_packet_sent(
1441            p,
1442            packet::Epoch::Application,
1443            HandshakeStatus::default(),
1444            now,
1445            "",
1446        );
1447
1448        assert_eq!(r.in_flight_count(packet::Epoch::Application), 1);
1449        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1450        assert_eq!(r.bytes_in_flight(), 1000);
1451
1452        let p = Sent {
1453            pkt_num: 1,
1454            frames: smallvec![],
1455            time_sent: now,
1456            time_acked: None,
1457            time_lost: None,
1458            size: 1000,
1459            ack_eliciting: true,
1460            in_flight: true,
1461            delivered: 0,
1462            delivered_time: now,
1463            first_sent_time: now,
1464            is_app_limited: false,
1465            tx_in_flight: 0,
1466            lost: 0,
1467            has_data: false,
1468            pmtud: true,
1469        };
1470
1471        r.on_packet_sent(
1472            p,
1473            packet::Epoch::Application,
1474            HandshakeStatus::default(),
1475            now,
1476            "",
1477        );
1478
1479        assert_eq!(r.in_flight_count(packet::Epoch::Application), 2);
1480
1481        let p = Sent {
1482            pkt_num: 2,
1483            frames: smallvec![],
1484            time_sent: now,
1485            time_acked: None,
1486            time_lost: None,
1487            size: 1000,
1488            ack_eliciting: true,
1489            in_flight: true,
1490            delivered: 0,
1491            delivered_time: now,
1492            first_sent_time: now,
1493            is_app_limited: false,
1494            tx_in_flight: 0,
1495            lost: 0,
1496            has_data: false,
1497            pmtud: false,
1498        };
1499
1500        r.on_packet_sent(
1501            p,
1502            packet::Epoch::Application,
1503            HandshakeStatus::default(),
1504            now,
1505            "",
1506        );
1507
1508        assert_eq!(r.in_flight_count(packet::Epoch::Application), 3);
1509
1510        // Wait for 10ms.
1511        now += Duration::from_millis(10);
1512
1513        // Only the first  packets and the last one are acked.
1514        let mut acked = ranges::RangeSet::default();
1515        acked.insert(0..1);
1516        acked.insert(2..3);
1517
1518        assert_eq!(
1519            r.on_ack_received(
1520                &acked,
1521                25,
1522                packet::Epoch::Application,
1523                HandshakeStatus::default(),
1524                now,
1525                "",
1526            ),
1527            (0, 0, 2 * 1000)
1528        );
1529
1530        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1531        assert_eq!(r.bytes_in_flight(), 1000);
1532        assert_eq!(r.lost_count(), 0);
1533
1534        // Wait until loss detection timer expires.
1535        now = r.loss_detection_timer().unwrap();
1536
1537        // Packet is declared lost.
1538        r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
1539        assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
1540
1541        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1542        assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
1543        assert_eq!(r.bytes_in_flight(), 0);
1544        assert_eq!(r.cwnd(), 12000);
1545
1546        assert_eq!(r.lost_count(), 0);
1547
1548        // Wait 1 RTT.
1549        now += r.rtt();
1550
1551        assert_eq!(
1552            r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1553            (0, 0)
1554        );
1555
1556        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1557        assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
1558        assert_eq!(r.bytes_in_flight(), 0);
1559        assert_eq!(r.lost_count(), 0);
1560    }
1561}
1562
1563mod congestion;
1564mod gcongestion;
1565mod rtt;