In quic, coalesce packet of higher encryption level with initial or handshake retransmission. protected by gfe2_reloadable_flag_quic_coalesced_packet_of_higher_space.

The goal of this change is to mitigate inflated RTT sample.

PiperOrigin-RevId: 321556627
Change-Id: I7fc8675bb0f05a48b6e81ed4aa9c04b42fb0690a
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 62aa83f..de7e450 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -10399,7 +10399,12 @@
                            _, _));
   EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
   connection_.GetRetransmissionAlarm()->Fire();
-  EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+  if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space)) {
+    // Verify 1-RTT packet gets coalesced with handshake retransmission.
+    EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
+  } else {
+    EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+  }
 
   // Send application data.
   connection_.SendApplicationDataAtLevel(ENCRYPTION_FORWARD_SECURE, 5, "data",
@@ -10410,15 +10415,24 @@
 
   // Retransmit handshake data again.
   clock_.AdvanceTime(retransmission_time - clock_.Now());
+  QuicPacketNumber handshake_retransmission =
+      GetQuicReloadableFlag(quic_default_on_pto) ? QuicPacketNumber(5)
+                                                 : QuicPacketNumber(7);
+  if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space)) {
+    handshake_retransmission += 1;
+    EXPECT_CALL(*send_algorithm_,
+                OnPacketSent(_, _, handshake_retransmission + 1, _, _));
+  }
   EXPECT_CALL(*send_algorithm_,
-              OnPacketSent(_, _,
-                           GetQuicReloadableFlag(quic_default_on_pto)
-                               ? QuicPacketNumber(5)
-                               : QuicPacketNumber(7),
-                           _, _));
+              OnPacketSent(_, _, handshake_retransmission, _, _));
   EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
   connection_.GetRetransmissionAlarm()->Fire();
-  EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+  if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space)) {
+    // Verify 1-RTT packet gets coalesced with handshake retransmission.
+    EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
+  } else {
+    EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+  }
 
   // Discard handshake key.
   connection_.OnHandshakeComplete();
@@ -10427,12 +10441,14 @@
 
   // Retransmit application data.
   clock_.AdvanceTime(retransmission_time - clock_.Now());
+  QuicPacketNumber application_retransmission =
+      GetQuicReloadableFlag(quic_default_on_pto) ? QuicPacketNumber(6)
+                                                 : QuicPacketNumber(9);
+  if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space)) {
+    application_retransmission += 2;
+  }
   EXPECT_CALL(*send_algorithm_,
-              OnPacketSent(_, _,
-                           GetQuicReloadableFlag(quic_default_on_pto)
-                               ? QuicPacketNumber(6)
-                               : QuicPacketNumber(9),
-                           _, _));
+              OnPacketSent(_, _, application_retransmission, _, _));
   connection_.GetRetransmissionAlarm()->Fire();
   EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
 }
@@ -11217,7 +11233,11 @@
   connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
                            std::make_unique<TaggingEncrypter>(0x02));
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
-  EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+  if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space)) {
+    EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2);
+  } else {
+    EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+  }
   connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
   // Verify PTO time does not change.
   EXPECT_EQ(expected_pto_time,
@@ -11356,6 +11376,89 @@
   }
 }
 
+// Regression test for b/161228202
+TEST_P(QuicConnectionTest, InflatedRttSample) {
+  if (!connection_.SupportsMultiplePacketNumberSpaces()) {
+    return;
+  }
+  // 30ms RTT.
+  const QuicTime::Delta kTestRTT = QuicTime::Delta::FromMilliseconds(30);
+  set_perspective(Perspective::IS_SERVER);
+  RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
+  use_tagging_decrypter();
+  // Receives packet 1000 in initial data.
+  if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+    EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+  }
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+  ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL);
+  EXPECT_TRUE(connection_.HasPendingAcks());
+
+  connection_.SetEncrypter(ENCRYPTION_INITIAL,
+                           std::make_unique<TaggingEncrypter>(0x01));
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+  // Send INITIAL 1.
+  connection_.SendCryptoDataWithString(std::string(512, 'a'), 0,
+                                       ENCRYPTION_INITIAL);
+  ASSERT_TRUE(connection_.sent_packet_manager()
+                  .GetRetransmissionTime()
+                  .IsInitialized());
+  QuicTime::Delta pto_timeout =
+      connection_.sent_packet_manager().GetRetransmissionTime() - clock_.Now();
+  // Send Handshake 2.
+  connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+                           std::make_unique<TaggingEncrypter>(0x02));
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+  if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space)) {
+    // Verify HANDSHAKE packet is coalesced with INITIAL retransmission.
+    EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2);
+  } else {
+    EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+  }
+  connection_.SendCryptoDataWithString(std::string(1024, 'a'), 0,
+                                       ENCRYPTION_HANDSHAKE);
+
+  // INITIAL 1 gets lost and PTO fires.
+  clock_.AdvanceTime(pto_timeout);
+  connection_.GetRetransmissionAlarm()->Fire();
+
+  clock_.AdvanceTime(kTestRTT);
+  // Assume retransmitted INITIAL gets received.
+  QuicFrames frames;
+  QuicPacketNumber initial_retransmission =
+      GetQuicReloadableFlag(quic_default_on_pto) ? QuicPacketNumber(3)
+                                                 : QuicPacketNumber(4);
+  auto ack_frame =
+      InitAckFrame({{initial_retransmission, initial_retransmission + 1}});
+  frames.push_back(QuicFrame(&ack_frame));
+  EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _))
+      .Times(AnyNumber());
+  ProcessFramesPacketAtLevel(1001, frames, ENCRYPTION_INITIAL);
+  EXPECT_EQ(kTestRTT, rtt_stats->latest_rtt());
+  // Because retransmitted INITIAL gets received so HANDSHAKE 2 gets processed.
+  frames.clear();
+  QuicAckFrame ack_frame2;
+  if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space)) {
+    // HANDSHAKE 5 is also processed.
+    ack_frame2 = InitAckFrame(
+        {{QuicPacketNumber(2), QuicPacketNumber(3)},
+         {initial_retransmission + 1, initial_retransmission + 2}});
+  } else {
+    ack_frame2 = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}});
+  }
+  ack_frame2.ack_delay_time = QuicTime::Delta::Zero();
+  frames.push_back(QuicFrame(&ack_frame2));
+  ProcessFramesPacketAtLevel(1, frames, ENCRYPTION_HANDSHAKE);
+  if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space)) {
+    // Verify RTT inflation gets mitigated.
+    EXPECT_EQ(rtt_stats->latest_rtt(), kTestRTT);
+  } else {
+    // Verify this RTT sample gets inflated as it includes the PTO timeout and
+    // the actual RTT.
+    EXPECT_GE(rtt_stats->latest_rtt(), pto_timeout + kTestRTT);
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic