gfe-relnote: Send QUIC connection close packets at all available encryption levels.
PiperOrigin-RevId: 275164869
Change-Id: I0a75e528218a6526dbeef2d44df5cf0cb332094e
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 079e14d..7916791 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -2832,13 +2832,13 @@
void QuicConnection::QueueUndecryptablePacket(
const QuicEncryptedPacket& packet) {
- for (const auto& saved_packet : undecryptable_packets_) {
- if (packet.data() == saved_packet->data() &&
- packet.length() == saved_packet->length()) {
- QUIC_DVLOG(1) << ENDPOINT << "Not queueing known undecryptable packet";
- return;
- }
+ for (const auto& saved_packet : undecryptable_packets_) {
+ if (packet.data() == saved_packet->data() &&
+ packet.length() == saved_packet->length()) {
+ QUIC_DVLOG(1) << ENDPOINT << "Not queueing known undecryptable packet";
+ return;
}
+ }
QUIC_DVLOG(1) << ENDPOINT << "Queueing undecryptable packet.";
undecryptable_packets_.push_back(packet.Clone());
}
@@ -2942,25 +2942,58 @@
void QuicConnection::SendConnectionClosePacket(QuicErrorCode error,
const std::string& details) {
- QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet.";
- SetDefaultEncryptionLevel(GetConnectionCloseEncryptionLevel());
- ClearQueuedPackets();
- // If there was a packet write error, write the smallest close possible.
- ScopedPacketFlusher flusher(this);
- // When multiple packet number spaces is supported, an ACK frame will be
- // bundled when connection is not write blocked.
- if (!SupportsMultiplePacketNumberSpaces() &&
- error != QUIC_PACKET_WRITE_ERROR &&
- !GetUpdatedAckFrame().ack_frame->packets.Empty()) {
- SendAck();
- }
- QuicConnectionCloseFrame* frame;
+ if (!GetQuicReloadableFlag(quic_close_all_encryptions_levels)) {
+ QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet.";
+ SetDefaultEncryptionLevel(GetConnectionCloseEncryptionLevel());
+ ClearQueuedPackets();
+ // If there was a packet write error, write the smallest close possible.
+ ScopedPacketFlusher flusher(this);
+ // When multiple packet number spaces is supported, an ACK frame will be
+ // bundled when connection is not write blocked.
+ if (!SupportsMultiplePacketNumberSpaces() &&
+ error != QUIC_PACKET_WRITE_ERROR &&
+ !GetUpdatedAckFrame().ack_frame->packets.Empty()) {
+ SendAck();
+ }
+ QuicConnectionCloseFrame* frame;
- frame = new QuicConnectionCloseFrame(transport_version(), error, details,
- framer_.current_received_frame_type());
- packet_generator_.ConsumeRetransmittableControlFrame(QuicFrame(frame));
- packet_generator_.FlushAllQueuedFrames();
- ClearQueuedPackets();
+ frame = new QuicConnectionCloseFrame(transport_version(), error, details,
+ framer_.current_received_frame_type());
+ packet_generator_.ConsumeRetransmittableControlFrame(QuicFrame(frame));
+ packet_generator_.FlushAllQueuedFrames();
+ ClearQueuedPackets();
+ return;
+ }
+ const EncryptionLevel current_encryption_level = encryption_level_;
+ ScopedPacketFlusher flusher(this);
+ QUIC_RELOADABLE_FLAG_COUNT(quic_close_all_encryptions_levels);
+ for (EncryptionLevel level :
+ {ENCRYPTION_INITIAL, ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT,
+ ENCRYPTION_FORWARD_SECURE}) {
+ if (!framer_.HasEncrypterOfEncryptionLevel(level)) {
+ continue;
+ }
+ QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet at level: "
+ << EncryptionLevelToString(level);
+ SetDefaultEncryptionLevel(level);
+ ClearQueuedPackets();
+ // If there was a packet write error, write the smallest close possible.
+ // When multiple packet number spaces are supported, an ACK frame will
+ // be bundled by the ScopedPacketFlusher. Otherwise, an ACK must be sent
+ // explicitly.
+ if (!SupportsMultiplePacketNumberSpaces() &&
+ error != QUIC_PACKET_WRITE_ERROR &&
+ !GetUpdatedAckFrame().ack_frame->packets.Empty()) {
+ SendAck();
+ }
+ auto* frame =
+ new QuicConnectionCloseFrame(transport_version(), error, details,
+ framer_.current_received_frame_type());
+ packet_generator_.ConsumeRetransmittableControlFrame(QuicFrame(frame));
+ packet_generator_.FlushAllQueuedFrames();
+ ClearQueuedPackets();
+ }
+ SetDefaultEncryptionLevel(current_encryption_level);
}
void QuicConnection::TearDownLocalConnectionState(
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 20f63f7..d73865c 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -2053,8 +2053,9 @@
// Regression test for b/74073386.
{
InSequence seq;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .Times(AtLeast(1));
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(AtLeast(1));
}
set_perspective(Perspective::IS_CLIENT);
@@ -2852,9 +2853,11 @@
// one. This should cause a connection error.
QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 7);
if (!GetParam().no_stop_waiting) {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .Times(AtLeast(1));
EXPECT_CALL(visitor_,
- OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
+ OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF))
+ .Times(AtLeast(1));
}
ProcessStopWaitingPacket(InitStopWaitingFrame(1));
if (!GetParam().no_stop_waiting) {
@@ -2907,7 +2910,7 @@
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
QuicAckFrame frame = InitAckFrame(1);
EXPECT_CALL(visitor_, OnCanWrite()).Times(0);
ProcessAckPacket(&frame);
@@ -5473,7 +5476,7 @@
// This time, we should time out.
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
clock_.AdvanceTime(five_ms);
EXPECT_EQ(default_timeout + five_ms, clock_.ApproximateNow());
connection_.GetTimeoutAlarm()->Fire();
@@ -5551,7 +5554,7 @@
// This time, we should time out.
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
clock_.AdvanceTime(final_timeout - clock_.Now());
EXPECT_EQ(connection_.GetTimeoutAlarm()->deadline(), clock_.Now());
EXPECT_EQ(final_timeout, clock_.Now());
@@ -5686,7 +5689,7 @@
// This time, we should time out and send a connection close due to the TLP.
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
clock_.AdvanceTime(connection_.GetTimeoutAlarm()->deadline() -
clock_.ApproximateNow() + five_ms);
connection_.GetTimeoutAlarm()->Fire();
@@ -5741,7 +5744,7 @@
// This time, we should time out and send a connection close due to the TLP.
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
clock_.AdvanceTime(connection_.GetTimeoutAlarm()->deadline() -
clock_.ApproximateNow() + five_ms);
connection_.GetTimeoutAlarm()->Fire();
@@ -5792,7 +5795,7 @@
// This time, we should time out.
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
clock_.AdvanceTime(five_ms);
EXPECT_EQ(default_timeout + five_ms, clock_.ApproximateNow());
connection_.GetTimeoutAlarm()->Fire();
@@ -5895,7 +5898,7 @@
// This time, we should time out.
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
connection_.GetRetransmissionAlarm()->Fire();
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_FALSE(connection_.connected());
@@ -7407,7 +7410,7 @@
EXPECT_EQ(1u, writer_->packets_write_attempts());
TriggerConnectionClose();
- EXPECT_EQ(2u, writer_->packets_write_attempts());
+ EXPECT_LE(2u, writer_->packets_write_attempts());
}
TEST_P(QuicConnectionTest, ConnectionCloseGettingWriteBlocked) {
@@ -8813,6 +8816,8 @@
use_tagging_decrypter();
connection_.SetEncrypter(ENCRYPTION_INITIAL,
std::make_unique<TaggingEncrypter>(0x01));
+ connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<TaggingEncrypter>(0x01));
connection_.SendCryptoStreamData();
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -8834,7 +8839,7 @@
InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(4)}});
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
ProcessFramePacketAtLevel(300, QuicFrame(&invalid_ack), ENCRYPTION_INITIAL);
TestConnectionCloseQuicErrorCode(QUIC_INVALID_ACK_DATA);
}
@@ -9317,7 +9322,7 @@
0, FIN, nullptr);
// 5PTO + 1 connection close.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(6));
// Fire the retransmission alarm 5 times.
for (int i = 0; i < 5; ++i) {
@@ -9371,7 +9376,7 @@
// Closes connection on 7th PTO.
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
connection_.GetRetransmissionAlarm()->Fire();
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_FALSE(connection_.connected());
@@ -9411,7 +9416,7 @@
// Closes connection on 8th PTO.
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
connection_.GetRetransmissionAlarm()->Fire();
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_FALSE(connection_.connected());