gfe-relnote: In QUIC, consider packets (which cannot be sent because of write blocked) as sent from unacked_packet_map and congestion control's perspectives. Protected by gfe2_reloadable_flag_quic_treat_queued_packets_as_sent.
PiperOrigin-RevId: 272424245
Change-Id: I83d54860464e3d6b6169475de90fa74904cc5438
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 1828a63..ce1e6c4 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -326,7 +326,9 @@
bytes_received_before_address_validation_(0),
bytes_sent_before_address_validation_(0),
address_validated_(false),
- skip_packet_number_for_pto_(false) {
+ skip_packet_number_for_pto_(false),
+ treat_queued_packets_as_sent_(
+ GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
QUIC_DLOG(INFO) << ENDPOINT << "Created connection with server connection ID "
<< server_connection_id
<< " and version: " << ParsedQuicVersionToString(version());
@@ -389,10 +391,13 @@
for (auto it = queued_packets_.begin(); it != queued_packets_.end(); ++it) {
// Delete the buffer before calling ClearSerializedPacket, which sets
// encrypted_buffer to nullptr.
+ DCHECK(!treat_queued_packets_as_sent_);
delete[] it->encrypted_buffer;
ClearSerializedPacket(&(*it));
}
queued_packets_.clear();
+
+ buffered_packets_.clear();
}
void QuicConnection::SetFromConfig(const QuicConfig& config) {
@@ -2019,6 +2024,7 @@
QUIC_CLIENT_HISTOGRAM_COUNTS("QuicSession.NumQueuedPacketsBeforeWrite",
queued_packets_.size(), 1, 1000, 50, "");
while (!queued_packets_.empty()) {
+ DCHECK(!treat_queued_packets_as_sent_);
// WritePacket() can potentially clear all queued packets, so we need to
// save the first queued packet to a local variable before calling it.
SerializedPacket packet(std::move(queued_packets_.front()));
@@ -2043,6 +2049,30 @@
// Continue to send the next packet in queue.
}
+
+ while (!buffered_packets_.empty()) {
+ DCHECK(treat_queued_packets_as_sent_);
+ if (HandleWriteBlocked()) {
+ break;
+ }
+ const BufferedPacket& packet = buffered_packets_.front();
+ WriteResult result = writer_->WritePacket(
+ packet.encrypted_buffer.data(), packet.encrypted_buffer.length(),
+ packet.self_address.host(), packet.peer_address, per_packet_options_);
+ QUIC_DVLOG(1) << ENDPOINT << "Sending buffered packet, result: " << result;
+ if (IsWriteError(result.status)) {
+ OnWriteError(result.error_code);
+ break;
+ }
+ if (result.status == WRITE_STATUS_OK ||
+ result.status == WRITE_STATUS_BLOCKED_DATA_BUFFERED) {
+ buffered_packets_.pop_front();
+ }
+ if (IsWriteBlockedStatus(result.status)) {
+ visitor_->OnWriteBlocked();
+ break;
+ }
+ }
}
void QuicConnection::WritePendingRetransmissions() {
@@ -2210,9 +2240,11 @@
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return true;
}
+ SerializedPacketFate fate = DeterminePacketFate();
// Termination packets are encrypted and saved, so don't exit early.
const bool is_termination_packet = IsTerminationPacket(*packet);
- if (HandleWriteBlocked() && !is_termination_packet) {
+ if (!treat_queued_packets_as_sent_ && HandleWriteBlocked() &&
+ !is_termination_packet) {
return false;
}
@@ -2232,7 +2264,7 @@
new QuicEncryptedPacket(buffer_copy, encrypted_length, true));
// This assures we won't try to write *forced* packets when blocked.
// Return true to stop processing.
- if (HandleWriteBlocked()) {
+ if (!treat_queued_packets_as_sent_ && HandleWriteBlocked()) {
return true;
}
}
@@ -2265,9 +2297,26 @@
}
per_packet_options_->release_time_delay = release_time_delay;
}
- WriteResult result = writer_->WritePacket(
- packet->encrypted_buffer, encrypted_length, self_address().host(),
- peer_address(), per_packet_options_);
+ WriteResult result(WRITE_STATUS_OK, encrypted_length);
+ switch (fate) {
+ case COALESCE:
+ DCHECK(false);
+ break;
+ case BUFFER:
+ DCHECK(treat_queued_packets_as_sent_);
+ QUIC_DVLOG(1) << ENDPOINT << "Adding packet: " << packet->packet_number
+ << " to buffered packets";
+ buffered_packets_.emplace_back(*packet, self_address(), peer_address());
+ break;
+ case SEND_TO_WRITER:
+ result = writer_->WritePacket(packet->encrypted_buffer, encrypted_length,
+ self_address().host(), peer_address(),
+ per_packet_options_);
+ break;
+ default:
+ DCHECK(false);
+ break;
+ }
QUIC_HISTOGRAM_ENUM(
"QuicConnection.WritePacketStatus", result.status,
@@ -2284,7 +2333,13 @@
// duplicate packet being sent. The helper must call OnCanWrite
// when the write completes, and OnWriteError if an error occurs.
if (result.status != WRITE_STATUS_BLOCKED_DATA_BUFFERED) {
- return false;
+ if (treat_queued_packets_as_sent_) {
+ QUIC_DVLOG(1) << ENDPOINT << "Adding packet: " << packet->packet_number
+ << " to buffered packets";
+ buffered_packets_.emplace_back(*packet, self_address(), peer_address());
+ } else {
+ return false;
+ }
}
}
@@ -2535,10 +2590,12 @@
// If there are already queued packets, queue this one immediately to ensure
// it's written in sequence number order.
if (!queued_packets_.empty() || !WritePacket(packet)) {
- // Take ownership of the underlying encrypted packet.
- packet->encrypted_buffer = CopyBuffer(*packet);
- queued_packets_.push_back(*packet);
- packet->retransmittable_frames.clear();
+ if (!treat_queued_packets_as_sent_) {
+ // Take ownership of the underlying encrypted packet.
+ packet->encrypted_buffer = CopyBuffer(*packet);
+ queued_packets_.push_back(*packet);
+ packet->retransmittable_frames.clear();
+ }
}
ClearSerializedPacket(packet);
@@ -2955,13 +3012,14 @@
bool QuicConnection::HasQueuedData() const {
return pending_version_negotiation_packet_ || !queued_packets_.empty() ||
- packet_generator_.HasPendingFrames();
+ packet_generator_.HasPendingFrames() || !buffered_packets_.empty();
}
bool QuicConnection::CanWriteStreamData() {
// Don't write stream data if there are negotiation or queued data packets
// to send. Otherwise, continue and bundle as many frames as possible.
- if (pending_version_negotiation_packet_ || !queued_packets_.empty()) {
+ if (pending_version_negotiation_packet_ || !queued_packets_.empty() ||
+ !buffered_packets_.empty()) {
return false;
}
@@ -3225,6 +3283,18 @@
!connection_->packet_generator_.PacketFlusherAttached());
}
+QuicConnection::BufferedPacket::BufferedPacket(
+ const SerializedPacket& packet,
+ const QuicSocketAddress& self_address,
+ const QuicSocketAddress& peer_address)
+ : encrypted_buffer(CopyBuffer(packet), packet.encrypted_length),
+ self_address(self_address),
+ peer_address(peer_address) {}
+
+QuicConnection::BufferedPacket::~BufferedPacket() {
+ delete[] encrypted_buffer.data();
+}
+
HasRetransmittableData QuicConnection::IsRetransmittable(
const SerializedPacket& packet) {
// Retransmitted packets retransmittable frames are owned by the unacked
@@ -3543,7 +3613,7 @@
}
bool application_limited =
- queued_packets_.empty() &&
+ queued_packets_.empty() && buffered_packets_.empty() &&
!sent_packet_manager_.HasPendingRetransmissions() &&
!visitor_->WillingAndAbleToWrite();
@@ -3885,6 +3955,14 @@
bytes_received_before_address_validation_;
}
+QuicConnection::SerializedPacketFate QuicConnection::DeterminePacketFate() {
+ if (treat_queued_packets_as_sent_ &&
+ (!buffered_packets_.empty() || HandleWriteBlocked())) {
+ return BUFFER;
+ }
+ return SEND_TO_WRITER;
+}
+
size_t QuicConnection::min_received_before_ack_decimation() const {
return uber_received_packet_manager_.min_received_before_ack_decimation();
}
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index 399ba13..bb4464b 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -623,7 +623,12 @@
}
// Testing only.
- size_t NumQueuedPackets() const { return queued_packets_.size(); }
+ size_t NumQueuedPackets() const {
+ if (treat_queued_packets_as_sent_) {
+ return buffered_packets_.size();
+ }
+ return queued_packets_.size();
+ }
// Returns true if the underlying UDP socket is writable, there is
// no queued data and the connection is not congestion-control
@@ -994,6 +999,33 @@
typedef std::list<SerializedPacket> QueuedPacketList;
+ // Indicates the fate of a serialized packet in WritePacket().
+ enum SerializedPacketFate : uint8_t {
+ COALESCE, // Try to coalesce packet.
+ BUFFER, // Buffer packet in buffered_packets_.
+ SEND_TO_WRITER, // Send packet to writer.
+ };
+
+ // BufferedPacket stores necessary information (encrypted buffer and self/peer
+ // addresses) of those packets which are serialized but failed to send because
+ // socket is blocked. From unacked packet map and send algorithm's
+ // perspective, buffered packets are treated as sent.
+ struct BufferedPacket {
+ BufferedPacket(const SerializedPacket& packet,
+ const QuicSocketAddress& self_address,
+ const QuicSocketAddress& peer_address);
+ BufferedPacket(const BufferedPacket& other) = delete;
+ BufferedPacket(const BufferedPacket&& other) = delete;
+
+ ~BufferedPacket();
+
+ // encrypted_buffer is owned by buffered packet.
+ QuicStringPiece encrypted_buffer;
+ // Self and peer addresses when the packet is serialized.
+ const QuicSocketAddress self_address;
+ const QuicSocketAddress peer_address;
+ };
+
// Notifies the visitor of the close and marks the connection as disconnected.
// Does not send a connection close frame to the peer. It should only be
// called by CloseConnection or OnConnectionCloseFrame, OnPublicResetPacket,
@@ -1142,6 +1174,9 @@
// and flags.
void MaybeEnableMultiplePacketNumberSpacesSupport();
+ // Returns packet fate when trying to write a packet.
+ SerializedPacketFate DeterminePacketFate();
+
// Returns the encryption level the connection close packet should be sent at,
// which is the highest encryption level that peer can guarantee to process.
EncryptionLevel GetConnectionCloseEncryptionLevel() const;
@@ -1272,6 +1307,8 @@
// unacked_packets_ if they are to be retransmitted. Packets encrypted_buffer
// fields are owned by the QueuedPacketList, in order to ensure they outlast
// the original scope of the SerializedPacket.
+ // TODO(fayang): Remove this when deprecating
+ // quic_treat_queued_packets_as_sent.
QueuedPacketList queued_packets_;
// Contains the connection close packets if the connection has been closed.
@@ -1494,6 +1531,16 @@
// If true, skip packet number before sending the last PTO retransmission.
bool skip_packet_number_for_pto_;
+
+ // Used to store content of packets which cannot be sent because of write
+ // blocked. Packets' encrypted buffers are copied and owned by
+ // buffered_packets_. From unacked_packet_map (and congestion control)'s
+ // perspective, those packets are considered sent. This is only used when
+ // treat_queued_packets_as_sent_ is true.
+ std::list<BufferedPacket> buffered_packets_;
+
+ // Latched value of quic_treat_queued_packets_as_sent.
+ const bool treat_queued_packets_as_sent_;
};
} // namespace quic
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index f65f0cd..9e11494 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -721,7 +721,19 @@
QuicConsumedData SendCryptoStreamData() {
QuicStreamOffset offset = 0;
QuicStringPiece data("chlo");
- return SendCryptoDataWithString(data, offset);
+ if (!QuicVersionUsesCryptoFrames(transport_version())) {
+ return SendCryptoDataWithString(data, offset);
+ }
+ producer_.SaveCryptoData(ENCRYPTION_INITIAL, offset, data);
+ size_t bytes_written;
+ if (notifier_) {
+ bytes_written =
+ notifier_->WriteCryptoData(ENCRYPTION_INITIAL, data.length(), offset);
+ } else {
+ bytes_written = QuicConnection::SendCryptoData(ENCRYPTION_INITIAL,
+ data.length(), offset);
+ }
+ return QuicConsumedData(bytes_written, /*fin_consumed*/ false);
}
QuicConsumedData SendCryptoDataWithString(QuicStringPiece data,
@@ -2015,7 +2027,11 @@
writer_->SetWritable();
connection_.SendConnectivityProbingPacket(writer_.get(),
connection_.peer_address());
-
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0);
+ connection_.OnCanWrite();
+ return;
+ }
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
EXPECT_QUIC_BUG(connection_.OnCanWrite(),
@@ -2046,7 +2062,12 @@
connection_.SendStreamDataWithString(/*id=*/2, "foo", 0, NO_FIN);
EXPECT_FALSE(connection_.connected());
- EXPECT_EQ(1u, connection_.NumQueuedPackets());
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ // No need to buffer packets.
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ } else {
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+ }
EXPECT_EQ(0u, connection_.GetStats().packets_discarded);
connection_.OnCanWrite();
@@ -3355,6 +3376,11 @@
BlockOnNextWrite();
QuicStreamId stream_id = 2;
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
connection_.SendStreamDataWithString(stream_id, "foo", 0, NO_FIN);
// Now that there is a queued packet, reset the stream.
@@ -3362,7 +3388,13 @@
// Unblock the connection and verify that the RST_STREAM is sent and the data
// packet is sent.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(2));
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .Times(AtLeast(1));
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .Times(AtLeast(2));
+ }
writer_->SetWritable();
connection_.OnCanWrite();
if (!connection_.session_decides_what_to_write()) {
@@ -3576,6 +3608,12 @@
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
.WillOnce(SetArgPointee<5>(lost_packets));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _))
+ .Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
ProcessAckPacket(&nack_two);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -3585,10 +3623,15 @@
QuicAckFrame ack_all = InitAckFrame(3);
ProcessAckPacket(&ack_all);
- // Unblock the socket and attempt to send the queued packets. We will always
- // send the retransmission.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _))
- .Times(1);
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _))
+ .Times(0);
+ } else {
+ // Unblock the socket and attempt to send the queued packets. We will always
+ // send the retransmission.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _))
+ .Times(1);
+ }
writer_->SetWritable();
connection_.OnCanWrite();
@@ -3640,6 +3683,19 @@
BlockOnNextWrite();
clock_.AdvanceTime(DefaultRetransmissionTime());
// Only one packet should be retransmitted.
+ if (connection_.session_decides_what_to_write()) {
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
+ } else {
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
+ }
connection_.GetRetransmissionAlarm()->Fire();
EXPECT_TRUE(connection_.HasQueuedData());
@@ -3650,10 +3706,18 @@
// Retransmit already retransmitted packets event though the packet number
// greater than the largest observed.
if (connection_.session_decides_what_to_write()) {
- // 2 RTOs + 1 TLP.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(3);
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ } else {
+ // 2 RTOs + 1 TLP.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(3);
+ }
} else {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ }
}
connection_.GetRetransmissionAlarm()->Fire();
connection_.OnCanWrite();
@@ -3674,20 +3738,39 @@
TEST_P(QuicConnectionTest, WriteBlockedThenSent) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
BlockOnNextWrite();
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
connection_.SendStreamDataWithString(1, "foo", 0, NO_FIN);
- EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+ } else {
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ }
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// The second packet should also be queued, in order to ensure packets are
// never sent out of order.
writer_->SetWritable();
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
connection_.SendStreamDataWithString(1, "foo", 0, NO_FIN);
EXPECT_EQ(2u, connection_.NumQueuedPackets());
// Now both are sent in order when we unblock.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ }
connection_.OnCanWrite();
EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
TEST_P(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) {
@@ -4282,7 +4365,13 @@
// Simulate the retransmission alarm firing and the socket blocking.
BlockOnNextWrite();
clock_.AdvanceTime(DefaultRetransmissionTime());
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Go forward secure.
connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
@@ -4290,6 +4379,7 @@
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
notifier_.NeuterUnencryptedData();
connection_.NeuterUnencryptedPackets();
+ connection_.OnHandshakeComplete();
EXPECT_EQ(QuicTime::Zero(), connection_.GetRetransmissionAlarm()->deadline());
// Unblock the socket and ensure that no packets are sent.
@@ -4429,12 +4519,26 @@
TEST_P(QuicConnectionTest, SetRTOAfterWritingToSocket) {
BlockOnNextWrite();
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
connection_.SendStreamDataWithString(1, "foo", 0, NO_FIN);
- // Make sure that RTO is not started when the packet is queued.
- EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+ } else {
+ // Make sure that RTO is not started when the packet is queued.
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ }
// Test that RTO is started once we write to the socket.
writer_->SetWritable();
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ }
connection_.OnCanWrite();
EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
}
@@ -7803,6 +7907,11 @@
EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(true));
BlockOnNextWrite();
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
connection_.SendStreamData3();
// Now unblock the writer, become congestion control blocked,
@@ -7810,11 +7919,12 @@
writer_->SetWritable();
CongestionBlockWrites();
EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(false));
- {
- InSequence seq;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(1);
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
}
+ EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(1);
connection_.OnCanWrite();
}
@@ -8216,16 +8326,32 @@
TEST_P(QuicConnectionTest, WriteBlockedWithInvalidAck) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(visitor_, OnConnectionClosed(_, _))
- .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame));
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0);
+ } else {
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _))
+ .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame));
+ }
BlockOnNextWrite();
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
connection_.SendStreamDataWithString(5, "foo", 0, FIN);
// This causes connection to be closed because packet 1 has not been sent yet.
QuicAckFrame frame = InitAckFrame(1);
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _));
+ }
ProcessAckPacket(1, &frame);
- EXPECT_EQ(1, connection_close_frame_count_);
- EXPECT_EQ(QUIC_INVALID_ACK_DATA,
- saved_connection_close_frame_.quic_error_code);
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_EQ(0, connection_close_frame_count_);
+ } else {
+ EXPECT_EQ(1, connection_close_frame_count_);
+ EXPECT_EQ(QUIC_INVALID_ACK_DATA,
+ saved_connection_close_frame_.quic_error_code);
+ }
}
TEST_P(QuicConnectionTest, SendMessage) {
@@ -8884,6 +9010,11 @@
EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 3);
+ if (GetQuicReloadableFlag(quic_treat_queued_packets_as_sent)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
// Retransmission timer fires in TLP mode.
connection_.GetRetransmissionAlarm()->Fire();
// Verify one packets is forced flushed when writer is blocked.