For IETF QUIC, do not detect path degrading or blackholing until handshake gets confirmed. (no change to gQUIC)

Protected by FLAGS_quic_reloadable_flag_quic_no_path_degrading_before_handshake_confirmed.

PiperOrigin-RevId: 491689909
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index b16c933..91fc27c 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -6356,6 +6356,15 @@
   if (!connected_) {
     return false;
   }
+  if (GetQuicReloadableFlag(
+          quic_no_path_degrading_before_handshake_confirmed) &&
+      SupportsMultiplePacketNumberSpaces()) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(
+        quic_no_path_degrading_before_handshake_confirmed, 1, 2);
+    // No path degrading detection before handshake confirmed.
+    return perspective_ == Perspective::IS_CLIENT && IsHandshakeConfirmed() &&
+           !is_path_degrading_;
+  }
   // No path degrading detection before handshake completes.
   if (!idle_network_detector_.handshake_timeout().IsInfinite()) {
     return false;
@@ -6396,6 +6405,13 @@
   if (!connected_ || blackhole_detection_disabled_) {
     return false;
   }
+  if (GetQuicReloadableFlag(
+          quic_no_path_degrading_before_handshake_confirmed) &&
+      SupportsMultiplePacketNumberSpaces() && !IsHandshakeConfirmed()) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(
+        quic_no_path_degrading_before_handshake_confirmed, 2, 2);
+    return false;
+  }
   // No blackhole detection before handshake completes.
   if (default_enable_5rto_blackhole_detection_) {
     QUIC_RELOADABLE_FLAG_COUNT_N(quic_default_enable_5rto_blackhole_detection2,
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index 2152a6f..e700d88 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -7160,6 +7160,9 @@
   EXPECT_TRUE(connection_.connected());
   EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
   EXPECT_FALSE(connection_.IsPathDegrading());
+  EXPECT_CALL(visitor_, GetHandshakeState())
+      .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
+  connection_.OnHandshakeComplete();
 
   const char data[] = "data";
   size_t data_size = strlen(data);
@@ -7245,6 +7248,9 @@
   EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
   EXPECT_FALSE(connection_.IsPathDegrading());
   EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
+  EXPECT_CALL(visitor_, GetHandshakeState())
+      .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
+  connection_.OnHandshakeComplete();
 
   const char data[] = "data";
   size_t data_size = strlen(data);
@@ -7290,7 +7296,7 @@
 
   // Now there's a retransmittable packet (PING) on the wire, so the path
   // degrading alarm should be set.
-  EXPECT_TRUE(connection_.PathDegradingDetectionInProgress());
+  ASSERT_TRUE(connection_.PathDegradingDetectionInProgress());
   delay = QuicConnectionPeer::GetSentPacketManager(&connection_)
               ->GetPathDegradingDelay();
   EXPECT_EQ(delay, connection_.GetBlackholeDetectorAlarm()->deadline() -
@@ -7487,6 +7493,9 @@
   EXPECT_TRUE(connection_.connected());
   EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
   EXPECT_FALSE(connection_.IsPathDegrading());
+  EXPECT_CALL(visitor_, GetHandshakeState())
+      .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
+  connection_.OnHandshakeComplete();
 
   const char data[] = "data";
   size_t data_size = strlen(data);
@@ -7546,6 +7555,23 @@
   EXPECT_TRUE(connection_.IsPathDegrading());
 }
 
+TEST_P(QuicConnectionTest, NoPathDegradingDetectionBeforeHandshakeConfirmed) {
+  EXPECT_TRUE(connection_.connected());
+  EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
+  EXPECT_FALSE(connection_.IsPathDegrading());
+  EXPECT_CALL(visitor_, GetHandshakeState())
+      .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+
+  connection_.SendStreamDataWithString(1, "data", 0, NO_FIN);
+  if (GetQuicReloadableFlag(
+          quic_no_path_degrading_before_handshake_confirmed) &&
+      connection_.SupportsMultiplePacketNumberSpaces()) {
+    EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
+  } else {
+    EXPECT_TRUE(connection_.PathDegradingDetectionInProgress());
+  }
+}
+
 // This test verifies that the connection unmarks path as degrarding and spins
 // the timer to detect future path degrading when forward progress is made
 // after path has been marked degrading.
@@ -7553,6 +7579,9 @@
   EXPECT_TRUE(connection_.connected());
   EXPECT_FALSE(connection_.PathDegradingDetectionInProgress());
   EXPECT_FALSE(connection_.IsPathDegrading());
+  EXPECT_CALL(visitor_, GetHandshakeState())
+      .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
+  connection_.OnHandshakeComplete();
 
   const char data[] = "data";
   size_t data_size = strlen(data);
@@ -9445,7 +9474,9 @@
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
   connection_.SetFromConfig(config);
-  if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+  if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2) ||
+      GetQuicReloadableFlag(
+          quic_no_path_degrading_before_handshake_confirmed)) {
     EXPECT_CALL(visitor_, GetHandshakeState())
         .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
   }
@@ -9495,7 +9526,9 @@
   }
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
   connection_.SetFromConfig(config);
-  if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+  if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2) ||
+      GetQuicReloadableFlag(
+          quic_no_path_degrading_before_handshake_confirmed)) {
     EXPECT_CALL(visitor_, GetHandshakeState())
         .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
   }
@@ -9544,7 +9577,9 @@
   config.SetConnectionOptionsToSend(connection_options);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
   connection_.SetFromConfig(config);
-  if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+  if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2) ||
+      GetQuicReloadableFlag(
+          quic_no_path_degrading_before_handshake_confirmed)) {
     EXPECT_CALL(visitor_, GetHandshakeState())
         .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
   }
@@ -10642,7 +10677,8 @@
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
   connection_.SetFromConfig(config);
   EXPECT_CALL(visitor_, GetHandshakeState())
-      .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+      .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
+  connection_.OnHandshakeComplete();
   EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet());
   // Send stream data.
   SendStreamDataToPeer(
@@ -10694,7 +10730,9 @@
   connection_options.push_back(k5RTO);
   config.SetConnectionOptionsToSend(connection_options);
   QuicConfigPeer::SetNegotiated(&config, true);
-  if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+  if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2) ||
+      GetQuicReloadableFlag(
+          quic_no_path_degrading_before_handshake_confirmed)) {
     EXPECT_CALL(visitor_, GetHandshakeState())
         .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
   }
@@ -10708,10 +10746,20 @@
   connection_.SetFromConfig(config);
 
   connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
-  EXPECT_TRUE(connection_.BlackholeDetectionInProgress());
+  if (GetQuicReloadableFlag(
+          quic_no_path_degrading_before_handshake_confirmed)) {
+    // No blackhole detection before handshake confirmed.
+    EXPECT_FALSE(connection_.BlackholeDetectionInProgress());
+  } else {
+    EXPECT_TRUE(connection_.BlackholeDetectionInProgress());
+  }
   // Discard handshake keys.
+  EXPECT_CALL(visitor_, GetHandshakeState())
+      .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
   connection_.OnHandshakeComplete();
-  if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
+  if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2) ||
+      GetQuicReloadableFlag(
+          quic_no_path_degrading_before_handshake_confirmed)) {
     // Verify blackhole detection stops.
     EXPECT_FALSE(connection_.BlackholeDetectionInProgress());
   } else {
@@ -11232,7 +11280,7 @@
   connection_.NeuterUnencryptedPackets();
   connection_.OnHandshakeComplete();
   EXPECT_CALL(visitor_, GetHandshakeState())
-      .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+      .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
 
   std::string data(1200, 'a');
   // Send data packets 1 - 5.
@@ -15419,7 +15467,7 @@
   connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
   connection_.RemoveEncrypter(ENCRYPTION_HANDSHAKE);
   EXPECT_CALL(visitor_, GetHandshakeState())
-      .WillRepeatedly(Return(HANDSHAKE_COMPLETE));
+      .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
 
   SendStreamDataToPeer(1, "foo", 0, NO_FIN, nullptr);
   ASSERT_TRUE(connection_.BlackholeDetectionInProgress());
diff --git a/quiche/quic/core/quic_flags_list.h b/quiche/quic/core/quic_flags_list.h
index 154ad0c..a38464c 100644
--- a/quiche/quic/core/quic_flags_list.h
+++ b/quiche/quic/core/quic_flags_list.h
@@ -29,6 +29,8 @@
 QUIC_FLAG(quic_reloadable_flag_quic_can_send_ack_frequency, true)
 // If true, allow client to enable BBRv2 on server via connection option \'B2ON\'.
 QUIC_FLAG(quic_reloadable_flag_quic_allow_client_enabled_bbr_v2, true)
+// If true, an endpoint does not detect path degrading or blackholing until handshake gets confirmed.
+QUIC_FLAG(quic_reloadable_flag_quic_no_path_degrading_before_handshake_confirmed, true)
 // If true, combine two WriteOrBufferData to one while writing headers.
 QUIC_FLAG(quic_reloadable_flag_quic_one_write_for_headers, true)
 // If true, default-enable 5RTO blachole detection.