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());