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
, transmission_type
,
54 sent_time
, bytes_sent
, packet
.is_fec_packet
);
55 if (old_sequence_number
== 0) {
56 if (packet
.retransmittable_frames
!= nullptr &&
57 packet
.retransmittable_frames
->HasCryptoHandshake() == IS_HANDSHAKE
) {
58 ++pending_crypto_packet_count_
;
61 TransferRetransmissionInfo(
62 old_sequence_number
, sequence_number
, transmission_type
, &info
);
65 largest_sent_packet_
= sequence_number
;
67 bytes_in_flight_
+= bytes_sent
;
68 info
.in_flight
= true;
70 unacked_packets_
.push_back(info
);
73 void QuicUnackedPacketMap::RemoveObsoletePackets() {
74 while (!unacked_packets_
.empty()) {
75 if (!IsPacketRemovable(least_unacked_
, unacked_packets_
.front())) {
78 unacked_packets_
.pop_front();
83 void QuicUnackedPacketMap::TransferRetransmissionInfo(
84 QuicPacketSequenceNumber old_sequence_number
,
85 QuicPacketSequenceNumber new_sequence_number
,
86 TransmissionType transmission_type
,
87 TransmissionInfo
* info
) {
88 DCHECK_GE(old_sequence_number
, least_unacked_
);
89 DCHECK_LT(old_sequence_number
, least_unacked_
+ unacked_packets_
.size());
90 DCHECK_GE(new_sequence_number
, least_unacked_
+ unacked_packets_
.size());
91 DCHECK_NE(NOT_RETRANSMISSION
, transmission_type
);
93 TransmissionInfo
* transmission_info
=
94 &unacked_packets_
.at(old_sequence_number
- least_unacked_
);
95 RetransmittableFrames
* frames
= transmission_info
->retransmittable_frames
;
96 transmission_info
->retransmittable_frames
= nullptr;
97 LOG_IF(DFATAL
, frames
== nullptr)
98 << "Attempt to retransmit packet with no "
99 << "retransmittable frames: " << old_sequence_number
;
101 // Only keep one transmission older than largest observed, because only the
102 // most recent is expected to possibly be a spurious retransmission.
103 while (transmission_info
->all_transmissions
!= nullptr &&
104 transmission_info
->all_transmissions
->size() > 1 &&
105 *(++transmission_info
->all_transmissions
->begin()) <
107 QuicPacketSequenceNumber old_transmission
=
108 *transmission_info
->all_transmissions
->begin();
109 TransmissionInfo
* old_info
=
110 &unacked_packets_
[old_transmission
- least_unacked_
];
111 // Don't remove old packets if they're still in flight.
112 if (old_info
->in_flight
) {
115 old_info
->all_transmissions
->pop_front();
116 // This will cause the packet be removed in RemoveObsoletePackets.
117 old_info
->all_transmissions
= nullptr;
119 // Don't link old transmissions to new ones when version or
120 // encryption changes.
121 if (transmission_type
== ALL_INITIAL_RETRANSMISSION
||
122 transmission_type
== ALL_UNACKED_RETRANSMISSION
) {
123 RemoveAckability(transmission_info
);
125 if (transmission_info
->all_transmissions
== nullptr) {
126 transmission_info
->all_transmissions
= new SequenceNumberList();
127 transmission_info
->all_transmissions
->push_back(old_sequence_number
);
129 transmission_info
->all_transmissions
->push_back(new_sequence_number
);
131 info
->retransmittable_frames
= frames
;
132 info
->all_transmissions
= transmission_info
->all_transmissions
;
133 // Proactively remove obsolete packets so the least unacked can be raised.
134 RemoveObsoletePackets();
137 void QuicUnackedPacketMap::ClearAllPreviousRetransmissions() {
138 while (!unacked_packets_
.empty() && least_unacked_
< largest_observed_
) {
139 // If this packet is in flight, or has retransmittable data, then there is
140 // no point in clearing out any further packets, because they would not
141 // affect the high water mark.
142 TransmissionInfo
* info
= &unacked_packets_
.front();
143 if (info
->in_flight
|| info
->retransmittable_frames
!= nullptr) {
147 if (info
->all_transmissions
!= nullptr) {
148 if (info
->all_transmissions
->size() < 2) {
149 LOG(DFATAL
) << "all_transmissions must be nullptr or have multiple "
150 << "elements. size:" << info
->all_transmissions
->size();
151 delete info
->all_transmissions
;
153 info
->all_transmissions
->pop_front();
154 if (info
->all_transmissions
->size() == 1) {
155 // Set the newer transmission's 'all_transmissions' entry to nullptr.
156 QuicPacketSequenceNumber new_transmission
=
157 info
->all_transmissions
->front();
158 TransmissionInfo
* new_info
=
159 &unacked_packets_
.at(new_transmission
- least_unacked_
);
160 delete new_info
->all_transmissions
;
161 new_info
->all_transmissions
= nullptr;
165 unacked_packets_
.pop_front();
170 bool QuicUnackedPacketMap::HasRetransmittableFrames(
171 QuicPacketSequenceNumber sequence_number
) const {
172 DCHECK_GE(sequence_number
, least_unacked_
);
173 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
174 return unacked_packets_
[sequence_number
- least_unacked_
]
175 .retransmittable_frames
!= nullptr;
178 void QuicUnackedPacketMap::NackPacket(QuicPacketSequenceNumber sequence_number
,
179 QuicPacketCount min_nacks
) {
180 DCHECK_GE(sequence_number
, least_unacked_
);
181 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
182 unacked_packets_
[sequence_number
- least_unacked_
].nack_count
=
184 unacked_packets_
[sequence_number
- least_unacked_
].nack_count
);
187 void QuicUnackedPacketMap::RemoveRetransmittability(
188 QuicPacketSequenceNumber sequence_number
) {
189 DCHECK_GE(sequence_number
, least_unacked_
);
190 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
191 TransmissionInfo
* info
= &unacked_packets_
[sequence_number
- least_unacked_
];
192 SequenceNumberList
* all_transmissions
= info
->all_transmissions
;
193 if (all_transmissions
== nullptr) {
194 MaybeRemoveRetransmittableFrames(info
);
197 // TODO(ianswett): Consider adding a check to ensure there are retransmittable
198 // frames associated with this packet.
199 for (QuicPacketSequenceNumber sequence_number
: *all_transmissions
) {
200 TransmissionInfo
* transmission_info
=
201 &unacked_packets_
[sequence_number
- least_unacked_
];
202 MaybeRemoveRetransmittableFrames(transmission_info
);
203 transmission_info
->all_transmissions
= nullptr;
205 delete all_transmissions
;
208 void QuicUnackedPacketMap::RemoveAckability(TransmissionInfo
* info
) {
209 DCHECK(info
->retransmittable_frames
== nullptr);
210 info
->is_unackable
= true;
211 SequenceNumberList
* all_transmissions
= info
->all_transmissions
;
212 if (all_transmissions
== nullptr) {
215 for (QuicPacketSequenceNumber sequence_number
: *all_transmissions
) {
216 TransmissionInfo
* transmission_info
=
217 &unacked_packets_
[sequence_number
- least_unacked_
];
218 transmission_info
->all_transmissions
= nullptr;
219 transmission_info
->is_unackable
= true;
221 delete all_transmissions
;
224 void QuicUnackedPacketMap::MaybeRemoveRetransmittableFrames(
225 TransmissionInfo
* transmission_info
) {
226 if (transmission_info
->retransmittable_frames
!= nullptr) {
227 if (transmission_info
->retransmittable_frames
->HasCryptoHandshake()
229 --pending_crypto_packet_count_
;
231 delete transmission_info
->retransmittable_frames
;
232 transmission_info
->retransmittable_frames
= nullptr;
236 void QuicUnackedPacketMap::IncreaseLargestObserved(
237 QuicPacketSequenceNumber largest_observed
) {
238 DCHECK_LE(largest_observed_
, largest_observed
);
239 largest_observed_
= largest_observed
;
242 bool QuicUnackedPacketMap::IsPacketUsefulForMeasuringRtt(
243 QuicPacketSequenceNumber sequence_number
,
244 const TransmissionInfo
& info
) const {
245 // Packet can be used for RTT measurement if it may yet be acked as the
246 // largest observed packet by the receiver.
247 return !info
.is_unackable
&& sequence_number
> largest_observed_
;
250 bool QuicUnackedPacketMap::IsPacketUsefulForCongestionControl(
251 const TransmissionInfo
& info
) const {
252 // Packet contributes to congestion control if it is considered inflight.
253 return info
.in_flight
;
256 bool QuicUnackedPacketMap::IsPacketUsefulForRetransmittableData(
257 const TransmissionInfo
& info
) const {
258 // Packet may have retransmittable frames, or the data may have been
259 // retransmitted with a new sequence number.
260 return info
.retransmittable_frames
!= nullptr ||
261 info
.all_transmissions
!= nullptr;
264 bool QuicUnackedPacketMap::IsPacketUseless(
265 QuicPacketSequenceNumber sequence_number
,
266 const TransmissionInfo
& info
) const {
267 return !IsPacketUsefulForMeasuringRtt(sequence_number
, info
) &&
268 !IsPacketUsefulForCongestionControl(info
) &&
269 !IsPacketUsefulForRetransmittableData(info
);
272 bool QuicUnackedPacketMap::IsPacketRemovable(
273 QuicPacketSequenceNumber sequence_number
,
274 const TransmissionInfo
& info
) const {
275 return (!IsPacketUsefulForMeasuringRtt(sequence_number
, info
) ||
276 unacked_packets_
.size() > kMaxTcpCongestionWindow
) &&
277 !IsPacketUsefulForCongestionControl(info
) &&
278 !IsPacketUsefulForRetransmittableData(info
);
281 bool QuicUnackedPacketMap::IsUnacked(
282 QuicPacketSequenceNumber sequence_number
) const {
283 if (sequence_number
< least_unacked_
||
284 sequence_number
>= least_unacked_
+ unacked_packets_
.size()) {
287 return !IsPacketUseless(sequence_number
,
288 unacked_packets_
[sequence_number
- least_unacked_
]);
291 void QuicUnackedPacketMap::RemoveFromInFlight(
292 QuicPacketSequenceNumber sequence_number
) {
293 DCHECK_GE(sequence_number
, least_unacked_
);
294 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
295 TransmissionInfo
* info
= &unacked_packets_
[sequence_number
- least_unacked_
];
296 if (info
->in_flight
) {
297 LOG_IF(DFATAL
, bytes_in_flight_
< info
->bytes_sent
);
298 bytes_in_flight_
-= info
->bytes_sent
;
299 info
->in_flight
= false;
303 void QuicUnackedPacketMap::CancelRetransmissionsForStream(
304 QuicStreamId stream_id
) {
305 if (stream_id
== kCryptoStreamId
|| stream_id
== kHeadersStreamId
) {
306 LOG(DFATAL
) << "Special streams must always retransmit data: " << stream_id
;
309 QuicPacketSequenceNumber sequence_number
= least_unacked_
;
310 for (UnackedPacketMap::const_iterator it
= unacked_packets_
.begin();
311 it
!= unacked_packets_
.end(); ++it
, ++sequence_number
) {
312 RetransmittableFrames
* retransmittable_frames
= it
->retransmittable_frames
;
313 if (!retransmittable_frames
) {
316 retransmittable_frames
->RemoveFramesForStream(stream_id
);
317 if (retransmittable_frames
->frames().empty()) {
318 RemoveRetransmittability(sequence_number
);
323 bool QuicUnackedPacketMap::HasUnackedPackets() const {
324 return !unacked_packets_
.empty();
327 bool QuicUnackedPacketMap::HasInFlightPackets() const {
328 return bytes_in_flight_
> 0;
331 const TransmissionInfo
& QuicUnackedPacketMap::GetTransmissionInfo(
332 QuicPacketSequenceNumber sequence_number
) const {
333 return unacked_packets_
[sequence_number
- least_unacked_
];
336 QuicTime
QuicUnackedPacketMap::GetLastPacketSentTime() const {
337 UnackedPacketMap::const_reverse_iterator it
= unacked_packets_
.rbegin();
338 while (it
!= unacked_packets_
.rend()) {
340 LOG_IF(DFATAL
, it
->sent_time
== QuicTime::Zero())
341 << "Sent time can never be zero for a packet in flight.";
342 return it
->sent_time
;
346 LOG(DFATAL
) << "GetLastPacketSentTime requires in flight packets.";
347 return QuicTime::Zero();
350 size_t QuicUnackedPacketMap::GetNumUnackedPacketsDebugOnly() const {
351 size_t unacked_packet_count
= 0;
352 QuicPacketSequenceNumber sequence_number
= least_unacked_
;
353 for (UnackedPacketMap::const_iterator it
= unacked_packets_
.begin();
354 it
!= unacked_packets_
.end(); ++it
, ++sequence_number
) {
355 if (!IsPacketUseless(sequence_number
, *it
)) {
356 ++unacked_packet_count
;
359 return unacked_packet_count
;
362 bool QuicUnackedPacketMap::HasMultipleInFlightPackets() const {
363 size_t num_in_flight
= 0;
364 for (UnackedPacketMap::const_reverse_iterator it
= unacked_packets_
.rbegin();
365 it
!= unacked_packets_
.rend(); ++it
) {
369 if (num_in_flight
> 1) {
376 bool QuicUnackedPacketMap::HasPendingCryptoPackets() const {
377 return pending_crypto_packet_count_
> 0;
380 bool QuicUnackedPacketMap::HasUnackedRetransmittableFrames() const {
381 for (UnackedPacketMap::const_reverse_iterator it
=
382 unacked_packets_
.rbegin(); it
!= unacked_packets_
.rend(); ++it
) {
383 if (it
->in_flight
&& it
->retransmittable_frames
) {
390 QuicPacketSequenceNumber
QuicUnackedPacketMap::GetLeastUnacked() const {
391 return least_unacked_
;