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) {