In quic, do not arm pto timer with no packets in flight if handshake packet gets received by peer. affecting client only. not protected. PiperOrigin-RevId: 321619242 Change-Id: If85c601a6d033d45658546c3b6ac87b8e908367f
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc index 948531a..2848137 100644 --- a/quic/core/quic_sent_packet_manager.cc +++ b/quic/core/quic_sent_packet_manager.cc
@@ -104,6 +104,7 @@ pto_exponential_backoff_start_point_(0), pto_rttvar_multiplier_(4), num_tlp_timeout_ptos_(0), + handshake_packet_acked_(false), one_rtt_packet_acked_(false), one_rtt_packet_sent_(false), first_pto_srtt_multiplier_(0), @@ -1053,12 +1054,7 @@ const QuicTime QuicSentPacketManager::GetRetransmissionTime() const { if (!unacked_packets_.HasInFlightPackets() && - (!handshake_mode_disabled_ || handshake_finished_ || - unacked_packets_.perspective() == Perspective::IS_SERVER)) { - // Do not set the timer if there is nothing in flight. However, to avoid - // handshake deadlock due to anti-amplification limit, client needs to set - // PTO timer when the handshake is not confirmed even there is nothing in - // flight. + PeerCompletedAddressValidation()) { return QuicTime::Zero(); } if (pending_timer_transmission_count_ > 0) { @@ -1417,6 +1413,9 @@ return PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE; } last_ack_frame_.packets.Add(acked_packet.packet_number); + if (info->encryption_level == ENCRYPTION_HANDSHAKE) { + handshake_packet_acked_ = true; + } if (info->encryption_level == ENCRYPTION_FORWARD_SECURE) { one_rtt_packet_acked_ = true; } @@ -1555,5 +1554,16 @@ return total_delay; } +bool QuicSentPacketManager::PeerCompletedAddressValidation() const { + if (unacked_packets_.perspective() == Perspective::IS_SERVER || + !handshake_mode_disabled_) { + return true; + } + + // To avoid handshake deadlock due to anti-amplification limit, client needs + // to set PTO timer until server successfully processed any HANDSHAKE packet. + return handshake_finished_ || handshake_packet_acked_; +} + #undef ENDPOINT // undef for jumbo builds } // namespace quic
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h index 4d76f5c..310cd1a 100644 --- a/quic/core/quic_sent_packet_manager.h +++ b/quic/core/quic_sent_packet_manager.h
@@ -529,6 +529,10 @@ QuicTime::Delta GetNConsecutiveRetransmissionTimeoutDelay( int num_timeouts) const; + // Returns true if peer has finished address validation, such that + // retransmission timer is not armed if there is no packets in flight. + bool PeerCompletedAddressValidation() const; + // Newly serialized retransmittable packets are added to this map, which // contains owning pointers to any contained frames. If a packet is // retransmitted, this map will contain entries for both the old and the new @@ -653,6 +657,9 @@ // Number of PTOs similar to TLPs. size_t num_tlp_timeout_ptos_; + // True if any ENCRYPTION_HANDSHAKE packet gets acknowledged. + bool handshake_packet_acked_; + // True if any 1-RTT packet gets acknowledged. bool one_rtt_packet_acked_;
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc index a6c8338..2ce7529 100644 --- a/quic/core/quic_sent_packet_manager_test.cc +++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -2765,6 +2765,19 @@ // Fire PTO. EXPECT_EQ(QuicSentPacketManager::PTO_MODE, manager_.OnRetransmissionTimeout()); + // Send handshake packet. + SendDataPacket(2, ENCRYPTION_HANDSHAKE); + // Ack packet 2. + ExpectAck(2); + manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3)); + EXPECT_EQ(PACKETS_NEWLY_ACKED, + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2), + ENCRYPTION_HANDSHAKE)); + // Verify retransmission timeout is zero because server has successfully + // processed HANDSHAKE packet. + EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime()); } TEST_F(QuicSentPacketManagerTest, DisableHandshakeModeServer) {