gfe-relnote: In QUIC, arm PTO from Now() if there is no in flight packet. Affecting client only. Protected by existing gfe2_reloadable_flag_quic_enable_version_draft_25_v3 and gfe2_reloadable_flag_quic_enable_version_draft_27. PiperOrigin-RevId: 308875747 Change-Id: I4fe855baa25131be8ce6c345f592788868a4df7a
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc index f0ee1a7..512632d 100644 --- a/quic/core/quic_sent_packet_manager.cc +++ b/quic/core/quic_sent_packet_manager.cc
@@ -844,8 +844,9 @@ // Find out the packet number space to send probe packets. if (!GetEarliestPacketSentTimeForPto(&packet_number_space) .IsInitialized()) { - QUIC_BUG << "earlist_sent_time not initialized when trying to send PTO " - "retransmissions"; + QUIC_BUG_IF(unacked_packets_.perspective() == Perspective::IS_SERVER) + << "earlist_sent_time not initialized when trying to send PTO " + "retransmissions"; return; } } @@ -1067,8 +1068,12 @@ PacketNumberSpace packet_number_space = NUM_PACKET_NUMBER_SPACES; // earliest_right_edge is the earliest sent time of the last in flight // packet of all packet number spaces. - const QuicTime earliest_right_edge = + QuicTime earliest_right_edge = GetEarliestPacketSentTimeForPto(&packet_number_space); + if (!earliest_right_edge.IsInitialized()) { + // Arm PTO from now if there is no in flight packets. + earliest_right_edge = clock_->ApproximateNow(); + } if (first_pto_srtt_multiplier_ > 0 && packet_number_space == APPLICATION_DATA && consecutive_pto_count_ == 0) {
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc index 7efa8e3..9d62bb6 100644 --- a/quic/core/quic_sent_packet_manager_test.cc +++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -3825,6 +3825,37 @@ manager_.GetRetransmissionTime()); } +TEST_F(QuicSentPacketManagerTest, HandshakeAckCausesInitialKeyDropping) { + manager_.EnableMultiplePacketNumberSpacesSupport(); + QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT); + // Send INITIAL packet 1. + SendDataPacket(1, ENCRYPTION_INITIAL); + QuicTime::Delta expected_pto_delay = + QuicTime::Delta::FromMilliseconds(3 * kInitialRttMs); + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); + // Send HANDSHAKE ack. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + SendAckPacket(2, /*largest_acked=*/1, ENCRYPTION_HANDSHAKE); + // Sending HANDSHAKE packet causes dropping of INITIAL key. + EXPECT_CALL(notifier_, HasUnackedCryptoData()).WillRepeatedly(Return(false)); + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); + manager_.NeuterUnencryptedPackets(); + // There is no in flight packets. + EXPECT_FALSE(manager_.HasInFlightPackets()); + // Verify PTO timer gets rearmed from now because of anti-amplification. + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); + + // Invoke PTO. + clock_.AdvanceTime(expected_pto_delay); + manager_.OnRetransmissionTimeout(); + // Verify nothing to probe (and connection will send PING for current + // encryption level). + EXPECT_CALL(notifier_, RetransmitFrames(_, _)).Times(0); + manager_.MaybeSendProbePackets(); +} + } // namespace } // namespace test } // namespace quic