In quic, respect enable_half_rtt_tail_loss_probe_ when using pto. protected by gfe2_reloadable_flag_quic_use_half_rtt_as_first_pto.

PiperOrigin-RevId: 323792003
Change-Id: Ida875ae614e9849efa6c51fd355ac6504b8e9744
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index ededb87..ae536a2 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -1244,6 +1244,12 @@
                QuicTime::Delta::FromMilliseconds(kMinHandshakeTimeoutMs)) *
            (1 << consecutive_pto_count_);
   }
+  if (GetQuicReloadableFlag(quic_use_half_rtt_as_first_pto) &&
+      enable_half_rtt_tail_loss_probe_ && consecutive_pto_count_ == 0 &&
+      handshake_finished_) {
+    QUIC_RELOADABLE_FLAG_COUNT(quic_use_half_rtt_as_first_pto);
+    return std::max(min_tlp_timeout_, rtt_stats_.smoothed_rtt() * 0.5);
+  }
   const QuicTime::Delta rtt_var = use_standard_deviation_for_pto_
                                       ? rtt_stats_.GetStandardOrMeanDeviation()
                                       : rtt_stats_.mean_deviation();
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index 2ce7529..57abfab 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -4140,6 +4140,56 @@
       QuicSentPacketManagerPeer::GetEnableHalfRttTailLossProbe(&manager_));
 }
 
+TEST_F(QuicSentPacketManagerTest, PtoWithTlpr) {
+  SetQuicReloadableFlag(quic_use_half_rtt_as_first_pto, true);
+  QuicConfig config;
+  QuicTagVector options;
+
+  options.push_back(kTLPR);
+  options.push_back(k1PTO);
+  options.push_back(kPTOS);
+  QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+  EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, PacingRate(_))
+      .WillRepeatedly(Return(QuicBandwidth::Zero()));
+  EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
+      .WillOnce(Return(10 * kDefaultTCPMSS));
+  manager_.SetFromConfig(config);
+  EXPECT_TRUE(
+      QuicSentPacketManagerPeer::GetEnableHalfRttTailLossProbe(&manager_));
+  RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+  rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
+                       QuicTime::Delta::Zero(), QuicTime::Zero());
+  QuicTime::Delta srtt = rtt_stats->smoothed_rtt();
+  manager_.SetHandshakeConfirmed();
+
+  SendDataPacket(1, ENCRYPTION_FORWARD_SECURE);
+  // Verify PTO is correctly set.
+  QuicTime::Delta expected_pto_delay = 0.5 * srtt;
+  QuicTime deadline = clock_.Now() + expected_pto_delay;
+  EXPECT_EQ(deadline, manager_.GetRetransmissionTime());
+
+  // Invoke PTO.
+  clock_.AdvanceTime(deadline - clock_.Now());
+  manager_.OnRetransmissionTimeout();
+  EXPECT_CALL(notifier_, RetransmitFrames(_, _))
+      .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) {
+        RetransmitDataPacket(3, type, ENCRYPTION_FORWARD_SECURE);
+      })));
+  manager_.MaybeSendProbePackets();
+
+  // Verify PTO period gets set correctly.
+  int pto_rttvar_multiplier =
+      GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4;
+  expected_pto_delay =
+      srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() +
+      QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
+  QuicTime sent_time = clock_.Now();
+  EXPECT_EQ(sent_time + expected_pto_delay * 2,
+            manager_.GetRetransmissionTime());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic