1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/quic/congestion_control/tcp_loss_algorithm.h" 6 7 #include "net/quic/congestion_control/rtt_stats.h" 8 #include "net/quic/quic_protocol.h" 9 10 namespace net { 11 12 namespace { 13 14 // TCP retransmits after 3 nacks. 15 static const size_t kNumberOfNacksBeforeRetransmission = 3; 16 17 // How many RTTs the algorithm waits before determining a packet is lost due 18 // to early retransmission. 19 static const double kEarlyRetransmitLossDelayMultiplier = 1.25; 20 21 } 22 23 TCPLossAlgorithm::TCPLossAlgorithm() 24 : loss_detection_timeout_(QuicTime::Zero()) { } 25 26 LossDetectionType TCPLossAlgorithm::GetLossDetectionType() const { 27 return kNack; 28 } 29 30 // Uses nack counts to decide when packets are lost. 31 SequenceNumberSet TCPLossAlgorithm::DetectLostPackets( 32 const QuicUnackedPacketMap& unacked_packets, 33 const QuicTime& time, 34 QuicPacketSequenceNumber largest_observed, 35 const RttStats& rtt_stats) { 36 SequenceNumberSet lost_packets; 37 loss_detection_timeout_ = QuicTime::Zero(); 38 QuicTime::Delta loss_delay = 39 rtt_stats.SmoothedRtt().Multiply(kEarlyRetransmitLossDelayMultiplier); 40 QuicPacketSequenceNumber sequence_number = unacked_packets.GetLeastUnacked(); 41 for (QuicUnackedPacketMap::const_iterator it = unacked_packets.begin(); 42 it != unacked_packets.end() && sequence_number <= largest_observed; 43 ++it, ++sequence_number) { 44 if (!it->in_flight) { 45 continue; 46 } 47 48 LOG_IF(DFATAL, it->nack_count == 0) 49 << "All packets less than largest observed should have been nacked."; 50 if (it->nack_count >= kNumberOfNacksBeforeRetransmission) { 51 lost_packets.insert(sequence_number); 52 continue; 53 } 54 55 // Only early retransmit(RFC5827) when the last packet gets acked and 56 // there are retransmittable packets in flight. 57 // This also implements a timer-protected variant of FACK. 58 if (it->retransmittable_frames && 59 unacked_packets.largest_sent_packet() == largest_observed) { 60 // Early retransmit marks the packet as lost once 1.25RTTs have passed 61 // since the packet was sent and otherwise sets an alarm. 62 if (time >= it->sent_time.Add(loss_delay)) { 63 lost_packets.insert(sequence_number); 64 } else { 65 // Set the timeout for the earliest retransmittable packet where early 66 // retransmit applies. 67 loss_detection_timeout_ = it->sent_time.Add(loss_delay); 68 break; 69 } 70 } 71 } 72 73 return lost_packets; 74 } 75 76 QuicTime TCPLossAlgorithm::GetLossTimeout() const { 77 return loss_detection_timeout_; 78 } 79 80 } // namespace net 81