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
10namespace net {
11
12namespace {
13
14// TCP retransmits after 3 nacks.
15static const size_t kNumberOfNacksBeforeRetransmission = 3;
16
17// How many RTTs the algorithm waits before determining a packet is lost due
18// to early retransmission.
19static const double kEarlyRetransmitLossDelayMultiplier = 1.25;
20
21}
22
23TCPLossAlgorithm::TCPLossAlgorithm()
24    : loss_detection_timeout_(QuicTime::Zero()) { }
25
26LossDetectionType TCPLossAlgorithm::GetLossDetectionType() const {
27  return kNack;
28}
29
30// Uses nack counts to decide when packets are lost.
31SequenceNumberSet 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
41  for (QuicUnackedPacketMap::const_iterator it = unacked_packets.begin();
42       it != unacked_packets.end() && it->first <= largest_observed; ++it) {
43    if (!it->second.in_flight) {
44      continue;
45    }
46
47    LOG_IF(DFATAL, it->second.nack_count == 0)
48        << "All packets less than largest observed should have been nacked.";
49    if (it->second.nack_count >= kNumberOfNacksBeforeRetransmission) {
50      lost_packets.insert(it->first);
51      continue;
52    }
53
54    // Only early retransmit(RFC5827) when the last packet gets acked and
55    // there are retransmittable packets in flight.
56    // This also implements a timer-protected variant of FACK.
57    if (it->second.retransmittable_frames &&
58        unacked_packets.largest_sent_packet() == largest_observed) {
59      // Early retransmit marks the packet as lost once 1.25RTTs have passed
60      // since the packet was sent and otherwise sets an alarm.
61      if (time >= it->second.sent_time.Add(loss_delay)) {
62        lost_packets.insert(it->first);
63      } else {
64        // Set the timeout for the earliest retransmittable packet where early
65        // retransmit applies.
66        loss_detection_timeout_ = it->second.sent_time.Add(loss_delay);
67        break;
68      }
69    }
70  }
71
72  return lost_packets;
73}
74
75QuicTime TCPLossAlgorithm::GetLossTimeout() const {
76  return loss_detection_timeout_;
77}
78
79}  // namespace net
80