Wire in the ack exponent trransport config for IETF QUIC

gfe-relnote: N/A, for IETF QUIC Only, protected by V99 flag.
PiperOrigin-RevId: 260736433
Change-Id: I5468bc4f052d78d2bf6890cdf0734cece5b107c0
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index fdd4fd1..12afbd1 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -219,6 +219,8 @@
 const QuicTag kSCLS = TAG('S', 'C', 'L', 'S');   // Silently close on timeout
 const QuicTag kMIBS = TAG('M', 'I', 'D', 'S');   // Max incoming bidi streams
 const QuicTag kMIUS = TAG('M', 'I', 'U', 'S');   // Max incoming unidi streams
+const QuicTag kADE  = TAG('A', 'D', 'E', 0);     // Ack Delay Exponent (IETF
+                                                 // QUIC ACK Frame Only).
 const QuicTag kIRTT = TAG('I', 'R', 'T', 'T');   // Estimated initial RTT in us.
 const QuicTag kSNI  = TAG('S', 'N', 'I', '\0');  // Server name
                                                  // indication
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index c78fab4..10455e8 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -634,6 +634,39 @@
   }
 }
 
+// Simple transaction, but set a non-default ack exponent at the client
+// and ensure it gets to the server.
+TEST_P(EndToEndTest, SimpleRequestResponseWithAckExponentChange) {
+  const uint32_t kClientAckDelayExponent = kDefaultAckDelayExponent + 100u;
+  // Force the ACK exponent to be something other than the default.
+  // Note that it is sent only if doing IETF QUIC.
+  client_config_.SetAckDelayExponentToSend(kClientAckDelayExponent);
+  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 (VersionHasIetfQuicFrames(
+          GetParam().negotiated_version.transport_version)) {
+    // Should be only for IETF QUIC.
+    EXPECT_EQ(kClientAckDelayExponent,
+              GetServerConnection()->framer().peer_ack_delay_exponent());
+  } else {
+    // No change for Google QUIC.
+    EXPECT_EQ(kDefaultAckDelayExponent,
+              GetServerConnection()->framer().peer_ack_delay_exponent());
+  }
+  // No change, regardless of version.
+  EXPECT_EQ(kDefaultAckDelayExponent,
+            GetServerConnection()->framer().local_ack_delay_exponent());
+}
+
 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 661b5f3..22aef80 100644
--- a/quic/core/quic_config.cc
+++ b/quic/core/quic_config.cc
@@ -414,7 +414,8 @@
       support_max_header_list_size_(kSMHL, PRESENCE_OPTIONAL),
       stateless_reset_token_(kSRST, PRESENCE_OPTIONAL),
       max_incoming_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL),
-      max_ack_delay_ms_(kMAD, PRESENCE_OPTIONAL) {
+      max_ack_delay_ms_(kMAD, PRESENCE_OPTIONAL),
+      ack_delay_exponent_(kADE, PRESENCE_OPTIONAL) {
   SetDefaults();
 }
 
@@ -557,6 +558,22 @@
   return max_ack_delay_ms_.GetReceivedValue();
 }
 
+void QuicConfig::SetAckDelayExponentToSend(uint32_t exponent) {
+  ack_delay_exponent_.SetSendValue(exponent);
+}
+
+uint32_t QuicConfig::GetAckDelayExponentToSend() {
+  return ack_delay_exponent_.GetSendValue();
+}
+
+bool QuicConfig::HasReceivedAckDelayExponent() const {
+  return ack_delay_exponent_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedAckDelayExponent() const {
+  return ack_delay_exponent_.GetReceivedValue();
+}
+
 bool QuicConfig::HasSetBytesForConnectionIdToSend() const {
   return bytes_for_connection_id_.HasSendValue();
 }
@@ -711,6 +728,7 @@
   SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow);
   SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs);
   SetSupportMaxHeaderListSize();
+  SetAckDelayExponentToSend(kDefaultAckDelayExponent);
 }
 
 void QuicConfig::ToHandshakeMessage(
@@ -724,6 +742,7 @@
   max_incoming_bidirectional_streams_.ToHandshakeMessage(out);
   if (VersionHasIetfQuicFrames(transport_version)) {
     max_incoming_unidirectional_streams_.ToHandshakeMessage(out);
+    ack_delay_exponent_.ToHandshakeMessage(out);
   }
   if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {
     QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 1, 4);
@@ -806,6 +825,10 @@
     error = max_ack_delay_ms_.ProcessPeerHello(peer_hello, hello_type,
                                                error_details);
   }
+  if (error == QUIC_NO_ERROR) {
+    error = ack_delay_exponent_.ProcessPeerHello(peer_hello, hello_type,
+                                                 error_details);
+  }
   return error;
 }
 
@@ -838,6 +861,7 @@
     QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 3, 4);
     params->max_ack_delay.set_value(kDefaultDelayedAckTimeMs);
   }
+  params->ack_delay_exponent.set_value(ack_delay_exponent_.GetSendValue());
   params->disable_migration =
       connection_migration_disabled_.HasSendValue() &&
       connection_migration_disabled_.GetSendValue() != 0;
@@ -924,6 +948,9 @@
     max_ack_delay_ms_.SetReceivedValue(std::min<uint32_t>(
         params.max_ack_delay.value(), std::numeric_limits<uint32_t>::max()));
   }
+  if (params.ack_delay_exponent.IsValid()) {
+    ack_delay_exponent_.SetReceivedValue(params.ack_delay_exponent.value());
+  }
   connection_migration_disabled_.SetReceivedValue(
       params.disable_migration ? 1u : 0u);
 
diff --git a/quic/core/quic_config.h b/quic/core/quic_config.h
index 3c82a68..b4a4ca9 100644
--- a/quic/core/quic_config.h
+++ b/quic/core/quic_config.h
@@ -424,6 +424,11 @@
   bool HasReceivedMaxAckDelayMs() const;
   uint32_t ReceivedMaxAckDelayMs() const;
 
+  void SetAckDelayExponentToSend(uint32_t exponent);
+  uint32_t GetAckDelayExponentToSend();
+  bool HasReceivedAckDelayExponent() const;
+  uint32_t ReceivedAckDelayExponent() const;
+
   bool negotiated() const;
 
   void SetCreateSessionTagIndicators(QuicTagVector tags);
@@ -516,6 +521,13 @@
   // The received value is the value received from the peer and used by
   // the peer.
   QuicFixedUint32 max_ack_delay_ms_;
+
+  // ack_delay_exponent parameter negotiated in IETF QUIC transport
+  // parameter negotiation. The sent exponent is the exponent that this
+  // node uses when serializing an ACK frame (and the peer should use when
+  // deserializing the frame); the received exponent is the value the peer uses
+  // to serialize frames and this node uses to deserialize them.
+  QuicFixedUint32 ack_delay_exponent_;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index a13c506..e65492f 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -425,6 +425,9 @@
     stateless_reset_token_received_ = true;
     received_stateless_reset_token_ = config.ReceivedStatelessResetToken();
   }
+  if (config.HasReceivedAckDelayExponent()) {
+    framer_.set_peer_ack_delay_exponent(config.ReceivedAckDelayExponent());
+  }
   if (GetQuicReloadableFlag(quic_send_timestamps) &&
       config.HasClientSentConnectionOption(kSTMP, perspective_)) {
     QUIC_RELOADABLE_FLAG_COUNT(quic_send_timestamps);
diff --git a/quic/core/quic_constants.h b/quic/core/quic_constants.h
index 1ba32d8..cdee0f9 100644
--- a/quic/core/quic_constants.h
+++ b/quic/core/quic_constants.h
@@ -113,6 +113,9 @@
 // in low-bandwidth (< ~384 kbps), where an ack is sent per packet.
 const int64_t kDefaultDelayedAckTimeMs = 25;
 
+// Default shift of the ACK delay in the IETF QUIC ACK frame.
+const uint32_t kDefaultAckDelayExponent = 3;
+
 // Minimum tail loss probe time in ms.
 static const int64_t kMinTailLossProbeTimeoutMs = 10;
 
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index e9d6fa9..59edc79 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -50,11 +50,6 @@
 #define ENDPOINT \
   (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
 
-// How much to shift the timestamp in the IETF Ack frame.
-// TODO(fkastenholz) when we get real IETF QUIC, need to get
-// the currect shift from the transport parameters.
-const int kIetfAckTimestampShift = 3;
-
 // Number of bits the packet number length bits are shifted from the right
 // edge of the header.
 const uint8_t kPublicHeaderSequenceNumberShift = 4;
@@ -482,7 +477,9 @@
           expected_server_connection_id_length),
       expected_client_connection_id_length_(0),
       supports_multiple_packet_number_spaces_(false),
-      last_written_packet_number_length_(0) {
+      last_written_packet_number_length_(0),
+      peer_ack_delay_exponent_(kDefaultAckDelayExponent),
+      local_ack_delay_exponent_(kDefaultAckDelayExponent) {
   DCHECK(!supported_versions.empty());
   version_ = supported_versions_[0];
   decrypter_[ENCRYPTION_INITIAL] = QuicMakeUnique<NullDecrypter>(perspective);
@@ -3753,12 +3750,10 @@
     return false;
   }
 
-  // TODO(fkastenholz) when we get real IETF QUIC, need to get
-  // the currect shift from the transport parameters.
   if (ack_delay_time_in_us == kVarInt62MaxValue) {
     ack_frame->ack_delay_time = QuicTime::Delta::Infinite();
   } else {
-    ack_delay_time_in_us = (ack_delay_time_in_us << kIetfAckTimestampShift);
+    ack_delay_time_in_us = (ack_delay_time_in_us << peer_ack_delay_exponent_);
     ack_frame->ack_delay_time =
         QuicTime::Delta::FromMicroseconds(ack_delay_time_in_us);
   }
@@ -4566,7 +4561,7 @@
   ack_frame_size += QuicDataWriter::GetVarInt62Len(largest_acked.ToUint64());
   uint64_t ack_delay_time_us;
   ack_delay_time_us = frame.ack_delay_time.ToMicroseconds();
-  ack_delay_time_us = ack_delay_time_us >> kIetfAckTimestampShift;
+  ack_delay_time_us = ack_delay_time_us >> local_ack_delay_exponent_;
   ack_frame_size += QuicDataWriter::GetVarInt62Len(ack_delay_time_us);
 
   // If |ecn_counters_populated| is true and any of the ecn counters is non-0
@@ -5423,8 +5418,7 @@
   if (!frame.ack_delay_time.IsInfinite()) {
     DCHECK_LE(0u, frame.ack_delay_time.ToMicroseconds());
     ack_delay_time_us = frame.ack_delay_time.ToMicroseconds();
-    // TODO(fkastenholz): Use the shift from TLS transport parameters.
-    ack_delay_time_us = ack_delay_time_us >> kIetfAckTimestampShift;
+    ack_delay_time_us = ack_delay_time_us >> local_ack_delay_exponent_;
   }
 
   if (!writer->WriteVarInt62(ack_delay_time_us)) {
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h
index 2349a77..0143abe 100644
--- a/quic/core/quic_framer.h
+++ b/quic/core/quic_framer.h
@@ -611,6 +611,18 @@
       uint8_t* source_connection_id_length_out,
       std::string* detailed_error);
 
+  void set_local_ack_delay_exponent(uint32_t exponent) {
+    local_ack_delay_exponent_ = exponent;
+  }
+  uint32_t local_ack_delay_exponent() const {
+    return local_ack_delay_exponent_;
+  }
+
+  void set_peer_ack_delay_exponent(uint32_t exponent) {
+    peer_ack_delay_exponent_ = exponent;
+  }
+  uint32_t peer_ack_delay_exponent() const { return peer_ack_delay_exponent_; }
+
  private:
   friend class test::QuicFramerPeer;
 
@@ -1020,6 +1032,15 @@
   // The length in bytes of the last packet number written to an IETF-framed
   // packet.
   size_t last_written_packet_number_length_;
+
+  // The amount to shift the ack timestamp in ACK frames. The default is 3.
+  // Local_ is the amount this node shifts timestamps in ACK frames it
+  // generates. it is sent to the peer in a transport parameter negotiation.
+  // Peer_ is the amount the peer shifts timestamps when it sends ACK frames to
+  // this node. This node "unshifts" by this amount. The value is received from
+  // the peer in the transport parameter negotiation. IETF QUIC only.
+  uint32_t peer_ack_delay_exponent_;
+  uint32_t local_ack_delay_exponent_;
 };
 
 }  // namespace quic