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.