In quic, do not extend idle time on undecryptable packets. protected by gfe2_reloadable_flag_quic_extend_idle_time_on_decryptable_packets.

PiperOrigin-RevId: 310407777
Change-Id: Ibb071c6652e1568ad11ead178328b073fcadd60f
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 91b5c2b..6445fce 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -299,6 +299,7 @@
       handshake_timeout_(QuicTime::Delta::Infinite()),
       time_of_first_packet_sent_after_receiving_(QuicTime::Zero()),
       time_of_last_received_packet_(clock_->ApproximateNow()),
+      time_of_last_decryptable_packet_(time_of_last_received_packet_),
       sent_packet_manager_(perspective,
                            clock_,
                            random_generator_,
@@ -845,6 +846,14 @@
     // Address is validated by successfully processing a HANDSHAKE packet.
     address_validated_ = true;
   }
+  if (extend_idle_time_on_decryptable_packets_) {
+    QUIC_RELOADABLE_FLAG_COUNT(quic_extend_idle_time_on_decryptable_packets);
+    if (use_idle_network_detector_) {
+      idle_network_detector_.OnPacketReceived(time_of_last_received_packet_);
+    } else {
+      time_of_last_decryptable_packet_ = time_of_last_received_packet_;
+    }
+  }
 
   visitor_->OnPacketDecrypted(level);
 }
@@ -1834,7 +1843,7 @@
              << " too far from current time:"
              << clock_->ApproximateNow().ToDebuggingValue();
   }
-  if (use_idle_network_detector_) {
+  if (!extend_idle_time_on_decryptable_packets_ && use_idle_network_detector_) {
     QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_idle_network_detector, 1, 6);
     idle_network_detector_.OnPacketReceived(packet.receipt_time());
   } else {
@@ -2414,7 +2423,7 @@
       idle_network_detector_.OnPacketSent(packet_send_time);
       QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_idle_network_detector, 2, 6);
     } else if (time_of_first_packet_sent_after_receiving_ <
-               time_of_last_received_packet_) {
+               GetTimeOfLastReceivedPacket()) {
       // Update |time_of_first_packet_sent_after_receiving_| if this is the
       // first packet sent after the last packet was received. If it were
       // updated on every sent packet, then sending into a black hole might
@@ -3192,7 +3201,7 @@
   }
 
   QuicTime time_of_last_packet =
-      std::max(time_of_last_received_packet_,
+      std::max(GetTimeOfLastReceivedPacket(),
                time_of_first_packet_sent_after_receiving_);
 
   // |delta| can be < 0 as |now| is approximate time but |time_of_last_packet|
@@ -3228,7 +3237,7 @@
 void QuicConnection::SetTimeoutAlarm() {
   DCHECK(!use_idle_network_detector_);
   QuicTime time_of_last_packet =
-      std::max(time_of_last_received_packet_,
+      std::max(GetTimeOfLastReceivedPacket(),
                time_of_first_packet_sent_after_receiving_);
 
   QuicTime deadline = time_of_last_packet + idle_network_timeout_;
@@ -4360,6 +4369,11 @@
   if (use_idle_network_detector_) {
     return idle_network_detector_.time_of_last_received_packet();
   }
+  if (extend_idle_time_on_decryptable_packets_) {
+    DCHECK(time_of_last_decryptable_packet_ == time_of_last_received_packet_ ||
+           !last_packet_decrypted_);
+    return time_of_last_decryptable_packet_;
+  }
   return time_of_last_received_packet_;
 }
 
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index 1bfacee..bc7245a 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -1471,13 +1471,20 @@
   // Timestamps used for timeouts.
   // The time of the first retransmittable packet that was sent after the most
   // recently received packet.
-  // TODO(fayang): Remove these two when deprecating
-  // quic_use_idle_network_detector.
+  // TODO(fayang): Remove time_of_first_packet_sent_after_receiving_ when
+  // deprecating quic_use_idle_network_detector.
   QuicTime time_of_first_packet_sent_after_receiving_;
   // The time that a packet is received for this connection. Initialized to
   // connection creation time.
-  // This is used for timeouts, and does not indicate the packet was processed.
+  // This does not indicate the packet was processed.
   QuicTime time_of_last_received_packet_;
+  // This gets set to time_of_last_received_packet_ when a packet gets
+  // decrypted. Please note, this is not necessarily the original receive time
+  // of this decrypt packet because connection can decryptable packet out of
+  // order.
+  // TODO(fayang): Remove time_of_last_decryptable_packet_ when
+  // deprecating quic_use_idle_network_detector.
+  QuicTime time_of_last_decryptable_packet_;
 
   // Sent packet manager which tracks the status of packets sent by this
   // connection and contains the send and receive algorithms to determine when
@@ -1651,6 +1658,9 @@
   const bool use_idle_network_detector_ =
       use_blackhole_detector_ &&
       GetQuicReloadableFlag(quic_use_idle_network_detector);
+
+  const bool extend_idle_time_on_decryptable_packets_ =
+      GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets);
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index edeff6d..1822d0c 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -10634,6 +10634,48 @@
   }
 }
 
+TEST_P(QuicConnectionTest, DonotExtendIdleTimeOnUndecryptablePackets) {
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  QuicConfig config;
+  connection_.SetFromConfig(config);
+  // Subtract a second from the idle timeout on the client side.
+  QuicTime initial_deadline =
+      clock_.ApproximateNow() +
+      QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
+  EXPECT_EQ(initial_deadline, connection_.GetTimeoutAlarm()->deadline());
+
+  // Received an undecryptable packet.
+  clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+  const uint8_t tag = 0x07;
+  peer_framer_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+                            std::make_unique<TaggingEncrypter>(tag));
+  ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_FORWARD_SECURE);
+  if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets) ||
+      !GetQuicReloadableFlag(quic_use_blackhole_detector)) {
+    // Verify deadline does not get extended.
+    EXPECT_EQ(initial_deadline, connection_.GetTimeoutAlarm()->deadline());
+  }
+  if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) {
+    EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(1);
+  } else {
+    EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0);
+  }
+  QuicTime::Delta delay = initial_deadline - clock_.ApproximateNow();
+  clock_.AdvanceTime(delay);
+  if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets) ||
+      !GetQuicReloadableFlag(quic_use_blackhole_detector)) {
+    connection_.GetTimeoutAlarm()->Fire();
+  }
+  if (GetQuicReloadableFlag(quic_extend_idle_time_on_decryptable_packets)) {
+    // Verify connection gets closed.
+    EXPECT_FALSE(connection_.connected());
+  } else {
+    // Verify the timeout alarm deadline is updated.
+    EXPECT_TRUE(connection_.connected());
+    EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic