blob: 8d0a4b79ed2af7a9f12a871dc84724bb86f5c88e [file] [log] [blame]
// 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