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.
5 #include "net/quic/quic_unacked_packet_map.h"
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "net/quic/quic_connection_stats.h"
10 #include "net/quic/quic_utils_chromium.h"
16 QuicUnackedPacketMap::QuicUnackedPacketMap()
17 : largest_sent_packet_(0),
21 pending_crypto_packet_count_(0) {
24 QuicUnackedPacketMap::~QuicUnackedPacketMap() {
25 QuicPacketSequenceNumber index
= least_unacked_
;
26 for (UnackedPacketMap::iterator it
= unacked_packets_
.begin();
27 it
!= unacked_packets_
.end(); ++it
, ++index
) {
28 delete it
->retransmittable_frames
;
29 // Only delete all_transmissions once, for the newest packet.
30 if (it
->all_transmissions
!= nullptr &&
31 index
== *it
->all_transmissions
->rbegin()) {
32 delete it
->all_transmissions
;
37 void QuicUnackedPacketMap::AddSentPacket(
38 const SerializedPacket
& packet
,
39 QuicPacketSequenceNumber old_sequence_number
,
40 TransmissionType transmission_type
,
42 QuicByteCount bytes_sent
,
44 QuicPacketSequenceNumber sequence_number
= packet
.sequence_number
;
45 LOG_IF(DFATAL
, largest_sent_packet_
> sequence_number
);
46 DCHECK_GE(sequence_number
, least_unacked_
+ unacked_packets_
.size());
47 while (least_unacked_
+ unacked_packets_
.size() < sequence_number
) {
48 unacked_packets_
.push_back(TransmissionInfo());
49 unacked_packets_
.back().is_unackable
= true;
52 TransmissionInfo
info(packet
.retransmittable_frames
,
53 packet
.sequence_number_length
,
56 info
.is_fec_packet
= packet
.is_fec_packet
;
58 if (old_sequence_number
== 0) {
59 if (packet
.retransmittable_frames
!= nullptr &&
60 packet
.retransmittable_frames
->HasCryptoHandshake() == IS_HANDSHAKE
) {
61 ++pending_crypto_packet_count_
;
64 TransferRetransmissionInfo(
65 old_sequence_number
, sequence_number
, transmission_type
, &info
);
68 largest_sent_packet_
= sequence_number
;
70 bytes_in_flight_
+= bytes_sent
;
71 info
.bytes_sent
= bytes_sent
;
72 info
.in_flight
= true;
74 unacked_packets_
.push_back(info
);
77 void QuicUnackedPacketMap::RemoveObsoletePackets() {
78 while (!unacked_packets_
.empty()) {
79 if (!IsPacketRemovable(least_unacked_
, unacked_packets_
.front())) {
82 unacked_packets_
.pop_front();
87 void QuicUnackedPacketMap::TransferRetransmissionInfo(
88 QuicPacketSequenceNumber old_sequence_number
,
89 QuicPacketSequenceNumber new_sequence_number
,
90 TransmissionType transmission_type
,
91 TransmissionInfo
* info
) {
92 DCHECK_GE(old_sequence_number
, least_unacked_
);
93 DCHECK_LT(old_sequence_number
, least_unacked_
+ unacked_packets_
.size());
94 DCHECK_GE(new_sequence_number
, least_unacked_
+ unacked_packets_
.size());
95 DCHECK_NE(NOT_RETRANSMISSION
, transmission_type
);
97 // TODO(ianswett): Discard and lose the packet lazily instead of immediately.
98 TransmissionInfo
* transmission_info
=
99 &unacked_packets_
.at(old_sequence_number
- least_unacked_
);
100 RetransmittableFrames
* frames
= transmission_info
->retransmittable_frames
;
101 transmission_info
->retransmittable_frames
= nullptr;
102 LOG_IF(DFATAL
, frames
== nullptr)
103 << "Attempt to retransmit packet with no "
104 << "retransmittable frames: " << old_sequence_number
;
106 // Only keep one transmission older than largest observed, because only the
107 // most recent is expected to possibly be a spurious retransmission.
108 while (transmission_info
->all_transmissions
!= nullptr &&
109 transmission_info
->all_transmissions
->size() > 1 &&
110 *(++transmission_info
->all_transmissions
->begin()) <
112 QuicPacketSequenceNumber old_transmission
=
113 *transmission_info
->all_transmissions
->begin();
114 TransmissionInfo
* old_info
=
115 &unacked_packets_
[old_transmission
- least_unacked_
];
116 // Don't remove old packets if they're still in flight.
117 if (old_info
->in_flight
) {
120 old_info
->all_transmissions
->pop_front();
121 // This will cause the packet be removed in RemoveObsoletePackets.
122 old_info
->all_transmissions
= nullptr;
124 // Don't link old transmissions to new ones when version or
125 // encryption changes.
126 if (transmission_type
== ALL_INITIAL_RETRANSMISSION
||
127 transmission_type
== ALL_UNACKED_RETRANSMISSION
) {
128 RemoveAckability(transmission_info
);
130 if (transmission_info
->all_transmissions
== nullptr) {
131 transmission_info
->all_transmissions
= new SequenceNumberList();
132 transmission_info
->all_transmissions
->push_back(old_sequence_number
);
134 transmission_info
->all_transmissions
->push_back(new_sequence_number
);
136 info
->retransmittable_frames
= frames
;
137 info
->all_transmissions
= transmission_info
->all_transmissions
;
138 // Proactively remove obsolete packets so the least unacked can be raised.
139 RemoveObsoletePackets();
142 void QuicUnackedPacketMap::ClearAllPreviousRetransmissions() {
143 while (!unacked_packets_
.empty() && least_unacked_
< largest_observed_
) {
144 // If this packet is in flight, or has retransmittable data, then there is
145 // no point in clearing out any further packets, because they would not
146 // affect the high water mark.
147 TransmissionInfo
* info
= &unacked_packets_
.front();
148 if (info
->in_flight
|| info
->retransmittable_frames
!= nullptr) {
152 if (info
->all_transmissions
!= nullptr) {
153 if (info
->all_transmissions
->size() < 2) {
154 LOG(DFATAL
) << "all_transmissions must be nullptr or have multiple "
155 << "elements. size:" << info
->all_transmissions
->size();
156 delete info
->all_transmissions
;
158 info
->all_transmissions
->pop_front();
159 if (info
->all_transmissions
->size() == 1) {
160 // Set the newer transmission's 'all_transmissions' entry to nullptr.
161 QuicPacketSequenceNumber new_transmission
=
162 info
->all_transmissions
->front();
163 TransmissionInfo
* new_info
=
164 &unacked_packets_
.at(new_transmission
- least_unacked_
);
165 delete new_info
->all_transmissions
;
166 new_info
->all_transmissions
= nullptr;
170 unacked_packets_
.pop_front();
175 bool QuicUnackedPacketMap::HasRetransmittableFrames(
176 QuicPacketSequenceNumber sequence_number
) const {
177 DCHECK_GE(sequence_number
, least_unacked_
);
178 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
179 return unacked_packets_
[sequence_number
- least_unacked_
]
180 .retransmittable_frames
!= nullptr;
183 void QuicUnackedPacketMap::NackPacket(QuicPacketSequenceNumber sequence_number
,
184 QuicPacketCount min_nacks
) {
185 DCHECK_GE(sequence_number
, least_unacked_
);
186 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
187 unacked_packets_
[sequence_number
- least_unacked_
].nack_count
=
189 unacked_packets_
[sequence_number
- least_unacked_
].nack_count
);
192 void QuicUnackedPacketMap::RemoveRetransmittability(
193 QuicPacketSequenceNumber sequence_number
) {
194 DCHECK_GE(sequence_number
, least_unacked_
);
195 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
196 TransmissionInfo
* info
= &unacked_packets_
[sequence_number
- least_unacked_
];
197 SequenceNumberList
* all_transmissions
= info
->all_transmissions
;
198 if (all_transmissions
== nullptr) {
199 MaybeRemoveRetransmittableFrames(info
);
202 // TODO(ianswett): Consider adding a check to ensure there are retransmittable
203 // frames associated with this packet.
204 for (SequenceNumberList::const_iterator it
= all_transmissions
->begin();
205 it
!= all_transmissions
->end(); ++it
) {
206 TransmissionInfo
* transmission_info
=
207 &unacked_packets_
[*it
- least_unacked_
];
208 MaybeRemoveRetransmittableFrames(transmission_info
);
209 transmission_info
->all_transmissions
= nullptr;
211 delete all_transmissions
;
214 void QuicUnackedPacketMap::RemoveAckability(TransmissionInfo
* info
) {
215 DCHECK(info
->retransmittable_frames
== nullptr);
216 info
->is_unackable
= true;
217 SequenceNumberList
* all_transmissions
= info
->all_transmissions
;
218 if (all_transmissions
== nullptr) {
221 for (SequenceNumberList::const_iterator it
= all_transmissions
->begin();
222 it
!= all_transmissions
->end(); ++it
) {
223 TransmissionInfo
* transmission_info
=
224 &unacked_packets_
[*it
- least_unacked_
];
225 transmission_info
->all_transmissions
= nullptr;
226 transmission_info
->is_unackable
= true;
228 delete all_transmissions
;
231 void QuicUnackedPacketMap::MaybeRemoveRetransmittableFrames(
232 TransmissionInfo
* transmission_info
) {
233 if (transmission_info
->retransmittable_frames
!= nullptr) {
234 if (transmission_info
->retransmittable_frames
->HasCryptoHandshake()
236 --pending_crypto_packet_count_
;
238 delete transmission_info
->retransmittable_frames
;
239 transmission_info
->retransmittable_frames
= nullptr;
243 void QuicUnackedPacketMap::IncreaseLargestObserved(
244 QuicPacketSequenceNumber largest_observed
) {
245 DCHECK_LE(largest_observed_
, largest_observed
);
246 largest_observed_
= largest_observed
;
249 bool QuicUnackedPacketMap::IsPacketUsefulForMeasuringRtt(
250 QuicPacketSequenceNumber sequence_number
,
251 const TransmissionInfo
& info
) const {
252 // Packet can be used for RTT measurement if it may yet be acked as the
253 // largest observed packet by the receiver.
254 return !info
.is_unackable
&& sequence_number
> largest_observed_
;
257 bool QuicUnackedPacketMap::IsPacketUsefulForCongestionControl(
258 QuicPacketSequenceNumber sequence_number
,
259 const TransmissionInfo
& info
) const {
260 // Packet contributes to congestion control if it is considered inflight.
261 return info
.in_flight
;
264 bool QuicUnackedPacketMap::IsPacketUsefulForRetransmittableData(
265 QuicPacketSequenceNumber sequence_number
,
266 const TransmissionInfo
& info
) const {
267 // Packet may have retransmittable frames, or the data may have been
268 // retransmitted with a new sequence number.
269 return info
.retransmittable_frames
!= nullptr ||
270 info
.all_transmissions
!= nullptr;
273 bool QuicUnackedPacketMap::IsPacketUseless(
274 QuicPacketSequenceNumber sequence_number
,
275 const TransmissionInfo
& info
) const {
276 return !IsPacketUsefulForMeasuringRtt(sequence_number
, info
) &&
277 !IsPacketUsefulForCongestionControl(sequence_number
, info
) &&
278 !IsPacketUsefulForRetransmittableData(sequence_number
, info
);
281 bool QuicUnackedPacketMap::IsPacketRemovable(
282 QuicPacketSequenceNumber sequence_number
,
283 const TransmissionInfo
& info
) const {
284 return (!IsPacketUsefulForMeasuringRtt(sequence_number
, info
) ||
285 unacked_packets_
.size() > kMaxTcpCongestionWindow
) &&
286 !IsPacketUsefulForCongestionControl(sequence_number
, info
) &&
287 !IsPacketUsefulForRetransmittableData(sequence_number
, info
);
290 bool QuicUnackedPacketMap::IsUnacked(
291 QuicPacketSequenceNumber sequence_number
) const {
292 if (sequence_number
< least_unacked_
||
293 sequence_number
>= least_unacked_
+ unacked_packets_
.size()) {
296 return !IsPacketUseless(sequence_number
,
297 unacked_packets_
[sequence_number
- least_unacked_
]);
300 void QuicUnackedPacketMap::RemoveFromInFlight(
301 QuicPacketSequenceNumber sequence_number
) {
302 DCHECK_GE(sequence_number
, least_unacked_
);
303 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
304 TransmissionInfo
* info
= &unacked_packets_
[sequence_number
- least_unacked_
];
305 if (info
->in_flight
) {
306 LOG_IF(DFATAL
, bytes_in_flight_
< info
->bytes_sent
);
307 bytes_in_flight_
-= info
->bytes_sent
;
308 info
->in_flight
= false;
312 bool QuicUnackedPacketMap::HasUnackedPackets() const {
313 return !unacked_packets_
.empty();
316 bool QuicUnackedPacketMap::HasInFlightPackets() const {
317 return bytes_in_flight_
> 0;
320 const TransmissionInfo
& QuicUnackedPacketMap::GetTransmissionInfo(
321 QuicPacketSequenceNumber sequence_number
) const {
322 return unacked_packets_
[sequence_number
- least_unacked_
];
325 QuicTime
QuicUnackedPacketMap::GetLastPacketSentTime() const {
326 UnackedPacketMap::const_reverse_iterator it
= unacked_packets_
.rbegin();
327 while (it
!= unacked_packets_
.rend()) {
329 LOG_IF(DFATAL
, it
->sent_time
== QuicTime::Zero())
330 << "Sent time can never be zero for a packet in flight.";
331 return it
->sent_time
;
335 LOG(DFATAL
) << "GetLastPacketSentTime requires in flight packets.";
336 return QuicTime::Zero();
339 QuicTime
QuicUnackedPacketMap::GetFirstInFlightPacketSentTime() const {
340 UnackedPacketMap::const_iterator it
= unacked_packets_
.begin();
341 while (it
!= unacked_packets_
.end() && !it
->in_flight
) {
344 if (it
== unacked_packets_
.end()) {
345 LOG(DFATAL
) << "GetFirstInFlightPacketSentTime requires in flight packets.";
346 return QuicTime::Zero();
348 return it
->sent_time
;
351 size_t QuicUnackedPacketMap::GetNumUnackedPacketsDebugOnly() const {
352 size_t unacked_packet_count
= 0;
353 QuicPacketSequenceNumber sequence_number
= least_unacked_
;
354 for (UnackedPacketMap::const_iterator it
= unacked_packets_
.begin();
355 it
!= unacked_packets_
.end(); ++it
, ++sequence_number
) {
356 if (!IsPacketUseless(sequence_number
, *it
)) {
357 ++unacked_packet_count
;
360 return unacked_packet_count
;
363 bool QuicUnackedPacketMap::HasMultipleInFlightPackets() const {
364 size_t num_in_flight
= 0;
365 for (UnackedPacketMap::const_reverse_iterator it
= unacked_packets_
.rbegin();
366 it
!= unacked_packets_
.rend(); ++it
) {
370 if (num_in_flight
> 1) {
377 bool QuicUnackedPacketMap::HasPendingCryptoPackets() const {
378 return pending_crypto_packet_count_
> 0;
381 bool QuicUnackedPacketMap::HasUnackedRetransmittableFrames() const {
382 for (UnackedPacketMap::const_reverse_iterator it
=
383 unacked_packets_
.rbegin(); it
!= unacked_packets_
.rend(); ++it
) {
384 if (it
->in_flight
&& it
->retransmittable_frames
) {
391 QuicPacketSequenceNumber
392 QuicUnackedPacketMap::GetLeastUnacked() const {
393 return least_unacked_
;
396 void QuicUnackedPacketMap::RestoreInFlight(
397 QuicPacketSequenceNumber sequence_number
) {
398 DCHECK_GE(sequence_number
, least_unacked_
);
399 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
400 TransmissionInfo
* info
= &unacked_packets_
[sequence_number
- least_unacked_
];
401 DCHECK(!info
->in_flight
);
402 DCHECK_NE(0u, info
->bytes_sent
);
403 DCHECK(info
->sent_time
.IsInitialized());
405 bytes_in_flight_
+= info
->bytes_sent
;
406 info
->in_flight
= true;