// Copyright 2013 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_received_packet_manager.h" #include "base/logging.h" #include "net/base/linked_hash_map.h" using std::make_pair; using std::max; using std::min; namespace net { QuicReceivedPacketManager::QuicReceivedPacketManager() : packets_entropy_hash_(0), largest_sequence_number_(0), peer_largest_observed_packet_(0), least_packet_awaited_by_peer_(1), peer_least_packet_awaiting_ack_(0), time_largest_observed_(QuicTime::Zero()) { received_info_.largest_observed = 0; received_info_.entropy_hash = 0; } QuicReceivedPacketManager::~QuicReceivedPacketManager() {} void QuicReceivedPacketManager::RecordPacketReceived( const QuicPacketHeader& header, QuicTime receipt_time) { QuicPacketSequenceNumber sequence_number = header.packet_sequence_number; DCHECK(IsAwaitingPacket(sequence_number)); InsertMissingPacketsBetween( &received_info_, max(received_info_.largest_observed + 1, peer_least_packet_awaiting_ack_), header.packet_sequence_number); if (received_info_.largest_observed > header.packet_sequence_number) { // We've gotten one of the out of order packets - remove it from our // "missing packets" list. DVLOG(1) << "Removing " << sequence_number << " from missing list"; received_info_.missing_packets.erase(sequence_number); } if (header.packet_sequence_number > received_info_.largest_observed) { received_info_.largest_observed = header.packet_sequence_number; time_largest_observed_ = receipt_time; } RecordPacketEntropyHash(sequence_number, header.entropy_hash); } bool QuicReceivedPacketManager::IsAwaitingPacket( QuicPacketSequenceNumber sequence_number) { return ::net::IsAwaitingPacket(received_info_, sequence_number); } void QuicReceivedPacketManager::UpdateReceivedPacketInfo( ReceivedPacketInfo* received_info, QuicTime approximate_now) { *received_info = received_info_; received_info->entropy_hash = EntropyHash(received_info_.largest_observed); if (time_largest_observed_ == QuicTime::Zero()) { // We have not received any new higher sequence numbers since we sent our // last ACK. received_info->delta_time_largest_observed = QuicTime::Delta::Infinite(); } else { received_info->delta_time_largest_observed = approximate_now.Subtract(time_largest_observed_); time_largest_observed_ = QuicTime::Zero(); } } void QuicReceivedPacketManager::RecordPacketEntropyHash( QuicPacketSequenceNumber sequence_number, QuicPacketEntropyHash entropy_hash) { if (sequence_number < largest_sequence_number_) { DLOG(INFO) << "Ignoring received packet entropy for sequence_number:" << sequence_number << " less than largest_peer_sequence_number:" << largest_sequence_number_; return; } packets_entropy_.insert(make_pair(sequence_number, entropy_hash)); packets_entropy_hash_ ^= entropy_hash; DVLOG(2) << "setting cumulative received entropy hash to: " << static_cast(packets_entropy_hash_) << " updated with sequence number " << sequence_number << " entropy hash: " << static_cast(entropy_hash); } QuicPacketEntropyHash QuicReceivedPacketManager::EntropyHash( QuicPacketSequenceNumber sequence_number) const { DCHECK_LE(sequence_number, received_info_.largest_observed); DCHECK_GE(sequence_number, largest_sequence_number_); if (sequence_number == received_info_.largest_observed) { return packets_entropy_hash_; } ReceivedEntropyMap::const_iterator it = packets_entropy_.upper_bound(sequence_number); // When this map is empty we should only query entropy for // |largest_received_sequence_number_|. // TODO(rtenneti): add support for LOG_IF_EVERY_N_SEC to chromium. // LOG_IF_EVERY_N_SEC(WARNING, it != packets_entropy_.end(), 10) LOG_IF(WARNING, it != packets_entropy_.end()) << "largest_received: " << received_info_.largest_observed << " sequence_number: " << sequence_number; // TODO(satyamshekhar): Make this O(1). QuicPacketEntropyHash hash = packets_entropy_hash_; for (; it != packets_entropy_.end(); ++it) { hash ^= it->second; } return hash; } void QuicReceivedPacketManager::RecalculateEntropyHash( QuicPacketSequenceNumber peer_least_unacked, QuicPacketEntropyHash entropy_hash) { DCHECK_LE(peer_least_unacked, received_info_.largest_observed); if (peer_least_unacked < largest_sequence_number_) { DLOG(INFO) << "Ignoring received peer_least_unacked:" << peer_least_unacked << " less than largest_peer_sequence_number:" << largest_sequence_number_; return; } largest_sequence_number_ = peer_least_unacked; packets_entropy_hash_ = entropy_hash; ReceivedEntropyMap::iterator it = packets_entropy_.lower_bound(peer_least_unacked); // TODO(satyamshekhar): Make this O(1). for (; it != packets_entropy_.end(); ++it) { packets_entropy_hash_ ^= it->second; } // Discard entropies before least unacked. packets_entropy_.erase( packets_entropy_.begin(), packets_entropy_.lower_bound( min(peer_least_unacked, received_info_.largest_observed))); } void QuicReceivedPacketManager::UpdatePacketInformationReceivedByPeer( const QuicAckFrame& incoming_ack) { // ValidateAck should fail if largest_observed ever shrinks. DCHECK_LE(peer_largest_observed_packet_, incoming_ack.received_info.largest_observed); peer_largest_observed_packet_ = incoming_ack.received_info.largest_observed; if (incoming_ack.received_info.missing_packets.empty()) { least_packet_awaited_by_peer_ = peer_largest_observed_packet_ + 1; } else { least_packet_awaited_by_peer_ = *(incoming_ack.received_info.missing_packets.begin()); } } bool QuicReceivedPacketManager::DontWaitForPacketsBefore( QuicPacketSequenceNumber least_unacked) { size_t missing_packets_count = received_info_.missing_packets.size(); received_info_.missing_packets.erase( received_info_.missing_packets.begin(), received_info_.missing_packets.lower_bound(least_unacked)); return missing_packets_count != received_info_.missing_packets.size(); } void QuicReceivedPacketManager::UpdatePacketInformationSentByPeer( const QuicAckFrame& incoming_ack) { // ValidateAck() should fail if peer_least_packet_awaiting_ack_ shrinks. DCHECK_LE(peer_least_packet_awaiting_ack_, incoming_ack.sent_info.least_unacked); if (incoming_ack.sent_info.least_unacked > peer_least_packet_awaiting_ack_) { bool missed_packets = DontWaitForPacketsBefore(incoming_ack.sent_info.least_unacked); if (missed_packets || incoming_ack.sent_info.least_unacked > received_info_.largest_observed + 1) { DVLOG(1) << "Updating entropy hashed since we missed packets"; // There were some missing packets that we won't ever get now. Recalculate // the received entropy hash. RecalculateEntropyHash(incoming_ack.sent_info.least_unacked, incoming_ack.sent_info.entropy_hash); } peer_least_packet_awaiting_ack_ = incoming_ack.sent_info.least_unacked; } DCHECK(received_info_.missing_packets.empty() || *received_info_.missing_packets.begin() >= peer_least_packet_awaiting_ack_); } } // namespace net