diff --git a/src/recovery/mod.rs b/src/recovery/mod.rs index 9feffc968c..892794d00e 100644 --- a/src/recovery/mod.rs +++ b/src/recovery/mod.rs @@ -256,7 +256,8 @@ impl Recovery { // Pacing: Set the pacing rate if BBR is not used if self.pacing_enabled && - self.cc_algo == CongestionControlAlgorithm::CUBIC + (self.cc_algo == CongestionControlAlgorithm::CUBIC || + self.cc_algo == CongestionControlAlgorithm::Reno) { let rate = match self.smoothed_rtt { Some(srtt) => @@ -1639,6 +1640,144 @@ mod tests { // Spurious loss. assert_eq!(r.lost_count, 1); } + + #[test] + fn test_packet_pacing() { + let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap(); + cfg.set_cc_algorithm(CongestionControlAlgorithm::CUBIC); + + let mut r = Recovery::new(&cfg); + + let mut now = Instant::now(); + + assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0); + + // send out first packet. + let p = Sent { + pkt_num: 0, + frames: vec![], + time_sent: now, + time_acked: None, + time_lost: None, + size: 6500, + ack_eliciting: true, + in_flight: true, + delivered: 0, + delivered_time: now, + recent_delivered_packet_sent_time: now, + is_app_limited: false, + has_data: false, + }; + + assert_eq!(r.pacing_enabled, true); + + r.on_packet_sent( + p, + packet::EPOCH_APPLICATION, + HandshakeStatus::default(), + now, + "", + ); + + assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 1); + assert_eq!(r.bytes_in_flight, 6500); + + // First packet will be sent out immidiately. + assert_eq!(r.pacing_rate, 0); + assert_eq!(r.get_packet_send_time().unwrap(), now); + + // Wait 50ms for ACK. + now += Duration::from_millis(50); + + let mut acked = ranges::RangeSet::default(); + acked.insert(0..1); + + assert_eq!( + r.on_ack_received( + &acked, + 10, + packet::EPOCH_APPLICATION, + HandshakeStatus::default(), + now, + "" + ), + Ok(()) + ); + + assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 0); + assert_eq!(r.bytes_in_flight, 0); + assert_eq!(r.smoothed_rtt.unwrap(), Duration::from_millis(50)); + + // Send out second packet. + let p = Sent { + pkt_num: 1, + frames: vec![], + time_sent: now, + time_acked: None, + time_lost: None, + size: 6500, + ack_eliciting: true, + in_flight: true, + delivered: 0, + delivered_time: now, + recent_delivered_packet_sent_time: now, + is_app_limited: false, + has_data: false, + }; + + r.on_packet_sent( + p, + packet::EPOCH_APPLICATION, + HandshakeStatus::default(), + now, + "", + ); + + assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 1); + assert_eq!(r.bytes_in_flight, 6500); + + // Pacing is not done during intial phase of connection. + assert_eq!(r.get_packet_send_time().unwrap(), now); + + // Send the third packet out. + let p = Sent { + pkt_num: 2, + frames: vec![], + time_sent: now, + time_acked: None, + time_lost: None, + size: 6500, + ack_eliciting: true, + in_flight: true, + delivered: 0, + delivered_time: now, + recent_delivered_packet_sent_time: now, + is_app_limited: false, + has_data: false, + }; + + r.on_packet_sent( + p, + packet::EPOCH_APPLICATION, + HandshakeStatus::default(), + now, + "", + ); + + assert_eq!(r.sent[packet::EPOCH_APPLICATION].len(), 2); + assert_eq!(r.bytes_in_flight, 13000); + assert_eq!(r.smoothed_rtt.unwrap(), Duration::from_millis(50)); + + // We pace this outgoing packet. as all conditions for pacing + // are passed. + assert_eq!(r.pacing_rate, (12000.0 / 0.05) as usize); + assert_eq!( + r.get_packet_send_time().unwrap(), + now + Duration::from_micros( + (6500 * 1000000) / (12000.0 / 0.05) as u64 + ) + ); + } } mod cubic;