Add methods that reads/writes connection ID in preferred_address transport parameter
.

PiperOrigin-RevId: 351576008
Change-Id: I6ce671ba7b90b338655713c92f811ac2338379e8
diff --git a/quic/core/quic_config.cc b/quic/core/quic_config.cc
index 63c6f77..725b513 100644
--- a/quic/core/quic_config.cc
+++ b/quic/core/quic_config.cc
@@ -17,6 +17,7 @@
 #include "quic/core/quic_connection_id.h"
 #include "quic/core/quic_constants.h"
 #include "quic/core/quic_socket_address_coder.h"
+#include "quic/core/quic_types.h"
 #include "quic/core/quic_utils.h"
 #include "quic/platform/api/quic_bug_tracker.h"
 #include "quic/platform/api/quic_flag_utils.h"
@@ -877,6 +878,20 @@
   alternate_server_address_ipv6_.SetSendValue(alternate_server_address_ipv6);
 }
 
+void QuicConfig::SetIPv6AlternateServerAddressToSend(
+    const QuicSocketAddress& alternate_server_address_ipv6,
+    const QuicConnectionId& connection_id,
+    QuicUint128 stateless_reset_token) {
+  if (!alternate_server_address_ipv6.host().IsIPv6()) {
+    QUIC_BUG << "Cannot use SetIPv6AlternateServerAddressToSend with "
+             << alternate_server_address_ipv6;
+    return;
+  }
+  alternate_server_address_ipv6_.SetSendValue(alternate_server_address_ipv6);
+  preferred_address_connection_id_and_token_ =
+      std::make_pair(connection_id, stateless_reset_token);
+}
+
 bool QuicConfig::HasReceivedIPv6AlternateServerAddress() const {
   return alternate_server_address_ipv6_.HasReceivedValue();
 }
@@ -896,6 +911,20 @@
   alternate_server_address_ipv4_.SetSendValue(alternate_server_address_ipv4);
 }
 
+void QuicConfig::SetIPv4AlternateServerAddressToSend(
+    const QuicSocketAddress& alternate_server_address_ipv4,
+    const QuicConnectionId& connection_id,
+    QuicUint128 stateless_reset_token) {
+  if (!alternate_server_address_ipv4.host().IsIPv4()) {
+    QUIC_BUG << "Cannot use SetIPv4AlternateServerAddressToSend with "
+             << alternate_server_address_ipv4;
+    return;
+  }
+  alternate_server_address_ipv4_.SetSendValue(alternate_server_address_ipv4);
+  preferred_address_connection_id_and_token_ =
+      std::make_pair(connection_id, stateless_reset_token);
+}
+
 bool QuicConfig::HasReceivedIPv4AlternateServerAddress() const {
   return alternate_server_address_ipv4_.HasReceivedValue();
 }
@@ -905,6 +934,18 @@
   return alternate_server_address_ipv4_.GetReceivedValue();
 }
 
+bool QuicConfig::HasReceivedPreferredAddressConnectionIdAndToken() const {
+  return (HasReceivedIPv6AlternateServerAddress() ||
+          HasReceivedIPv4AlternateServerAddress()) &&
+         preferred_address_connection_id_and_token_.has_value();
+}
+
+const std::pair<QuicConnectionId, QuicUint128>&
+QuicConfig::ReceivedPreferredAddressConnectionIdAndToken() const {
+  DCHECK(HasReceivedPreferredAddressConnectionIdAndToken());
+  return *preferred_address_connection_id_and_token_;
+}
+
 void QuicConfig::SetOriginalConnectionIdToSend(
     const QuicConnectionId& original_destination_connection_id) {
   original_destination_connection_id_to_send_ =
@@ -1202,6 +1243,15 @@
       preferred_address.ipv4_socket_address =
           alternate_server_address_ipv4_.GetSendValue();
     }
+    if (preferred_address_connection_id_and_token_) {
+      preferred_address.connection_id =
+          preferred_address_connection_id_and_token_->first;
+      auto* begin = reinterpret_cast<const char*>(
+          &preferred_address_connection_id_and_token_->second);
+      auto* end =
+          begin + sizeof(preferred_address_connection_id_and_token_->second);
+      preferred_address.stateless_reset_token.assign(begin, end);
+    }
     params->preferred_address =
         std::make_unique<TransportParameters::PreferredAddress>(
             preferred_address);
@@ -1320,6 +1370,15 @@
         alternate_server_address_ipv4_.SetReceivedValue(
             params.preferred_address->ipv4_socket_address);
       }
+      // TODO(haoyuewang) Treat 0 length connection ID sent in preferred_address
+      // as a connection error of type TRANSPORT_PARAMETER_ERROR when server
+      // fully supports it.
+      if (!params.preferred_address->connection_id.IsEmpty()) {
+        preferred_address_connection_id_and_token_ = std::make_pair(
+            params.preferred_address->connection_id,
+            *reinterpret_cast<const QuicUint128*>(
+                &params.preferred_address->stateless_reset_token.front()));
+      }
     }
     if (params.min_ack_delay_us.value() != 0) {
       if (params.min_ack_delay_us.value() >
diff --git a/quic/core/quic_config.h b/quic/core/quic_config.h
index 6778e80..d0fa2c7 100644
--- a/quic/core/quic_config.h
+++ b/quic/core/quic_config.h
@@ -391,15 +391,28 @@
   // IPv6 alternate server address.
   void SetIPv6AlternateServerAddressToSend(
       const QuicSocketAddress& alternate_server_address_ipv6);
+  void SetIPv6AlternateServerAddressToSend(
+      const QuicSocketAddress& alternate_server_address_ipv6,
+      const QuicConnectionId& connection_id,
+      QuicUint128 stateless_reset_token);
   bool HasReceivedIPv6AlternateServerAddress() const;
   const QuicSocketAddress& ReceivedIPv6AlternateServerAddress() const;
 
   // IPv4 alternate server address.
   void SetIPv4AlternateServerAddressToSend(
       const QuicSocketAddress& alternate_server_address_ipv4);
+  void SetIPv4AlternateServerAddressToSend(
+      const QuicSocketAddress& alternate_server_address_ipv4,
+      const QuicConnectionId& connection_id,
+      QuicUint128 stateless_reset_token);
   bool HasReceivedIPv4AlternateServerAddress() const;
   const QuicSocketAddress& ReceivedIPv4AlternateServerAddress() const;
 
+  // Preferred Address Connection ID and Token.
+  bool HasReceivedPreferredAddressConnectionIdAndToken() const;
+  const std::pair<QuicConnectionId, QuicUint128>&
+  ReceivedPreferredAddressConnectionIdAndToken() const;
+
   // Original destination connection ID.
   void SetOriginalConnectionIdToSend(
       const QuicConnectionId& original_destination_connection_id);
@@ -589,6 +602,10 @@
   // Note that when QUIC_CRYPTO is in use, only one of the addresses is sent.
   QuicFixedSocketAddress alternate_server_address_ipv6_;
   QuicFixedSocketAddress alternate_server_address_ipv4_;
+  // Connection Id data to send from the server or receive at the client as part
+  // of the preferred address transport parameter.
+  absl::optional<std::pair<QuicConnectionId, QuicUint128>>
+      preferred_address_connection_id_and_token_;
 
   // Stateless reset token used in IETF public reset packet.
   // Uses the stateless_reset_token transport parameter in IETF QUIC.
diff --git a/quic/core/quic_config_test.cc b/quic/core/quic_config_test.cc
index e38975c..2f37835 100644
--- a/quic/core/quic_config_test.cc
+++ b/quic/core/quic_config_test.cc
@@ -4,10 +4,12 @@
 
 #include "quic/core/quic_config.h"
 
+#include <memory>
 #include <string>
 
 #include "quic/core/crypto/crypto_handshake_message.h"
 #include "quic/core/crypto/crypto_protocol.h"
+#include "quic/core/crypto/transport_parameters.h"
 #include "quic/core/quic_constants.h"
 #include "quic/core/quic_packets.h"
 #include "quic/core/quic_time.h"
@@ -475,6 +477,15 @@
   config_.SetRetrySourceConnectionIdToSend(TestConnectionId(0x3333));
   config_.SetMinAckDelayMs(kDefaultMinAckDelayTimeMs);
 
+  QuicIpAddress host;
+  host.FromString("127.0.3.1");
+  QuicSocketAddress kTestServerAddress = QuicSocketAddress(host, 1234);
+  QuicConnectionId new_connection_id = TestConnectionId(5);
+  QuicUint128 new_stateless_reset_token =
+      QuicUtils::GenerateStatelessResetToken(new_connection_id);
+  config_.SetIPv4AlternateServerAddressToSend(
+      kTestServerAddress, new_connection_id, new_stateless_reset_token);
+
   TransportParameters params;
   config_.FillTransportParameters(&params);
 
@@ -508,6 +519,12 @@
       static_cast<uint64_t>(kDefaultMinAckDelayTimeMs) * kNumMicrosPerMilli,
       params.min_ack_delay_us.value());
   EXPECT_TRUE(params.key_update_not_yet_supported);
+
+  EXPECT_EQ(params.preferred_address->ipv4_socket_address, kTestServerAddress);
+  EXPECT_EQ(params.preferred_address->connection_id, new_connection_id);
+  EXPECT_EQ(*reinterpret_cast<QuicUint128*>(
+                &params.preferred_address->stateless_reset_token.front()),
+            new_stateless_reset_token);
 }
 
 TEST_P(QuicConfigTest, ProcessTransportParametersServer) {
@@ -745,6 +762,47 @@
   EXPECT_TRUE(config_.KeyUpdateSupportedRemotely());
 }
 
+TEST_P(QuicConfigTest, SendPreferredIPv4Address) {
+  if (!version_.UsesTls()) {
+    // TransportParameters are only used for QUIC+TLS.
+    return;
+  }
+
+  EXPECT_FALSE(config_.HasReceivedPreferredAddressConnectionIdAndToken());
+
+  TransportParameters params;
+  QuicIpAddress host;
+  host.FromString("::ffff:192.0.2.128");
+  QuicSocketAddress kTestServerAddress = QuicSocketAddress(host, 1234);
+  QuicConnectionId new_connection_id = TestConnectionId(5);
+  QuicUint128 new_stateless_reset_token =
+      QuicUtils::GenerateStatelessResetToken(new_connection_id);
+  auto preferred_address =
+      std::make_unique<TransportParameters::PreferredAddress>();
+  preferred_address->ipv6_socket_address = kTestServerAddress;
+  preferred_address->connection_id = new_connection_id;
+  preferred_address->stateless_reset_token.assign(
+      reinterpret_cast<const char*>(&new_stateless_reset_token),
+      reinterpret_cast<const char*>(&new_stateless_reset_token) +
+          sizeof(new_stateless_reset_token));
+  params.preferred_address = std::move(preferred_address);
+
+  std::string error_details;
+  EXPECT_THAT(config_.ProcessTransportParameters(
+                  params, /* is_resumption = */ false, &error_details),
+              IsQuicNoError());
+
+  EXPECT_TRUE(config_.HasReceivedIPv6AlternateServerAddress());
+  EXPECT_EQ(config_.ReceivedIPv6AlternateServerAddress(), kTestServerAddress);
+  EXPECT_TRUE(config_.HasReceivedPreferredAddressConnectionIdAndToken());
+  const std::pair<QuicConnectionId, QuicUint128>&
+      preferred_address_connection_id_and_token =
+          config_.ReceivedPreferredAddressConnectionIdAndToken();
+  EXPECT_EQ(preferred_address_connection_id_and_token.first, new_connection_id);
+  EXPECT_EQ(preferred_address_connection_id_and_token.second,
+            new_stateless_reset_token);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic