Connect up IETF QUIC Max ACK Delay transport parameter

This CL sets the QuicSentPacketManager's ACK Delay from the
MAX ACK Delay transport parameter.

gfe-relnote: N/A done only if IETF QUIC enabled & negotiated.
PiperOrigin-RevId: 260502360
Change-Id: Idd8a9d0fe36e7ab0794aa7532d608489866248eb
diff --git a/quic/core/crypto/crypto_handshake_message.cc b/quic/core/crypto/crypto_handshake_message.cc
index bf1df2b..022a86b 100644
--- a/quic/core/crypto/crypto_handshake_message.cc
+++ b/quic/core/crypto/crypto_handshake_message.cc
@@ -278,6 +278,7 @@
       case kMIBS:
       case kSCLS:
       case kTCID:
+      case kMAD:
         // uint32_t value
         if (it->second.size() == 4) {
           uint32_t value;
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index f2033e1..fdd4fd1 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -238,6 +238,8 @@
 const QuicTag kUAID = TAG('U', 'A', 'I', 'D');   // Client's User Agent ID.
 const QuicTag kXLCT = TAG('X', 'L', 'C', 'T');   // Expected leaf certificate.
 
+const QuicTag kMAD  = TAG('M', 'A', 'D', 0);     // Max Ack Delay (IETF QUIC)
+
 // Rejection tags
 const QuicTag kRREJ = TAG('R', 'R', 'E', 'J');   // Reasons for server sending
 
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index cbfb84d..c78fab4 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -605,6 +605,35 @@
   EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
 }
 
+// Simple transaction, but set a non-default ack delay at the client
+// and ensure it gets to the server.
+TEST_P(EndToEndTest, SimpleRequestResponseWithAckDelayChange) {
+  // Force the ACK delay to be something other than the default.
+  // Note that it is sent only if doing IETF QUIC.
+  client_config_.SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs + 100u);
+  ASSERT_TRUE(Initialize());
+
+  EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+  EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
+  int expected_num_client_hellos = 2;
+  if (ServerSendsVersionNegotiation()) {
+    ++expected_num_client_hellos;
+  }
+  EXPECT_EQ(expected_num_client_hellos,
+            client_->client()->GetNumSentClientHellos());
+  if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
+    EXPECT_EQ(kDefaultDelayedAckTimeMs + 100u,
+              GetSentPacketManagerFromFirstServerSession()
+                  ->peer_max_ack_delay()
+                  .ToMilliseconds());
+  } else {
+    EXPECT_EQ(kDefaultDelayedAckTimeMs,
+              GetSentPacketManagerFromFirstServerSession()
+                  ->peer_max_ack_delay()
+                  .ToMilliseconds());
+  }
+}
+
 TEST_P(EndToEndTest, SimpleRequestResponseForcedVersionNegotiation) {
   client_supported_versions_.insert(client_supported_versions_.begin(),
                                     QuicVersionReservedForNegotiation());
diff --git a/quic/core/quic_config.cc b/quic/core/quic_config.cc
index e24e84b..661b5f3 100644
--- a/quic/core/quic_config.cc
+++ b/quic/core/quic_config.cc
@@ -413,7 +413,8 @@
       alternate_server_address_(kASAD, PRESENCE_OPTIONAL),
       support_max_header_list_size_(kSMHL, PRESENCE_OPTIONAL),
       stateless_reset_token_(kSRST, PRESENCE_OPTIONAL),
-      max_incoming_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL) {
+      max_incoming_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL),
+      max_ack_delay_ms_(kMAD, PRESENCE_OPTIONAL) {
   SetDefaults();
 }
 
@@ -540,6 +541,22 @@
   return max_incoming_unidirectional_streams_.GetReceivedValue();
 }
 
+void QuicConfig::SetMaxAckDelayToSendMs(uint32_t max_ack_delay_ms) {
+  return max_ack_delay_ms_.SetSendValue(max_ack_delay_ms);
+}
+
+uint32_t QuicConfig::GetMaxAckDelayToToSendMs() const {
+  return max_ack_delay_ms_.GetSendValue();
+}
+
+bool QuicConfig::HasReceivedMaxAckDelayMs() const {
+  return max_ack_delay_ms_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedMaxAckDelayMs() const {
+  return max_ack_delay_ms_.GetReceivedValue();
+}
+
 bool QuicConfig::HasSetBytesForConnectionIdToSend() const {
   return bytes_for_connection_id_.HasSendValue();
 }
@@ -692,6 +709,7 @@
 
   SetInitialStreamFlowControlWindowToSend(kMinimumFlowControlSendWindow);
   SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow);
+  SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs);
   SetSupportMaxHeaderListSize();
 }
 
@@ -707,6 +725,10 @@
   if (VersionHasIetfQuicFrames(transport_version)) {
     max_incoming_unidirectional_streams_.ToHandshakeMessage(out);
   }
+  if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 1, 4);
+    max_ack_delay_ms_.ToHandshakeMessage(out);
+  }
   bytes_for_connection_id_.ToHandshakeMessage(out);
   initial_round_trip_time_us_.ToHandshakeMessage(out);
   initial_stream_flow_control_window_bytes_.ToHandshakeMessage(out);
@@ -777,6 +799,13 @@
     error = stateless_reset_token_.ProcessPeerHello(peer_hello, hello_type,
                                                     error_details);
   }
+
+  if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time) &&
+      error == QUIC_NO_ERROR) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 2, 4);
+    error = max_ack_delay_ms_.ProcessPeerHello(peer_hello, hello_type,
+                                               error_details);
+  }
   return error;
 }
 
@@ -805,7 +834,10 @@
       max_incoming_bidirectional_streams_.GetSendValue());
   params->initial_max_streams_uni.set_value(
       max_incoming_unidirectional_streams_.GetSendValue());
-  params->max_ack_delay.set_value(kDefaultDelayedAckTimeMs);
+  if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 3, 4);
+    params->max_ack_delay.set_value(kDefaultDelayedAckTimeMs);
+  }
   params->disable_migration =
       connection_migration_disabled_.HasSendValue() &&
       connection_migration_disabled_.GetSendValue() != 0;
@@ -887,7 +919,11 @@
   initial_stream_flow_control_window_bytes_.SetReceivedValue(
       std::min<uint64_t>(params.initial_max_stream_data_bidi_local.value(),
                          std::numeric_limits<uint32_t>::max()));
-
+  if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 4, 4);
+    max_ack_delay_ms_.SetReceivedValue(std::min<uint32_t>(
+        params.max_ack_delay.value(), std::numeric_limits<uint32_t>::max()));
+  }
   connection_migration_disabled_.SetReceivedValue(
       params.disable_migration ? 1u : 0u);
 
diff --git a/quic/core/quic_config.h b/quic/core/quic_config.h
index ae15b6a..3c82a68 100644
--- a/quic/core/quic_config.h
+++ b/quic/core/quic_config.h
@@ -414,6 +414,16 @@
 
   QuicUint128 ReceivedStatelessResetToken() const;
 
+  // Manage the IETF QUIC Max ACK Delay transport parameter.
+  // The sent value is the delay that this node uses
+  // (QuicSentPacketManager::local_max_ack_delay_).
+  // The received delay is the value received from
+  // the peer (QuicSentPacketManager::peer_max_ack_delay_).
+  void SetMaxAckDelayToSendMs(uint32_t max_ack_delay_ms);
+  uint32_t GetMaxAckDelayToToSendMs() const;
+  bool HasReceivedMaxAckDelayMs() const;
+  uint32_t ReceivedMaxAckDelayMs() const;
+
   bool negotiated() const;
 
   void SetCreateSessionTagIndicators(QuicTagVector tags);
@@ -501,6 +511,11 @@
   // Maximum number of incoming unidirectional streams that the connection can
   // support.
   QuicFixedUint32 max_incoming_unidirectional_streams_;
+
+  // Maximum ack delay. The sent value is the value used on this node.
+  // The received value is the value received from the peer and used by
+  // the peer.
+  QuicFixedUint32 max_ack_delay_ms_;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_config_test.cc b/quic/core/quic_config_test.cc
index 84e89c1..630e67a 100644
--- a/quic/core/quic_config_test.cc
+++ b/quic/core/quic_config_test.cc
@@ -56,6 +56,8 @@
 }
 
 TEST_P(QuicConfigTest, ProcessClientHello) {
+  const uint32_t kTestMaxAckDelayMs =
+      static_cast<uint32_t>(kDefaultDelayedAckTimeMs + 1);
   QuicConfig client_config;
   QuicTagVector cgst;
   cgst.push_back(kQBIC);
@@ -70,6 +72,7 @@
   QuicTagVector copt;
   copt.push_back(kTBBR);
   client_config.SetConnectionOptionsToSend(copt);
+  client_config.SetMaxAckDelayToSendMs(kTestMaxAckDelayMs);
   CryptoHandshakeMessage msg;
   client_config.ToHandshakeMessage(&msg, GetParam());
 
@@ -99,6 +102,12 @@
             2 * kInitialStreamFlowControlWindowForTest);
   EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(),
             2 * kInitialSessionFlowControlWindowForTest);
+  if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
+    EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs());
+    EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs());
+  } else {
+    EXPECT_FALSE(config_.HasReceivedMaxAckDelayMs());
+  }
 }
 
 TEST_P(QuicConfigTest, ProcessServerHello) {
@@ -106,6 +115,8 @@
   host.FromString("127.0.3.1");
   const QuicSocketAddress kTestServerAddress = QuicSocketAddress(host, 1234);
   const QuicUint128 kTestResetToken = MakeQuicUint128(0, 10111100001);
+  const uint32_t kTestMaxAckDelayMs =
+      static_cast<uint32_t>(kDefaultDelayedAckTimeMs + 1);
   QuicConfig server_config;
   QuicTagVector cgst;
   cgst.push_back(kQBIC);
@@ -119,6 +130,7 @@
       2 * kInitialSessionFlowControlWindowForTest);
   server_config.SetAlternateServerAddressToSend(kTestServerAddress);
   server_config.SetStatelessResetTokenToSend(kTestResetToken);
+  server_config.SetMaxAckDelayToSendMs(kTestMaxAckDelayMs);
   CryptoHandshakeMessage msg;
   server_config.ToHandshakeMessage(&msg, GetParam());
   std::string error_details;
@@ -137,6 +149,12 @@
   EXPECT_EQ(kTestServerAddress, config_.ReceivedAlternateServerAddress());
   EXPECT_TRUE(config_.HasReceivedStatelessResetToken());
   EXPECT_EQ(kTestResetToken, config_.ReceivedStatelessResetToken());
+  if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
+    EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs());
+    EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs());
+  } else {
+    EXPECT_FALSE(config_.HasReceivedMaxAckDelayMs());
+  }
 }
 
 TEST_P(QuicConfigTest, MissingOptionalValuesInCHLO) {
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index 5762333..90771f8 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -243,6 +243,11 @@
   }
   send_algorithm_->SetFromConfig(config, perspective);
 
+  if (config.HasReceivedMaxAckDelayMs()) {
+    peer_max_ack_delay_ =
+        QuicTime::Delta::FromMilliseconds(config.ReceivedMaxAckDelayMs());
+  }
+
   if (network_change_visitor_ != nullptr) {
     network_change_visitor_->OnCongestionChange();
   }