gfe-relnote: In QUIC, add uber_received_packet_manager which purely wraps a received_packet_manager. Using it is protected by gfe2_reloadable_flag_quic_use_uber_received_packet_manager. PiperOrigin-RevId: 239601171 Change-Id: Iaa62e2641e0466a03981a6ba7dd128990b09744c
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index 574dd0c..f213d35 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -266,6 +266,7 @@ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET), close_connection_after_five_rtos_(false), received_packet_manager_(&stats_), + uber_received_packet_manager_(&stats_), ack_queued_(false), num_retransmittable_packets_received_since_last_ack_sent_(0), num_packets_received_since_last_ack_sent_(0), @@ -353,7 +354,10 @@ GetQuicReloadableFlag(quic_fix_termination_packets)), send_ack_when_on_can_write_(false), validate_packet_number_post_decryption_( - GetQuicReloadableFlag(quic_validate_packet_number_post_decryption)) { + GetQuicReloadableFlag(quic_validate_packet_number_post_decryption)), + use_uber_received_packet_manager_( + received_packet_manager_.decide_when_to_send_acks() && + GetQuicReloadableFlag(quic_use_uber_received_packet_manager)) { if (ack_mode_ == ACK_DECIMATION) { QUIC_RELOADABLE_FLAG_COUNT(quic_enable_ack_decimation); } @@ -370,6 +374,9 @@ if (validate_packet_number_post_decryption_) { QUIC_RELOADABLE_FLAG_COUNT(quic_validate_packet_number_post_decryption); } + if (use_uber_received_packet_manager_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_use_uber_received_packet_manager); + } QUIC_DLOG(INFO) << ENDPOINT << "Created connection with connection_id: " << connection_id << " and version: " @@ -396,7 +403,11 @@ SetMaxPacketLength(perspective_ == Perspective::IS_SERVER ? kDefaultServerMaxPacketSize : kDefaultMaxPacketSize); - received_packet_manager_.set_max_ack_ranges(255); + if (use_uber_received_packet_manager_) { + uber_received_packet_manager_.set_max_ack_ranges(255); + } else { + received_packet_manager_.set_max_ack_ranges(255); + } MaybeEnableSessionDecidesWhatToWrite(); DCHECK(!GetQuicRestartFlag(quic_no_server_conn_ver_negotiation2) || perspective_ == Perspective::IS_CLIENT || @@ -452,7 +463,11 @@ debug_visitor_->OnSetFromConfig(config); } if (received_packet_manager_.decide_when_to_send_acks()) { - received_packet_manager_.SetFromConfig(config, perspective_); + if (use_uber_received_packet_manager_) { + uber_received_packet_manager_.SetFromConfig(config, perspective_); + } else { + received_packet_manager_.SetFromConfig(config, perspective_); + } } else { if (GetQuicReloadableFlag(quic_enable_ack_decimation) && config.HasClientSentConnectionOption(kACD0, perspective_)) { @@ -493,7 +508,11 @@ config.HasClientSentConnectionOption(kSTMP, perspective_)) { QUIC_RELOADABLE_FLAG_COUNT(quic_send_timestamps); framer_.set_process_timestamps(true); - received_packet_manager_.set_save_timestamps(true); + if (use_uber_received_packet_manager_) { + uber_received_packet_manager_.set_save_timestamps(true); + } else { + received_packet_manager_.set_save_timestamps(true); + } } supports_release_time_ = @@ -802,21 +821,27 @@ // If this packet has already been seen, or the sender has told us that it // will not be retransmitted, then stop processing the packet. - if (!validate_packet_number_post_decryption_ && - !received_packet_manager_.IsAwaitingPacket(header.packet_number)) { - if (framer_.IsIetfStatelessResetPacket(header)) { - QuicIetfStatelessResetPacket packet( - header, header.possible_stateless_reset_token); - OnAuthenticatedIetfStatelessResetPacket(packet); + if (!validate_packet_number_post_decryption_) { + const bool is_awaiting = + use_uber_received_packet_manager_ + ? uber_received_packet_manager_.IsAwaitingPacket( + header.packet_number) + : received_packet_manager_.IsAwaitingPacket(header.packet_number); + if (!is_awaiting) { + if (framer_.IsIetfStatelessResetPacket(header)) { + QuicIetfStatelessResetPacket packet( + header, header.possible_stateless_reset_token); + OnAuthenticatedIetfStatelessResetPacket(packet); + return false; + } + QUIC_DLOG(INFO) << ENDPOINT << "Packet " << header.packet_number + << " no longer being waited for. Discarding."; + if (debug_visitor_ != nullptr) { + debug_visitor_->OnDuplicatePacket(header.packet_number); + } + ++stats_.packets_dropped; return false; } - QUIC_DLOG(INFO) << ENDPOINT << "Packet " << header.packet_number - << " no longer being waited for. Discarding."; - if (debug_visitor_ != nullptr) { - debug_visitor_->OnDuplicatePacket(header.packet_number); - } - ++stats_.packets_dropped; - return false; } if (version_negotiation_state_ != NEGOTIATED_VERSION && @@ -925,13 +950,20 @@ QUIC_DVLOG(1) << ENDPOINT << "Received packet header: " << header; last_header_ = header; // An ack will be sent if a missing retransmittable packet was received; - was_last_packet_missing_ = - received_packet_manager_.IsMissing(last_header_.packet_number); + if (!use_uber_received_packet_manager_) { + was_last_packet_missing_ = + received_packet_manager_.IsMissing(last_header_.packet_number); + } // Record packet receipt to populate ack info before processing stream // frames, since the processing may result in sending a bundled ack. - received_packet_manager_.RecordPacketReceived(last_header_, - time_of_last_received_packet_); + if (use_uber_received_packet_manager_) { + uber_received_packet_manager_.RecordPacketReceived( + last_header_, time_of_last_received_packet_); + } else { + received_packet_manager_.RecordPacketReceived( + last_header_, time_of_last_received_packet_); + } DCHECK(connected_); return true; } @@ -958,8 +990,8 @@ QUIC_PEER_BUG << ENDPOINT << "Received an unencrypted data frame: closing connection" << " packet_number:" << last_header_.packet_number - << " stream_id:" << frame.stream_id << " received_packets:" - << received_packet_manager_.ack_frame(); + << " stream_id:" << frame.stream_id + << " received_packets:" << GetUpdatedAckFrame(); CloseConnection(QUIC_UNENCRYPTED_STREAM_DATA, "Unencrypted stream data seen.", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); @@ -1134,7 +1166,11 @@ } largest_seen_packet_with_stop_waiting_ = last_header_.packet_number; - received_packet_manager_.DontWaitForPacketsBefore(frame.least_unacked); + if (use_uber_received_packet_manager_) { + uber_received_packet_manager_.DontWaitForPacketsBefore(frame.least_unacked); + } else { + received_packet_manager_.DontWaitForPacketsBefore(frame.least_unacked); + } return connected_; } @@ -1161,14 +1197,15 @@ const char* QuicConnection::ValidateStopWaitingFrame( const QuicStopWaitingFrame& stop_waiting) { - if (received_packet_manager_.peer_least_packet_awaiting_ack() - .IsInitialized() && - stop_waiting.least_unacked < - received_packet_manager_.peer_least_packet_awaiting_ack()) { - QUIC_DLOG(ERROR) - << ENDPOINT - << "Peer's sent low least_unacked: " << stop_waiting.least_unacked - << " vs " << received_packet_manager_.peer_least_packet_awaiting_ack(); + const QuicPacketNumber peer_least_packet_awaiting_ack = + use_uber_received_packet_manager_ + ? uber_received_packet_manager_.peer_least_packet_awaiting_ack() + : received_packet_manager_.peer_least_packet_awaiting_ack(); + if (peer_least_packet_awaiting_ack.IsInitialized() && + stop_waiting.least_unacked < peer_least_packet_awaiting_ack) { + QUIC_DLOG(ERROR) << ENDPOINT << "Peer's sent low least_unacked: " + << stop_waiting.least_unacked << " vs " + << peer_least_packet_awaiting_ack; // We never process old ack frames, so this number should only increase. return "Least unacked too small."; } @@ -1451,11 +1488,19 @@ should_last_packet_instigate_acks_ && was_last_packet_missing_; if (received_packet_manager_.decide_when_to_send_acks()) { - received_packet_manager_.MaybeUpdateAckTimeout( - should_last_packet_instigate_acks_, last_header_.packet_number, - time_of_last_received_packet_, clock_->ApproximateNow(), - sent_packet_manager_.GetRttStats(), - sent_packet_manager_.delayed_ack_time()); + if (use_uber_received_packet_manager_) { + uber_received_packet_manager_.MaybeUpdateAckTimeout( + should_last_packet_instigate_acks_, last_header_.packet_number, + time_of_last_received_packet_, clock_->ApproximateNow(), + sent_packet_manager_.GetRttStats(), + sent_packet_manager_.delayed_ack_time()); + } else { + received_packet_manager_.MaybeUpdateAckTimeout( + should_last_packet_instigate_acks_, last_header_.packet_number, + time_of_last_received_packet_, clock_->ApproximateNow(), + sent_packet_manager_.GetRttStats(), + sent_packet_manager_.delayed_ack_time()); + } } else if (ack_frame_updated()) { // It's possible the ack frame was sent along with response data, so it // no longer needs to be sent. @@ -1609,6 +1654,10 @@ } const QuicFrame QuicConnection::GetUpdatedAckFrame() { + if (use_uber_received_packet_manager_) { + return uber_received_packet_manager_.GetUpdatedAckFrame( + clock_->ApproximateNow()); + } return received_packet_manager_.GetUpdatedAckFrame(clock_->ApproximateNow()); } @@ -1910,7 +1959,10 @@ WriteQueuedPackets(); if (received_packet_manager_.decide_when_to_send_acks()) { - const QuicTime ack_timeout = received_packet_manager_.ack_timeout(); + const QuicTime ack_timeout = + use_uber_received_packet_manager_ + ? uber_received_packet_manager_.GetAckTimeout() + : received_packet_manager_.ack_timeout(); if (ack_timeout.IsInitialized() && ack_timeout <= clock_->ApproximateNow()) { // Send an ACK now because either 1) we were write blocked when we last @@ -2033,14 +2085,19 @@ bool QuicConnection::ValidateReceivedPacketNumber( QuicPacketNumber packet_number) { - if (validate_packet_number_post_decryption_ && - !received_packet_manager_.IsAwaitingPacket(packet_number)) { - QUIC_DLOG(INFO) << ENDPOINT << "Packet " << packet_number - << " no longer being waited for. Discarding."; - if (debug_visitor_ != nullptr) { - debug_visitor_->OnDuplicatePacket(packet_number); + if (validate_packet_number_post_decryption_) { + const bool is_awaiting = + use_uber_received_packet_manager_ + ? uber_received_packet_manager_.IsAwaitingPacket(packet_number) + : received_packet_manager_.IsAwaitingPacket(packet_number); + if (!is_awaiting) { + QUIC_DLOG(INFO) << ENDPOINT << "Packet " << packet_number + << " no longer being waited for. Discarding."; + if (debug_visitor_ != nullptr) { + debug_visitor_->OnDuplicatePacket(packet_number); + } + return false; } - return false; } if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { @@ -2064,17 +2121,18 @@ } return true; } - - if (packet_number > received_packet_manager_.PeerFirstSendingPacketNumber() && + const QuicPacketNumber peer_first_sending_packet_number = + use_uber_received_packet_manager_ + ? uber_received_packet_manager_.PeerFirstSendingPacketNumber() + : received_packet_manager_.PeerFirstSendingPacketNumber(); + if (packet_number > peer_first_sending_packet_number && packet_number <= MaxRandomInitialPacketNumber()) { QUIC_CODE_COUNT_N(had_possibly_random_ipn, 2, 2); } const bool out_of_bound = last_header_.packet_number.IsInitialized() ? !Near(packet_number, last_header_.packet_number) - : packet_number >= - (received_packet_manager_.PeerFirstSendingPacketNumber() + - kMaxPacketGap); + : packet_number >= (peer_first_sending_packet_number + kMaxPacketGap); if (!out_of_bound) { return true; } @@ -2213,7 +2271,12 @@ QuicFrames frames; bool has_pending_ack = false; if (received_packet_manager_.decide_when_to_send_acks()) { - has_pending_ack = received_packet_manager_.ack_timeout().IsInitialized(); + if (use_uber_received_packet_manager_) { + has_pending_ack = + uber_received_packet_manager_.GetAckTimeout().IsInitialized(); + } else { + has_pending_ack = received_packet_manager_.ack_timeout().IsInitialized(); + } } else { has_pending_ack = ack_alarm_->IsSet(); } @@ -3207,7 +3270,9 @@ if (connection_->packet_generator_.deprecate_ack_bundling_mode()) { if (connection_->received_packet_manager_.decide_when_to_send_acks()) { const QuicTime ack_timeout = - connection_->received_packet_manager_.ack_timeout(); + connection_->use_uber_received_packet_manager_ + ? connection_->uber_received_packet_manager_.GetAckTimeout() + : connection_->received_packet_manager_.ack_timeout(); if (ack_timeout.IsInitialized()) { if (ack_timeout <= connection_->clock_->ApproximateNow() && !connection_->CanWrite(NO_RETRANSMITTABLE_DATA)) { @@ -3531,6 +3596,9 @@ } bool QuicConnection::ack_frame_updated() const { + if (use_uber_received_packet_manager_) { + return uber_received_packet_manager_.AckFrameUpdated(); + } return received_packet_manager_.ack_frame_updated(); } @@ -3676,8 +3744,13 @@ void QuicConnection::PostProcessAfterAckFrame(bool send_stop_waiting, bool acked_new_packet) { if (no_stop_waiting_frames_) { - received_packet_manager_.DontWaitForPacketsBefore( - sent_packet_manager_.largest_packet_peer_knows_is_acked()); + if (use_uber_received_packet_manager_) { + uber_received_packet_manager_.DontWaitForPacketsBefore( + sent_packet_manager_.largest_packet_peer_knows_is_acked()); + } else { + received_packet_manager_.DontWaitForPacketsBefore( + sent_packet_manager_.largest_packet_peer_knows_is_acked()); + } } // Always reset the retransmission alarm when an ack comes in, since we now // have a better estimate of the current rtt than when it was set. @@ -3744,7 +3817,11 @@ num_retransmittable_packets_received_since_last_ack_sent_ = 0; num_packets_received_since_last_ack_sent_ = 0; if (received_packet_manager_.decide_when_to_send_acks()) { - received_packet_manager_.ResetAckStates(); + if (use_uber_received_packet_manager_) { + uber_received_packet_manager_.ResetAckStates(); + } else { + received_packet_manager_.ResetAckStates(); + } } } @@ -3827,11 +3904,17 @@ } QuicPacketNumber QuicConnection::GetLargestReceivedPacket() const { + if (use_uber_received_packet_manager_) { + return uber_received_packet_manager_.GetLargestObserved(); + } return received_packet_manager_.GetLargestObserved(); } size_t QuicConnection::min_received_before_ack_decimation() const { if (received_packet_manager_.decide_when_to_send_acks()) { + if (use_uber_received_packet_manager_) { + return uber_received_packet_manager_.min_received_before_ack_decimation(); + } return received_packet_manager_.min_received_before_ack_decimation(); } return min_received_before_ack_decimation_; @@ -3839,7 +3922,13 @@ void QuicConnection::set_min_received_before_ack_decimation(size_t new_value) { if (received_packet_manager_.decide_when_to_send_acks()) { - received_packet_manager_.set_min_received_before_ack_decimation(new_value); + if (use_uber_received_packet_manager_) { + uber_received_packet_manager_.set_min_received_before_ack_decimation( + new_value); + } else { + received_packet_manager_.set_min_received_before_ack_decimation( + new_value); + } } else { min_received_before_ack_decimation_ = new_value; } @@ -3847,6 +3936,10 @@ size_t QuicConnection::ack_frequency_before_ack_decimation() const { if (received_packet_manager_.decide_when_to_send_acks()) { + if (use_uber_received_packet_manager_) { + return uber_received_packet_manager_ + .ack_frequency_before_ack_decimation(); + } return received_packet_manager_.ack_frequency_before_ack_decimation(); } return ack_frequency_before_ack_decimation_; @@ -3855,7 +3948,13 @@ void QuicConnection::set_ack_frequency_before_ack_decimation(size_t new_value) { DCHECK_GT(new_value, 0u); if (received_packet_manager_.decide_when_to_send_acks()) { - received_packet_manager_.set_ack_frequency_before_ack_decimation(new_value); + if (use_uber_received_packet_manager_) { + uber_received_packet_manager_.set_ack_frequency_before_ack_decimation( + new_value); + } else { + received_packet_manager_.set_ack_frequency_before_ack_decimation( + new_value); + } } else { ack_frequency_before_ack_decimation_ = new_value; }
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h index ae9d5c3..745991f 100644 --- a/quic/core/quic_connection.h +++ b/quic/core/quic_connection.h
@@ -38,10 +38,10 @@ #include "net/third_party/quiche/src/quic/core/quic_packet_generator.h" #include "net/third_party/quiche/src/quic/core/quic_packet_writer.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" -#include "net/third_party/quiche/src/quic/core/quic_received_packet_manager.h" #include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h" #include "net/third_party/quiche/src/quic/core/quic_time.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/uber_received_packet_manager.h" #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" @@ -1236,7 +1236,11 @@ // 200ms, this is over 5 seconds. bool close_connection_after_five_rtos_; + // TODO(fayang): remove received_packet_manager_ when deprecating + // quic_use_uber_received_packet_manager. QuicReceivedPacketManager received_packet_manager_; + // Used when use_uber_received_packet_manager_ is true. + UberReceivedPacketManager uber_received_packet_manager_; // Indicates whether an ack should be sent the next time we try to write. // TODO(fayang): Remove ack_queued_ when deprecating @@ -1487,6 +1491,10 @@ // Latched value of quic_validate_packet_number_post_decryption. const bool validate_packet_number_post_decryption_; + + // Latched value of quic_rpm_decides_when_to_send_acks and + // quic_use_uber_received_packet_manager. + const bool use_uber_received_packet_manager_; }; } // namespace quic
diff --git a/quic/core/quic_received_packet_manager.cc b/quic/core/quic_received_packet_manager.cc index 921c674..82984eb 100644 --- a/quic/core/quic_received_packet_manager.cc +++ b/quic/core/quic_received_packet_manager.cc
@@ -154,7 +154,7 @@ } bool QuicReceivedPacketManager::IsAwaitingPacket( - QuicPacketNumber packet_number) { + QuicPacketNumber packet_number) const { return quic::IsAwaitingPacket(ack_frame_, packet_number, peer_least_packet_awaiting_ack_); }
diff --git a/quic/core/quic_received_packet_manager.h b/quic/core/quic_received_packet_manager.h index 787e1fb..8eb8cac 100644 --- a/quic/core/quic_received_packet_manager.h +++ b/quic/core/quic_received_packet_manager.h
@@ -17,6 +17,7 @@ namespace test { class QuicConnectionPeer; class QuicReceivedPacketManagerPeer; +class UberReceivedPacketManagerPeer; } // namespace test struct QuicConnectionStats; @@ -42,7 +43,7 @@ virtual bool IsMissing(QuicPacketNumber packet_number); // Checks if we're still waiting for the packet with |packet_number|. - virtual bool IsAwaitingPacket(QuicPacketNumber packet_number); + virtual bool IsAwaitingPacket(QuicPacketNumber packet_number) const; // Retrieves a frame containing a QuicAckFrame. The ack frame may not be // changed outside QuicReceivedPacketManager and must be serialized before @@ -75,7 +76,7 @@ // packets of the largest observed. virtual bool HasNewMissingPackets() const; - QuicPacketNumber peer_least_packet_awaiting_ack() { + QuicPacketNumber peer_least_packet_awaiting_ack() const { return peer_least_packet_awaiting_ack_; } @@ -123,6 +124,7 @@ private: friend class test::QuicConnectionPeer; friend class test::QuicReceivedPacketManagerPeer; + friend class test::UberReceivedPacketManagerPeer; // Sets ack_timeout_ to |time| if ack_timeout_ is not initialized or > time. void MaybeUpdateAckTimeoutTo(QuicTime time);
diff --git a/quic/core/uber_received_packet_manager.cc b/quic/core/uber_received_packet_manager.cc new file mode 100644 index 0000000..b730474 --- /dev/null +++ b/quic/core/uber_received_packet_manager.cc
@@ -0,0 +1,108 @@ +// Copyright 2019 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/third_party/quiche/src/quic/core/uber_received_packet_manager.h" + +namespace quic { + +UberReceivedPacketManager::UberReceivedPacketManager(QuicConnectionStats* stats) + : received_packet_manager_(stats) {} + +UberReceivedPacketManager::~UberReceivedPacketManager() {} + +void UberReceivedPacketManager::SetFromConfig(const QuicConfig& config, + Perspective perspective) { + received_packet_manager_.SetFromConfig(config, perspective); +} + +bool UberReceivedPacketManager::IsAwaitingPacket( + QuicPacketNumber packet_number) const { + return received_packet_manager_.IsAwaitingPacket(packet_number); +} + +const QuicFrame UberReceivedPacketManager::GetUpdatedAckFrame( + QuicTime approximate_now) { + return received_packet_manager_.GetUpdatedAckFrame(approximate_now); +} + +void UberReceivedPacketManager::RecordPacketReceived( + const QuicPacketHeader& header, + QuicTime receipt_time) { + received_packet_manager_.RecordPacketReceived(header, receipt_time); +} + +void UberReceivedPacketManager::DontWaitForPacketsBefore( + QuicPacketNumber least_unacked) { + received_packet_manager_.DontWaitForPacketsBefore(least_unacked); +} + +void UberReceivedPacketManager::MaybeUpdateAckTimeout( + bool should_last_packet_instigate_acks, + QuicPacketNumber last_received_packet_number, + QuicTime time_of_last_received_packet, + QuicTime now, + const RttStats* rtt_stats, + QuicTime::Delta delayed_ack_time) { + received_packet_manager_.MaybeUpdateAckTimeout( + should_last_packet_instigate_acks, last_received_packet_number, + time_of_last_received_packet, now, rtt_stats, delayed_ack_time); +} + +void UberReceivedPacketManager::ResetAckStates() { + received_packet_manager_.ResetAckStates(); +} + +bool UberReceivedPacketManager::AckFrameUpdated() const { + return received_packet_manager_.ack_frame_updated(); +} + +QuicPacketNumber UberReceivedPacketManager::GetLargestObserved() const { + return received_packet_manager_.GetLargestObserved(); +} + +QuicTime UberReceivedPacketManager::GetAckTimeout() const { + return received_packet_manager_.ack_timeout(); +} + +QuicPacketNumber UberReceivedPacketManager::PeerFirstSendingPacketNumber() + const { + return received_packet_manager_.PeerFirstSendingPacketNumber(); +} + +QuicPacketNumber UberReceivedPacketManager::peer_least_packet_awaiting_ack() + const { + return received_packet_manager_.peer_least_packet_awaiting_ack(); +} + +size_t UberReceivedPacketManager::min_received_before_ack_decimation() const { + return received_packet_manager_.min_received_before_ack_decimation(); +} + +void UberReceivedPacketManager::set_min_received_before_ack_decimation( + size_t new_value) { + received_packet_manager_.set_min_received_before_ack_decimation(new_value); +} + +size_t UberReceivedPacketManager::ack_frequency_before_ack_decimation() const { + return received_packet_manager_.ack_frequency_before_ack_decimation(); +} + +void UberReceivedPacketManager::set_ack_frequency_before_ack_decimation( + size_t new_value) { + received_packet_manager_.set_ack_frequency_before_ack_decimation(new_value); +} + +const QuicAckFrame& UberReceivedPacketManager::ack_frame() const { + return received_packet_manager_.ack_frame(); +} + +void UberReceivedPacketManager::set_max_ack_ranges(size_t max_ack_ranges) { + received_packet_manager_.set_max_ack_ranges(max_ack_ranges); +} + +void UberReceivedPacketManager::set_save_timestamps(bool save_timestamps) { + received_packet_manager_.set_save_timestamps(save_timestamps); +} + +} // namespace quic
diff --git a/quic/core/uber_received_packet_manager.h b/quic/core/uber_received_packet_manager.h new file mode 100644 index 0000000..367a7c0 --- /dev/null +++ b/quic/core/uber_received_packet_manager.h
@@ -0,0 +1,87 @@ +// Copyright 2019 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. + +#ifndef QUICHE_QUIC_CORE_UBER_RECEIVED_PACKET_MANAGER_H_ +#define QUICHE_QUIC_CORE_UBER_RECEIVED_PACKET_MANAGER_H_ + +#include "net/third_party/quiche/src/quic/core/quic_received_packet_manager.h" + +namespace quic { + +// This class simply wraps a single received packet manager. +class QUIC_EXPORT_PRIVATE UberReceivedPacketManager { + public: + explicit UberReceivedPacketManager(QuicConnectionStats* stats); + UberReceivedPacketManager(const UberReceivedPacketManager&) = delete; + UberReceivedPacketManager& operator=(const UberReceivedPacketManager&) = + delete; + virtual ~UberReceivedPacketManager(); + + void SetFromConfig(const QuicConfig& config, Perspective perspective); + + // Checks if we are still waiting for the packet with |packet_number|. + bool IsAwaitingPacket(QuicPacketNumber packet_number) const; + + // Called after a packet has been successfully decrypted and its header has + // been parsed. + void RecordPacketReceived(const QuicPacketHeader& header, + QuicTime receipt_time); + + // Retrieves a frame containing a QuicAckFrame. The ack frame must be + // serialized before another packet is received, or it will change. + const QuicFrame GetUpdatedAckFrame(QuicTime approximate_now); + + // Stop ACKing packets before |least_unacked|. + void DontWaitForPacketsBefore(QuicPacketNumber least_unacked); + + // Called after header of last received packet has been successfully processed + // to update ACK timeout. + void MaybeUpdateAckTimeout(bool should_last_packet_instigate_acks, + QuicPacketNumber last_received_packet_number, + QuicTime time_of_last_received_packet, + QuicTime now, + const RttStats* rtt_stats, + QuicTime::Delta delayed_ack_time); + + // Resets ACK related states, called after an ACK is successfully sent. + void ResetAckStates(); + + // Returns true if ACK frame has been updated since GetUpdatedAckFrame was + // last called. + bool AckFrameUpdated() const; + + // Returns the largest received packet number. + QuicPacketNumber GetLargestObserved() const; + + // Returns current ACK timeout. + QuicTime GetAckTimeout() const; + + // Returns peer first sending packet number to our best knowledge. + QuicPacketNumber PeerFirstSendingPacketNumber() const; + + QuicPacketNumber peer_least_packet_awaiting_ack() const; + + size_t min_received_before_ack_decimation() const; + void set_min_received_before_ack_decimation(size_t new_value); + + size_t ack_frequency_before_ack_decimation() const; + void set_ack_frequency_before_ack_decimation(size_t new_value); + + // For logging purposes. + const QuicAckFrame& ack_frame() const; + + void set_max_ack_ranges(size_t max_ack_ranges); + + void set_save_timestamps(bool save_timestamps); + + private: + friend class test::QuicConnectionPeer; + friend class test::UberReceivedPacketManagerPeer; + + QuicReceivedPacketManager received_packet_manager_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_UBER_RECEIVED_PACKET_MANAGER_H_
diff --git a/quic/core/uber_received_packet_manager_test.cc b/quic/core/uber_received_packet_manager_test.cc new file mode 100644 index 0000000..4ffb03c --- /dev/null +++ b/quic/core/uber_received_packet_manager_test.cc
@@ -0,0 +1,690 @@ +// Copyright 2019 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/third_party/quiche/src/quic/core/uber_received_packet_manager.h" + +#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_stats.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" + +namespace quic { +namespace test { + +class UberReceivedPacketManagerPeer { + public: + static void SetAckMode(UberReceivedPacketManager* manager, AckMode ack_mode) { + manager->received_packet_manager_.ack_mode_ = ack_mode; + } + + static void SetFastAckAfterQuiescence(UberReceivedPacketManager* manager, + bool fast_ack_after_quiescence) { + manager->received_packet_manager_.fast_ack_after_quiescence_ = + fast_ack_after_quiescence; + } + + static void SetAckDecimationDelay(UberReceivedPacketManager* manager, + float ack_decimation_delay) { + manager->received_packet_manager_.ack_decimation_delay_ = + ack_decimation_delay; + } +}; + +namespace { + +const bool kInstigateAck = true; +const QuicTime::Delta kMinRttMs = QuicTime::Delta::FromMilliseconds(40); +const QuicTime::Delta kDelayedAckTime = + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); + +class UberReceivedPacketManagerTest : public QuicTest { + protected: + UberReceivedPacketManagerTest() { + SetQuicReloadableFlag(quic_deprecate_ack_bundling_mode, true); + SetQuicReloadableFlag(quic_rpm_decides_when_to_send_acks, true); + manager_ = QuicMakeUnique<UberReceivedPacketManager>(&stats_); + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); + rtt_stats_.UpdateRtt(kMinRttMs, QuicTime::Delta::Zero(), QuicTime::Zero()); + manager_->set_save_timestamps(true); + } + + void RecordPacketReceipt(uint64_t packet_number) { + RecordPacketReceipt(packet_number, QuicTime::Zero()); + } + + void RecordPacketReceipt(uint64_t packet_number, QuicTime receipt_time) { + QuicPacketHeader header; + header.packet_number = QuicPacketNumber(packet_number); + manager_->RecordPacketReceived(header, receipt_time); + } + + bool HasPendingAck() { return manager_->GetAckTimeout().IsInitialized(); } + + void MaybeUpdateAckTimeout(bool should_last_packet_instigate_acks, + uint64_t last_received_packet_number) { + manager_->MaybeUpdateAckTimeout( + should_last_packet_instigate_acks, + QuicPacketNumber(last_received_packet_number), clock_.ApproximateNow(), + clock_.ApproximateNow(), &rtt_stats_, kDelayedAckTime); + } + + void CheckAckTimeout(QuicTime time) { + DCHECK(HasPendingAck() && manager_->GetAckTimeout() == time); + if (time <= clock_.ApproximateNow()) { + // ACK timeout expires, send an ACK. + manager_->ResetAckStates(); + DCHECK(!HasPendingAck()); + } + } + + MockClock clock_; + RttStats rtt_stats_; + QuicConnectionStats stats_; + std::unique_ptr<UberReceivedPacketManager> manager_; +}; + +TEST_F(UberReceivedPacketManagerTest, DontWaitForPacketsBefore) { + QuicPacketHeader header; + header.packet_number = QuicPacketNumber(2u); + manager_->RecordPacketReceived(header, QuicTime::Zero()); + header.packet_number = QuicPacketNumber(7u); + manager_->RecordPacketReceived(header, QuicTime::Zero()); + EXPECT_TRUE(manager_->IsAwaitingPacket(QuicPacketNumber(3u))); + EXPECT_TRUE(manager_->IsAwaitingPacket(QuicPacketNumber(6u))); + manager_->DontWaitForPacketsBefore(QuicPacketNumber(4)); + EXPECT_FALSE(manager_->IsAwaitingPacket(QuicPacketNumber(3u))); + EXPECT_TRUE(manager_->IsAwaitingPacket(QuicPacketNumber(6u))); +} + +TEST_F(UberReceivedPacketManagerTest, GetUpdatedAckFrame) { + QuicPacketHeader header; + header.packet_number = QuicPacketNumber(2u); + QuicTime two_ms = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2); + EXPECT_FALSE(manager_->AckFrameUpdated()); + manager_->RecordPacketReceived(header, two_ms); + EXPECT_TRUE(manager_->AckFrameUpdated()); + + QuicFrame ack = manager_->GetUpdatedAckFrame(QuicTime::Zero()); + manager_->ResetAckStates(); + EXPECT_FALSE(manager_->AckFrameUpdated()); + // When UpdateReceivedPacketInfo with a time earlier than the time of the + // largest observed packet, make sure that the delta is 0, not negative. + EXPECT_EQ(QuicTime::Delta::Zero(), ack.ack_frame->ack_delay_time); + EXPECT_EQ(1u, ack.ack_frame->received_packet_times.size()); + + QuicTime four_ms = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(4); + ack = manager_->GetUpdatedAckFrame(four_ms); + manager_->ResetAckStates(); + EXPECT_FALSE(manager_->AckFrameUpdated()); + // When UpdateReceivedPacketInfo after not having received a new packet, + // the delta should still be accurate. + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(2), + ack.ack_frame->ack_delay_time); + // And received packet times won't have change. + EXPECT_EQ(1u, ack.ack_frame->received_packet_times.size()); + + header.packet_number = QuicPacketNumber(999u); + manager_->RecordPacketReceived(header, two_ms); + header.packet_number = QuicPacketNumber(4u); + manager_->RecordPacketReceived(header, two_ms); + header.packet_number = QuicPacketNumber(1000u); + manager_->RecordPacketReceived(header, two_ms); + EXPECT_TRUE(manager_->AckFrameUpdated()); + ack = manager_->GetUpdatedAckFrame(two_ms); + manager_->ResetAckStates(); + EXPECT_FALSE(manager_->AckFrameUpdated()); + // UpdateReceivedPacketInfo should discard any times which can't be + // expressed on the wire. + EXPECT_EQ(2u, ack.ack_frame->received_packet_times.size()); +} + +TEST_F(UberReceivedPacketManagerTest, UpdateReceivedConnectionStats) { + EXPECT_FALSE(manager_->AckFrameUpdated()); + RecordPacketReceipt(1); + EXPECT_TRUE(manager_->AckFrameUpdated()); + RecordPacketReceipt(6); + RecordPacketReceipt(2, + QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1)); + + EXPECT_EQ(4u, stats_.max_sequence_reordering); + EXPECT_EQ(1000, stats_.max_time_reordering_us); + EXPECT_EQ(1u, stats_.packets_reordered); +} + +TEST_F(UberReceivedPacketManagerTest, LimitAckRanges) { + manager_->set_max_ack_ranges(10); + EXPECT_FALSE(manager_->AckFrameUpdated()); + for (int i = 0; i < 100; ++i) { + RecordPacketReceipt(1 + 2 * i); + EXPECT_TRUE(manager_->AckFrameUpdated()); + manager_->GetUpdatedAckFrame(QuicTime::Zero()); + EXPECT_GE(10u, manager_->ack_frame().packets.NumIntervals()); + EXPECT_EQ(QuicPacketNumber(1u + 2 * i), + manager_->ack_frame().packets.Max()); + for (int j = 0; j < std::min(10, i + 1); ++j) { + ASSERT_GE(i, j); + EXPECT_TRUE(manager_->ack_frame().packets.Contains( + QuicPacketNumber(1 + (i - j) * 2))); + if (i > j) { + EXPECT_FALSE(manager_->ack_frame().packets.Contains( + QuicPacketNumber((i - j) * 2))); + } + } + } +} + +TEST_F(UberReceivedPacketManagerTest, IgnoreOutOfOrderTimestamps) { + EXPECT_FALSE(manager_->AckFrameUpdated()); + RecordPacketReceipt(1, QuicTime::Zero()); + EXPECT_TRUE(manager_->AckFrameUpdated()); + EXPECT_EQ(1u, manager_->ack_frame().received_packet_times.size()); + RecordPacketReceipt(2, + QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1)); + EXPECT_EQ(2u, manager_->ack_frame().received_packet_times.size()); + RecordPacketReceipt(3, QuicTime::Zero()); + EXPECT_EQ(2u, manager_->ack_frame().received_packet_times.size()); +} + +TEST_F(UberReceivedPacketManagerTest, OutOfOrderReceiptCausesAckSent) { + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(3, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 3); + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + // Delayed ack is scheduled. + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } else { + // Should ack immediately since we have missing packets. + CheckAckTimeout(clock_.ApproximateNow()); + } + + RecordPacketReceipt(2, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 2); + CheckAckTimeout(clock_.ApproximateNow()); + + RecordPacketReceipt(1, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 1); + // Should ack immediately, since this fills the last hole. + CheckAckTimeout(clock_.ApproximateNow()); + + RecordPacketReceipt(4, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 4); + // Delayed ack is scheduled. + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); +} + +TEST_F(UberReceivedPacketManagerTest, OutOfOrderAckReceiptCausesNoAck) { + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(2, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(!kInstigateAck, 2); + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(1, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(!kInstigateAck, 1); + EXPECT_FALSE(HasPendingAck()); +} + +TEST_F(UberReceivedPacketManagerTest, AckReceiptCausesAckSend) { + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(1, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(!kInstigateAck, 1); + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(2, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(!kInstigateAck, 2); + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(3, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 3); + // Delayed ack is scheduled. + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + clock_.AdvanceTime(kDelayedAckTime); + CheckAckTimeout(clock_.ApproximateNow()); + + RecordPacketReceipt(4, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(!kInstigateAck, 4); + EXPECT_FALSE(HasPendingAck()); + + RecordPacketReceipt(5, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(!kInstigateAck, 5); + EXPECT_FALSE(HasPendingAck()); +} + +TEST_F(UberReceivedPacketManagerTest, AckSentEveryNthPacket) { + EXPECT_FALSE(HasPendingAck()); + manager_->set_ack_frequency_before_ack_decimation(3); + + // Receives packets 1 - 39. + for (size_t i = 1; i <= 39; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 3 == 0) { + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } +} + +TEST_F(UberReceivedPacketManagerTest, AckDecimationReducesAcks) { + EXPECT_FALSE(HasPendingAck()); + UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), + ACK_DECIMATION_WITH_REORDERING); + + // Start ack decimation from 10th packet. + manager_->set_min_received_before_ack_decimation(10); + + // Receives packets 1 - 29. + for (size_t i = 1; i <= 29; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i <= 10) { + // For packets 1-10, ack every 2 packets. + if (i % 2 == 0) { + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + continue; + } + // ack at 20. + if (i == 20) { + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kMinRttMs * 0.25); + } + } + + // We now receive the 30th packet, and so we send an ack. + RecordPacketReceipt(30, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 30); + CheckAckTimeout(clock_.ApproximateNow()); +} + +TEST_F(UberReceivedPacketManagerTest, SendDelayedAfterQuiescence) { + EXPECT_FALSE(HasPendingAck()); + UberReceivedPacketManagerPeer::SetFastAckAfterQuiescence(manager_.get(), + true); + // The beginning of the connection counts as quiescence. + QuicTime ack_time = + clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); + + RecordPacketReceipt(1, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 1); + CheckAckTimeout(ack_time); + // Simulate delayed ack alarm firing. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + CheckAckTimeout(clock_.ApproximateNow()); + + // Process another packet immediately after sending the ack and expect the + // ack timeout to be set delayed ack time in the future. + ack_time = clock_.ApproximateNow() + kDelayedAckTime; + RecordPacketReceipt(2, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 2); + CheckAckTimeout(ack_time); + // Simulate delayed ack alarm firing. + clock_.AdvanceTime(kDelayedAckTime); + CheckAckTimeout(clock_.ApproximateNow()); + + // Wait 1 second and enesure the ack timeout is set to 1ms in the future. + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); + ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); + RecordPacketReceipt(3, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 3); + CheckAckTimeout(ack_time); +} + +TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimation) { + EXPECT_FALSE(HasPendingAck()); + UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), ACK_DECIMATION); + // The ack time should be based on min_rtt * 1/4, since it's less than the + // default delayed ack time. + QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; + + // Process all the packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (uint64_t i = 1; i < 10; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); + } + CheckAckTimeout(clock_.ApproximateNow()); +} + +TEST_F(UberReceivedPacketManagerTest, + SendDelayedAckAckDecimationAfterQuiescence) { + EXPECT_FALSE(HasPendingAck()); + UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), ACK_DECIMATION); + UberReceivedPacketManagerPeer::SetFastAckAfterQuiescence(manager_.get(), + true); + // The beginning of the connection counts as quiescence. + QuicTime ack_time = + clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); + RecordPacketReceipt(1, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 1); + CheckAckTimeout(ack_time); + // Simulate delayed ack alarm firing. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + CheckAckTimeout(clock_.ApproximateNow()); + + // Process another packet immedately after sending the ack and expect the + // ack timeout to be set delayed ack time in the future. + ack_time = clock_.ApproximateNow() + kDelayedAckTime; + RecordPacketReceipt(2, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 2); + CheckAckTimeout(ack_time); + // Simulate delayed ack alarm firing. + clock_.AdvanceTime(kDelayedAckTime); + CheckAckTimeout(clock_.ApproximateNow()); + + // Wait 1 second and enesure the ack timeout is set to 1ms in the future. + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); + ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); + RecordPacketReceipt(3, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 3); + CheckAckTimeout(ack_time); + // Process enough packets to get into ack decimation behavior. + // The ack time should be based on min_rtt/4, since it's less than the + // default delayed ack time. + ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 4; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + EXPECT_FALSE(HasPendingAck()); + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (uint64_t i = 1; i < 10; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); + } + CheckAckTimeout(clock_.ApproximateNow()); + + // Wait 1 second and enesure the ack timeout is set to 1ms in the future. + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); + ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); + RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10); + CheckAckTimeout(ack_time); +} + +TEST_F(UberReceivedPacketManagerTest, + SendDelayedAckDecimationUnlimitedAggregation) { + EXPECT_FALSE(HasPendingAck()); + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(kACKD); + // No limit on the number of packets received before sending an ack. + connection_options.push_back(kAKDU); + config.SetConnectionOptionsToSend(connection_options); + manager_->SetFromConfig(config, Perspective::IS_CLIENT); + + // The ack time should be based on min_rtt/4, since it's less than the + // default delayed ack time. + QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; + + // Process all the initial packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + // 18 packets will not cause an ack to be sent. 19 will because when + // stop waiting frames are in use, we ack every 20 packets no matter what. + for (int i = 1; i <= 18; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); + } + CheckAckTimeout(ack_time); +} + +TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimationEighthRtt) { + EXPECT_FALSE(HasPendingAck()); + UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), ACK_DECIMATION); + UberReceivedPacketManagerPeer::SetAckDecimationDelay(manager_.get(), 0.125); + + // The ack time should be based on min_rtt/8, since it's less than the + // default delayed ack time. + QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; + + // Process all the packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (uint64_t i = 1; i < 10; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); + } + CheckAckTimeout(clock_.ApproximateNow()); +} + +TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimationWithReordering) { + EXPECT_FALSE(HasPendingAck()); + UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), + ACK_DECIMATION_WITH_REORDERING); + + // The ack time should be based on min_rtt/4, since it's less than the + // default delayed ack time. + QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; + // Process all the packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + // Receive one packet out of order and then the rest in order. + // The loop leaves a one packet gap between acks sent to simulate some loss. + for (int j = 0; j < 3; ++j) { + // Process packet 10 first and ensure the timeout is one eighth min_rtt. + RecordPacketReceipt(kFirstDecimatedPacket + 9 + (j * 11), + clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9 + (j * 11)); + ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (int i = 0; i < 9; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i + (j * 11), + clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, + kFirstDecimatedPacket + i + (j * 11)); + } + CheckAckTimeout(clock_.ApproximateNow()); + } +} + +TEST_F(UberReceivedPacketManagerTest, + SendDelayedAckDecimationWithLargeReordering) { + EXPECT_FALSE(HasPendingAck()); + UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), + ACK_DECIMATION_WITH_REORDERING); + // The ack time should be based on min_rtt/4, since it's less than the + // default delayed ack time. + QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; + + // Process all the packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19); + ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (int i = 1; i < 9; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); + } + CheckAckTimeout(clock_.ApproximateNow()); + + // The next packet received in order will cause an immediate ack, because it + // fills a hole. + RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10); + CheckAckTimeout(clock_.ApproximateNow()); +} + +TEST_F(UberReceivedPacketManagerTest, + SendDelayedAckDecimationWithReorderingEighthRtt) { + EXPECT_FALSE(HasPendingAck()); + UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), + ACK_DECIMATION_WITH_REORDERING); + UberReceivedPacketManagerPeer::SetAckDecimationDelay(manager_.get(), 0.125); + // The ack time should be based on min_rtt/8, since it's less than the + // default delayed ack time. + QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; + + // Process all the packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + // Process packet 10 first and ensure the timeout is one eighth min_rtt. + RecordPacketReceipt(kFirstDecimatedPacket + 9, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9); + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (int i = 1; i < 9; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck + i, kFirstDecimatedPacket); + } + CheckAckTimeout(clock_.ApproximateNow()); +} + +TEST_F(UberReceivedPacketManagerTest, + SendDelayedAckDecimationWithLargeReorderingEighthRtt) { + EXPECT_FALSE(HasPendingAck()); + UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), + ACK_DECIMATION_WITH_REORDERING); + UberReceivedPacketManagerPeer::SetAckDecimationDelay(manager_.get(), 0.125); + + // The ack time should be based on min_rtt/8, since it's less than the + // default delayed ack time. + QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; + // Process all the packets in order so there aren't missing packets. + uint64_t kFirstDecimatedPacket = 101; + for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + RecordPacketReceipt(i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, i); + if (i % 2 == 0) { + // Ack every 2 packets by default. + CheckAckTimeout(clock_.ApproximateNow()); + } else { + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + } + } + + RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); + CheckAckTimeout(ack_time); + + RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19); + CheckAckTimeout(ack_time); + + // The 10th received packet causes an ack to be sent. + for (int i = 1; i < 9; ++i) { + RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); + } + CheckAckTimeout(clock_.ApproximateNow()); + + // The next packet received in order will cause an immediate ack, because it + // fills a hole. + RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10); + CheckAckTimeout(clock_.ApproximateNow()); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/test_tools/quic_connection_peer.cc b/quic/test_tools/quic_connection_peer.cc index 953e495..22d2880 100644 --- a/quic/test_tools/quic_connection_peer.cc +++ b/quic/test_tools/quic_connection_peer.cc
@@ -39,7 +39,12 @@ QuicConnection* connection) { const bool ack_frame_updated = connection->ack_frame_updated(); const QuicFrame ack_frame = connection->GetUpdatedAckFrame(); - connection->received_packet_manager_.ack_frame_updated_ = ack_frame_updated; + if (connection->use_uber_received_packet_manager_) { + connection->uber_received_packet_manager_.received_packet_manager_ + .ack_frame_updated_ = ack_frame_updated; + } else { + connection->received_packet_manager_.ack_frame_updated_ = ack_frame_updated; + } return ack_frame; } @@ -259,7 +264,12 @@ void QuicConnectionPeer::SetAckMode(QuicConnection* connection, AckMode ack_mode) { if (connection->received_packet_manager_.decide_when_to_send_acks()) { - connection->received_packet_manager_.ack_mode_ = ack_mode; + if (connection->use_uber_received_packet_manager_) { + connection->uber_received_packet_manager_.received_packet_manager_ + .ack_mode_ = ack_mode; + } else { + connection->received_packet_manager_.ack_mode_ = ack_mode; + } } else { connection->ack_mode_ = ack_mode; } @@ -270,8 +280,13 @@ QuicConnection* connection, bool fast_ack_after_quiescence) { if (connection->received_packet_manager_.decide_when_to_send_acks()) { - connection->received_packet_manager_.fast_ack_after_quiescence_ = - fast_ack_after_quiescence; + if (connection->use_uber_received_packet_manager_) { + connection->uber_received_packet_manager_.received_packet_manager_ + .fast_ack_after_quiescence_ = fast_ack_after_quiescence; + } else { + connection->received_packet_manager_.fast_ack_after_quiescence_ = + fast_ack_after_quiescence; + } } else { connection->fast_ack_after_quiescence_ = fast_ack_after_quiescence; } @@ -281,8 +296,13 @@ void QuicConnectionPeer::SetAckDecimationDelay(QuicConnection* connection, float ack_decimation_delay) { if (connection->received_packet_manager_.decide_when_to_send_acks()) { - connection->received_packet_manager_.ack_decimation_delay_ = - ack_decimation_delay; + if (connection->use_uber_received_packet_manager_) { + connection->uber_received_packet_manager_.received_packet_manager_ + .ack_decimation_delay_ = ack_decimation_delay; + } else { + connection->received_packet_manager_.ack_decimation_delay_ = + ack_decimation_delay; + } } else { connection->ack_decimation_delay_ = ack_decimation_delay; }
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h index 965082b..f61bd25 100644 --- a/quic/test_tools/quic_test_utils.h +++ b/quic/test_tools/quic_test_utils.h
@@ -1040,7 +1040,7 @@ MOCK_METHOD2(RecordPacketReceived, void(const QuicPacketHeader& header, QuicTime receipt_time)); MOCK_METHOD1(IsMissing, bool(QuicPacketNumber packet_number)); - MOCK_METHOD1(IsAwaitingPacket, bool(QuicPacketNumber packet_number)); + MOCK_CONST_METHOD1(IsAwaitingPacket, bool(QuicPacketNumber packet_number)); MOCK_METHOD1(UpdatePacketInformationSentByPeer, void(const QuicStopWaitingFrame& stop_waiting)); MOCK_CONST_METHOD0(HasNewMissingPackets, bool(void));