| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/quic/quic_unacked_packet_map.h" |
| |
| #include "base/logging.h" |
| #include "base/stl_util.h" |
| #include "net/quic/quic_connection_stats.h" |
| #include "net/quic/quic_utils_chromium.h" |
| |
| using std::max; |
| |
| namespace net { |
| |
| QuicUnackedPacketMap::TransmissionInfo::TransmissionInfo() |
| : retransmittable_frames(NULL), |
| sequence_number_length(PACKET_1BYTE_SEQUENCE_NUMBER), |
| sent_time(QuicTime::Zero()), |
| bytes_sent(0), |
| nack_count(0), |
| all_transmissions(NULL), |
| pending(false) { } |
| |
| QuicUnackedPacketMap::TransmissionInfo::TransmissionInfo( |
| RetransmittableFrames* retransmittable_frames, |
| QuicPacketSequenceNumber sequence_number, |
| QuicSequenceNumberLength sequence_number_length) |
| : retransmittable_frames(retransmittable_frames), |
| sequence_number_length(sequence_number_length), |
| sent_time(QuicTime::Zero()), |
| bytes_sent(0), |
| nack_count(0), |
| all_transmissions(new SequenceNumberSet), |
| pending(false) { |
| all_transmissions->insert(sequence_number); |
| } |
| |
| QuicUnackedPacketMap::TransmissionInfo::TransmissionInfo( |
| RetransmittableFrames* retransmittable_frames, |
| QuicPacketSequenceNumber sequence_number, |
| QuicSequenceNumberLength sequence_number_length, |
| SequenceNumberSet* all_transmissions) |
| : retransmittable_frames(retransmittable_frames), |
| sequence_number_length(sequence_number_length), |
| sent_time(QuicTime::Zero()), |
| bytes_sent(0), |
| nack_count(0), |
| all_transmissions(all_transmissions), |
| pending(false) { |
| all_transmissions->insert(sequence_number); |
| } |
| |
| QuicUnackedPacketMap::QuicUnackedPacketMap() |
| : largest_sent_packet_(0), |
| bytes_in_flight_(0), |
| pending_crypto_packet_count_(0) { |
| } |
| |
| QuicUnackedPacketMap::~QuicUnackedPacketMap() { |
| for (UnackedPacketMap::iterator it = unacked_packets_.begin(); |
| it != unacked_packets_.end(); ++it) { |
| delete it->second.retransmittable_frames; |
| // Only delete all_transmissions once, for the newest packet. |
| if (it->first == *it->second.all_transmissions->rbegin()) { |
| delete it->second.all_transmissions; |
| } |
| } |
| } |
| |
| // TODO(ianswett): Combine this method with OnPacketSent once packets are always |
| // sent in order and the connection tracks RetransmittableFrames for longer. |
| void QuicUnackedPacketMap::AddPacket( |
| const SerializedPacket& serialized_packet) { |
| if (!unacked_packets_.empty()) { |
| bool is_old_packet = unacked_packets_.rbegin()->first >= |
| serialized_packet.sequence_number; |
| LOG_IF(DFATAL, is_old_packet) << "Old packet serialized: " |
| << serialized_packet.sequence_number |
| << " vs: " |
| << unacked_packets_.rbegin()->first; |
| } |
| |
| unacked_packets_[serialized_packet.sequence_number] = |
| TransmissionInfo(serialized_packet.retransmittable_frames, |
| serialized_packet.sequence_number, |
| serialized_packet.sequence_number_length); |
| if (serialized_packet.retransmittable_frames != NULL && |
| serialized_packet.retransmittable_frames->HasCryptoHandshake() |
| == IS_HANDSHAKE) { |
| ++pending_crypto_packet_count_; |
| } |
| } |
| |
| void QuicUnackedPacketMap::OnRetransmittedPacket( |
| QuicPacketSequenceNumber old_sequence_number, |
| QuicPacketSequenceNumber new_sequence_number) { |
| DCHECK(ContainsKey(unacked_packets_, old_sequence_number)); |
| DCHECK(unacked_packets_.empty() || |
| unacked_packets_.rbegin()->first < new_sequence_number); |
| |
| // TODO(ianswett): Discard and lose the packet lazily instead of immediately. |
| TransmissionInfo* transmission_info = |
| FindOrNull(unacked_packets_, old_sequence_number); |
| RetransmittableFrames* frames = transmission_info->retransmittable_frames; |
| LOG_IF(DFATAL, frames == NULL) << "Attempt to retransmit packet with no " |
| << "retransmittable frames: " |
| << old_sequence_number; |
| |
| // We keep the old packet in the unacked packet list until it, or one of |
| // the retransmissions of it are acked. |
| transmission_info->retransmittable_frames = NULL; |
| unacked_packets_[new_sequence_number] = |
| TransmissionInfo(frames, |
| new_sequence_number, |
| transmission_info->sequence_number_length, |
| transmission_info->all_transmissions); |
| } |
| |
| void QuicUnackedPacketMap::ClearPreviousRetransmissions(size_t num_to_clear) { |
| UnackedPacketMap::iterator it = unacked_packets_.begin(); |
| while (it != unacked_packets_.end() && num_to_clear > 0) { |
| QuicPacketSequenceNumber sequence_number = it->first; |
| // If this is a pending packet, or has retransmittable data, then there is |
| // no point in clearing out any further packets, because they would not |
| // affect the high water mark. |
| if (it->second.pending || it->second.retransmittable_frames != NULL) { |
| break; |
| } |
| |
| ++it; |
| RemovePacket(sequence_number); |
| --num_to_clear; |
| } |
| } |
| |
| bool QuicUnackedPacketMap::HasRetransmittableFrames( |
| QuicPacketSequenceNumber sequence_number) const { |
| const TransmissionInfo* transmission_info = |
| FindOrNull(unacked_packets_, sequence_number); |
| if (transmission_info == NULL) { |
| return false; |
| } |
| |
| return transmission_info->retransmittable_frames != NULL; |
| } |
| |
| void QuicUnackedPacketMap::NackPacket(QuicPacketSequenceNumber sequence_number, |
| size_t min_nacks) { |
| UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number); |
| if (it == unacked_packets_.end()) { |
| LOG(DFATAL) << "NackPacket called for packet that is not unacked: " |
| << sequence_number; |
| return; |
| } |
| |
| it->second.nack_count = max(min_nacks, it->second.nack_count); |
| } |
| |
| void QuicUnackedPacketMap::RemovePacket( |
| QuicPacketSequenceNumber sequence_number) { |
| UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number); |
| if (it == unacked_packets_.end()) { |
| LOG(DFATAL) << "packet is not unacked: " << sequence_number; |
| return; |
| } |
| const TransmissionInfo& transmission_info = it->second; |
| transmission_info.all_transmissions->erase(sequence_number); |
| if (transmission_info.all_transmissions->empty()) { |
| delete transmission_info.all_transmissions; |
| } |
| if (transmission_info.retransmittable_frames != NULL) { |
| if (transmission_info.retransmittable_frames->HasCryptoHandshake() |
| == IS_HANDSHAKE) { |
| --pending_crypto_packet_count_; |
| } |
| delete transmission_info.retransmittable_frames; |
| } |
| unacked_packets_.erase(it); |
| } |
| |
| void QuicUnackedPacketMap::NeuterPacket( |
| QuicPacketSequenceNumber sequence_number) { |
| UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number); |
| if (it == unacked_packets_.end()) { |
| LOG(DFATAL) << "packet is not unacked: " << sequence_number; |
| return; |
| } |
| TransmissionInfo* transmission_info = &it->second; |
| if (transmission_info->all_transmissions->size() > 1) { |
| transmission_info->all_transmissions->erase(sequence_number); |
| transmission_info->all_transmissions = new SequenceNumberSet(); |
| transmission_info->all_transmissions->insert(sequence_number); |
| } |
| if (transmission_info->retransmittable_frames != NULL) { |
| if (transmission_info->retransmittable_frames->HasCryptoHandshake() |
| == IS_HANDSHAKE) { |
| --pending_crypto_packet_count_; |
| } |
| delete transmission_info->retransmittable_frames; |
| transmission_info->retransmittable_frames = NULL; |
| } |
| } |
| |
| // static |
| bool QuicUnackedPacketMap::IsSentAndNotPending( |
| const TransmissionInfo& transmission_info) { |
| return !transmission_info.pending && |
| transmission_info.sent_time != QuicTime::Zero() && |
| transmission_info.bytes_sent == 0; |
| } |
| |
| bool QuicUnackedPacketMap::IsUnacked( |
| QuicPacketSequenceNumber sequence_number) const { |
| return ContainsKey(unacked_packets_, sequence_number); |
| } |
| |
| bool QuicUnackedPacketMap::IsPending( |
| QuicPacketSequenceNumber sequence_number) const { |
| const TransmissionInfo* transmission_info = |
| FindOrNull(unacked_packets_, sequence_number); |
| return transmission_info != NULL && transmission_info->pending; |
| } |
| |
| void QuicUnackedPacketMap::SetNotPending( |
| QuicPacketSequenceNumber sequence_number) { |
| UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number); |
| if (it == unacked_packets_.end()) { |
| LOG(DFATAL) << "SetNotPending called for packet that is not unacked: " |
| << sequence_number; |
| return; |
| } |
| if (it->second.pending) { |
| LOG_IF(DFATAL, bytes_in_flight_ < it->second.bytes_sent); |
| bytes_in_flight_ -= it->second.bytes_sent; |
| it->second.pending = false; |
| } |
| } |
| |
| bool QuicUnackedPacketMap::HasUnackedPackets() const { |
| return !unacked_packets_.empty(); |
| } |
| |
| bool QuicUnackedPacketMap::HasPendingPackets() const { |
| for (UnackedPacketMap::const_reverse_iterator it = |
| unacked_packets_.rbegin(); it != unacked_packets_.rend(); ++it) { |
| if (it->second.pending) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| const QuicUnackedPacketMap::TransmissionInfo& |
| QuicUnackedPacketMap::GetTransmissionInfo( |
| QuicPacketSequenceNumber sequence_number) const { |
| return unacked_packets_.find(sequence_number)->second; |
| } |
| |
| QuicTime QuicUnackedPacketMap::GetLastPacketSentTime() const { |
| UnackedPacketMap::const_reverse_iterator it = unacked_packets_.rbegin(); |
| while (it != unacked_packets_.rend()) { |
| if (it->second.pending) { |
| LOG_IF(DFATAL, it->second.sent_time == QuicTime::Zero()) |
| << "Sent time can never be zero for a pending packet."; |
| return it->second.sent_time; |
| } |
| ++it; |
| } |
| LOG(DFATAL) << "Unable to find sent time. " |
| << "This method is only intended when there are pending packets."; |
| return QuicTime::Zero(); |
| } |
| |
| QuicTime QuicUnackedPacketMap::GetFirstPendingPacketSentTime() const { |
| UnackedPacketMap::const_iterator it = unacked_packets_.begin(); |
| while (it != unacked_packets_.end() && !it->second.pending) { |
| ++it; |
| } |
| if (it == unacked_packets_.end()) { |
| LOG(DFATAL) << "No pending packets"; |
| return QuicTime::Zero(); |
| } |
| return it->second.sent_time; |
| } |
| |
| size_t QuicUnackedPacketMap::GetNumUnackedPackets() const { |
| return unacked_packets_.size(); |
| } |
| |
| bool QuicUnackedPacketMap::HasMultiplePendingPackets() const { |
| size_t num_pending = 0; |
| for (UnackedPacketMap::const_reverse_iterator it = unacked_packets_.rbegin(); |
| it != unacked_packets_.rend(); ++it) { |
| if (it->second.pending) { |
| ++num_pending; |
| } |
| if (num_pending > 1) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool QuicUnackedPacketMap::HasPendingCryptoPackets() const { |
| return pending_crypto_packet_count_ > 0; |
| } |
| |
| bool QuicUnackedPacketMap::HasUnackedRetransmittableFrames() const { |
| for (UnackedPacketMap::const_reverse_iterator it = |
| unacked_packets_.rbegin(); it != unacked_packets_.rend(); ++it) { |
| if (it->second.pending && it->second.retransmittable_frames) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| size_t QuicUnackedPacketMap::GetNumRetransmittablePackets() const { |
| size_t num_unacked_packets = 0; |
| for (UnackedPacketMap::const_iterator it = unacked_packets_.begin(); |
| it != unacked_packets_.end(); ++it) { |
| if (it->second.retransmittable_frames != NULL) { |
| ++num_unacked_packets; |
| } |
| } |
| return num_unacked_packets; |
| } |
| |
| QuicPacketSequenceNumber |
| QuicUnackedPacketMap::GetLeastUnackedSentPacket() const { |
| if (unacked_packets_.empty()) { |
| // If there are no unacked packets, return 0. |
| return 0; |
| } |
| |
| return unacked_packets_.begin()->first; |
| } |
| |
| SequenceNumberSet QuicUnackedPacketMap::GetUnackedPackets() const { |
| SequenceNumberSet unacked_packets; |
| for (UnackedPacketMap::const_iterator it = unacked_packets_.begin(); |
| it != unacked_packets_.end(); ++it) { |
| unacked_packets.insert(it->first); |
| } |
| return unacked_packets; |
| } |
| |
| void QuicUnackedPacketMap::SetSent(QuicPacketSequenceNumber sequence_number, |
| QuicTime sent_time, |
| QuicByteCount bytes_sent, |
| bool set_pending) { |
| DCHECK_LT(0u, sequence_number); |
| UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number); |
| if (it == unacked_packets_.end()) { |
| LOG(DFATAL) << "OnPacketSent called for packet that is not unacked: " |
| << sequence_number; |
| return; |
| } |
| DCHECK(!it->second.pending); |
| |
| largest_sent_packet_ = max(sequence_number, largest_sent_packet_); |
| it->second.sent_time = sent_time; |
| if (set_pending) { |
| bytes_in_flight_ += bytes_sent; |
| it->second.bytes_sent = bytes_sent; |
| it->second.pending = true; |
| } |
| } |
| |
| } // namespace net |