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