gfe-relnote: In QUIC, add a connection option to close connection after 6 consecutive PTO. Protected by gfe2_reloadable_flag_quic_enable_pto.

PiperOrigin-RevId: 273298757
Change-Id: I877cbaf1941a1229cf466a6bed2826e0fa1e74c3
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index 5f98345..4d5a890 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -186,6 +186,8 @@
 const QuicTag k1PTO = TAG('1', 'P', 'T', 'O');   // Send 1 packet upon PTO.
 const QuicTag k2PTO = TAG('2', 'P', 'T', 'O');   // Send 2 packets upon PTO.
 
+const QuicTag k6PTO = TAG('6', 'P', 'T', 'O');   // Closes connection on 6
+                                                 // consecutive PTOs.
 const QuicTag k7PTO = TAG('7', 'P', 'T', 'O');   // Closes connection on 7
                                                  // consecutive PTOs.
 const QuicTag k8PTO = TAG('8', 'P', 'T', 'O');   // Closes connection on 8
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 9cabfc5..220a17a 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -436,6 +436,10 @@
     close_connection_after_five_rtos_ = true;
   }
   if (sent_packet_manager_.pto_enabled()) {
+    if (config.HasClientSentConnectionOption(k6PTO, perspective_)) {
+      max_consecutive_ptos_ = 5;
+      QUIC_CODE_COUNT(quic_close_connection_6pto);
+    }
     if (config.HasClientSentConnectionOption(k7PTO, perspective_)) {
       max_consecutive_ptos_ = 6;
       QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 3, 4);
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 9e11494..b03efdb 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -9095,6 +9095,48 @@
   EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
 }
 
+TEST_P(QuicConnectionTest, CloseConnectionAfter6ClientPTOs) {
+  if (!connection_.session_decides_what_to_write() ||
+      !GetQuicReloadableFlag(quic_fix_rto_retransmission3)) {
+    return;
+  }
+  SetQuicReloadableFlag(quic_enable_pto, true);
+  QuicConfig config;
+  QuicTagVector connection_options;
+  connection_options.push_back(k1PTO);
+  connection_options.push_back(k6PTO);
+  config.SetConnectionOptionsToSend(connection_options);
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  connection_.SetFromConfig(config);
+  EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+  // Send stream data.
+  SendStreamDataToPeer(
+      GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo",
+      0, FIN, nullptr);
+
+  // 5PTO + 1 connection close.
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6);
+
+  // Fire the retransmission alarm 5 times.
+  for (int i = 0; i < 5; ++i) {
+    connection_.GetRetransmissionAlarm()->Fire();
+    EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+    EXPECT_TRUE(connection_.connected());
+  }
+
+  EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveTlpCount());
+  EXPECT_EQ(0u, connection_.sent_packet_manager().GetConsecutiveRtoCount());
+  EXPECT_EQ(5u, connection_.sent_packet_manager().GetConsecutivePtoCount());
+  // Closes connection on 6th PTO.
+  EXPECT_CALL(visitor_,
+              OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
+  connection_.GetRetransmissionAlarm()->Fire();
+  EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
+  EXPECT_FALSE(connection_.connected());
+  TestConnectionCloseQuicErrorCode(QUIC_TOO_MANY_RTOS);
+}
+
 TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) {
   if (!connection_.session_decides_what_to_write() ||
       !GetQuicReloadableFlag(quic_fix_rto_retransmission3)) {