Introduce draft-28 transport parameters

This CL adds the new transport parameters to TransportParameters.
They will be used in a subsequent CL.

Add unused code

PiperOrigin-RevId: 313678124
Change-Id: Ic04c88f8e3a7275316f67abfd8207d9d1efe15ee
diff --git a/quic/core/crypto/transport_parameters.cc b/quic/core/crypto/transport_parameters.cc
index 45b284b..12c0d0d 100644
--- a/quic/core/crypto/transport_parameters.cc
+++ b/quic/core/crypto/transport_parameters.cc
@@ -46,6 +46,8 @@
   kDisableActiveMigration = 0xc,
   kPreferredAddress = 0xd,
   kActiveConnectionIdLimit = 0xe,
+  kInitialSourceConnectionId = 0xf,
+  kRetrySourceConnectionId = 0x10,
 
   kMaxDatagramFrameSize = 0x20,
 
@@ -104,6 +106,10 @@
       return "preferred_address";
     case TransportParameters::kActiveConnectionIdLimit:
       return "active_connection_id_limit";
+    case TransportParameters::kInitialSourceConnectionId:
+      return "initial_source_connection_id";
+    case TransportParameters::kRetrySourceConnectionId:
+      return "retry_source_connection_id";
     case TransportParameters::kMaxDatagramFrameSize:
       return "max_datagram_frame_size";
     case TransportParameters::kInitialRoundTripTime:
@@ -138,6 +144,8 @@
     case TransportParameters::kDisableActiveMigration:
     case TransportParameters::kPreferredAddress:
     case TransportParameters::kActiveConnectionIdLimit:
+    case TransportParameters::kInitialSourceConnectionId:
+    case TransportParameters::kRetrySourceConnectionId:
     case TransportParameters::kMaxDatagramFrameSize:
     case TransportParameters::kInitialRoundTripTime:
     case TransportParameters::kGoogleConnectionOptions:
@@ -429,6 +437,14 @@
           preferred_address->ToString();
   }
   rv += active_connection_id_limit.ToString(/*for_use_in_list=*/true);
+  if (initial_source_connection_id.has_value()) {
+    rv += " " + TransportParameterIdToString(kInitialSourceConnectionId) + " " +
+          initial_source_connection_id.value().ToString();
+  }
+  if (retry_source_connection_id.has_value()) {
+    rv += " " + TransportParameterIdToString(kRetrySourceConnectionId) + " " +
+          retry_source_connection_id.value().ToString();
+  }
   rv += max_datagram_frame_size.ToString(/*for_use_in_list=*/true);
   rv += initial_round_trip_time_us.ToString(/*for_use_in_list=*/true);
   if (google_connection_options.has_value()) {
@@ -522,6 +538,8 @@
       max_ack_delay(other.max_ack_delay),
       disable_active_migration(other.disable_active_migration),
       active_connection_id_limit(other.active_connection_id_limit),
+      initial_source_connection_id(other.initial_source_connection_id),
+      retry_source_connection_id(other.retry_source_connection_id),
       max_datagram_frame_size(other.max_datagram_frame_size),
       initial_round_trip_time_us(other.initial_round_trip_time_us),
       google_connection_options(other.google_connection_options),
@@ -561,6 +579,8 @@
         disable_active_migration == rhs.disable_active_migration &&
         active_connection_id_limit.value() ==
             rhs.active_connection_id_limit.value() &&
+        initial_source_connection_id == rhs.initial_source_connection_id &&
+        retry_source_connection_id == rhs.retry_source_connection_id &&
         max_datagram_frame_size.value() ==
             rhs.max_datagram_frame_size.value() &&
         initial_round_trip_time_us.value() ==
@@ -602,7 +622,7 @@
   }
   if (perspective == Perspective::IS_CLIENT &&
       original_destination_connection_id.has_value()) {
-    *error_details = "Client cannot send original connection ID";
+    *error_details = "Client cannot send original_destination_connection_id";
     return false;
   }
   if (!stateless_reset_token.empty() &&
@@ -629,6 +649,11 @@
     *error_details = "Internal preferred address family failure";
     return false;
   }
+  if (perspective == Perspective::IS_CLIENT &&
+      retry_source_connection_id.has_value()) {
+    *error_details = "Client cannot send retry_source_connection_id";
+    return false;
+  }
   for (const auto& kv : custom_parameters) {
     if (TransportParameterIdIsKnown(kv.first)) {
       *error_details = quiche::QuicheStrCat(
@@ -715,6 +740,8 @@
       kTypeAndValueLength +               // disable_active_migration
       kPreferredAddressParameterLength +  // preferred_address
       kIntegerParameterLength +           // active_connection_id_limit
+      kConnectionIdParameterLength +      // initial_source_connection_id
+      kConnectionIdParameterLength +      // retry_source_connection_id
       kIntegerParameterLength +           // max_datagram_frame_size
       kIntegerParameterLength +           // initial_round_trip_time_us
       kTypeAndValueLength +               // google_connection_options
@@ -868,6 +895,42 @@
     }
   }
 
+  // initial_source_connection_id
+  if (in.initial_source_connection_id.has_value()) {
+    QuicConnectionId initial_source_connection_id =
+        in.initial_source_connection_id.value();
+    if (!WriteTransportParameterId(
+            &writer, TransportParameters::kInitialSourceConnectionId,
+            version) ||
+        !WriteTransportParameterStringPiece(
+            &writer,
+            quiche::QuicheStringPiece(initial_source_connection_id.data(),
+                                      initial_source_connection_id.length()),
+            version)) {
+      QUIC_BUG << "Failed to write initial_source_connection_id "
+               << initial_source_connection_id << " for " << in;
+      return false;
+    }
+  }
+
+  // retry_source_connection_id
+  if (in.retry_source_connection_id.has_value()) {
+    DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
+    QuicConnectionId retry_source_connection_id =
+        in.retry_source_connection_id.value();
+    if (!WriteTransportParameterId(
+            &writer, TransportParameters::kRetrySourceConnectionId, version) ||
+        !WriteTransportParameterStringPiece(
+            &writer,
+            quiche::QuicheStringPiece(retry_source_connection_id.data(),
+                                      retry_source_connection_id.length()),
+            version)) {
+      QUIC_BUG << "Failed to write retry_source_connection_id "
+               << retry_source_connection_id << " for " << in;
+      return false;
+    }
+  }
+
   // Google-specific connection options.
   if (in.google_connection_options.has_value()) {
     static_assert(sizeof(in.google_connection_options.value().front()) == 4,
@@ -1193,6 +1256,48 @@
         parse_success =
             out->active_connection_id_limit.Read(&value_reader, error_details);
         break;
+      case TransportParameters::kInitialSourceConnectionId: {
+        if (out->initial_source_connection_id.has_value()) {
+          *error_details = "Received a second initial_source_connection_id";
+          return false;
+        }
+        const size_t connection_id_length = value_reader.BytesRemaining();
+        if (!QuicUtils::IsConnectionIdLengthValidForVersion(
+                connection_id_length, version.transport_version)) {
+          *error_details = quiche::QuicheStrCat(
+              "Received initial_source_connection_id of invalid length ",
+              connection_id_length);
+          return false;
+        }
+        QuicConnectionId initial_source_connection_id;
+        if (!value_reader.ReadConnectionId(&initial_source_connection_id,
+                                           connection_id_length)) {
+          *error_details = "Failed to read initial_source_connection_id";
+          return false;
+        }
+        out->initial_source_connection_id = initial_source_connection_id;
+      } break;
+      case TransportParameters::kRetrySourceConnectionId: {
+        if (out->retry_source_connection_id.has_value()) {
+          *error_details = "Received a second retry_source_connection_id";
+          return false;
+        }
+        const size_t connection_id_length = value_reader.BytesRemaining();
+        if (!QuicUtils::IsConnectionIdLengthValidForVersion(
+                connection_id_length, version.transport_version)) {
+          *error_details = quiche::QuicheStrCat(
+              "Received retry_source_connection_id of invalid length ",
+              connection_id_length);
+          return false;
+        }
+        QuicConnectionId retry_source_connection_id;
+        if (!value_reader.ReadConnectionId(&retry_source_connection_id,
+                                           connection_id_length)) {
+          *error_details = "Failed to read retry_source_connection_id";
+          return false;
+        }
+        out->retry_source_connection_id = retry_source_connection_id;
+      } break;
       case TransportParameters::kMaxDatagramFrameSize:
         parse_success =
             out->max_datagram_frame_size.Read(&value_reader, error_details);
diff --git a/quic/core/crypto/transport_parameters.h b/quic/core/crypto/transport_parameters.h
index 1d91db3..80c905c 100644
--- a/quic/core/crypto/transport_parameters.h
+++ b/quic/core/crypto/transport_parameters.h
@@ -180,6 +180,14 @@
   // to store.
   IntegerParameter active_connection_id_limit;
 
+  // The value that the endpoint included in the Source Connection ID field of
+  // the first Initial packet it sent.
+  quiche::QuicheOptional<QuicConnectionId> initial_source_connection_id;
+
+  // The value that the server included in the Source Connection ID field of a
+  // Retry packet it sent.
+  quiche::QuicheOptional<QuicConnectionId> retry_source_connection_id;
+
   // Indicates support for the DATAGRAM frame and the maximum frame size that
   // the sender accepts. See draft-ietf-quic-datagram.
   IntegerParameter max_datagram_frame_size;
diff --git a/quic/core/crypto/transport_parameters_test.cc b/quic/core/crypto/transport_parameters_test.cc
index 628c19f..a3fc084 100644
--- a/quic/core/crypto/transport_parameters_test.cc
+++ b/quic/core/crypto/transport_parameters_test.cc
@@ -56,6 +56,14 @@
   return TestConnectionId(0x1337);
 }
 
+QuicConnectionId CreateFakeInitialSourceConnectionId() {
+  return TestConnectionId(0x2345);
+}
+
+QuicConnectionId CreateFakeRetrySourceConnectionId() {
+  return TestConnectionId(0x9876);
+}
+
 QuicConnectionId CreateFakePreferredConnectionId() {
   return TestConnectionId(0xBEEF);
 }
@@ -222,6 +230,23 @@
   EXPECT_EQ(orig_params, new_params);
   EXPECT_TRUE(orig_params == new_params);
   EXPECT_FALSE(orig_params != new_params);
+
+  // Test comparison on connection IDs.
+  orig_params.initial_source_connection_id =
+      CreateFakeInitialSourceConnectionId();
+  new_params.initial_source_connection_id = QuicheNullOpt;
+  EXPECT_NE(orig_params, new_params);
+  EXPECT_FALSE(orig_params == new_params);
+  EXPECT_TRUE(orig_params != new_params);
+  new_params.initial_source_connection_id = TestConnectionId(0xbadbad);
+  EXPECT_NE(orig_params, new_params);
+  EXPECT_FALSE(orig_params == new_params);
+  EXPECT_TRUE(orig_params != new_params);
+  new_params.initial_source_connection_id =
+      CreateFakeInitialSourceConnectionId();
+  EXPECT_EQ(orig_params, new_params);
+  EXPECT_TRUE(orig_params == new_params);
+  EXPECT_FALSE(orig_params != new_params);
 }
 
 TEST_P(TransportParametersTest, CopyConstructor) {
@@ -250,6 +275,9 @@
   orig_params.preferred_address = CreateFakePreferredAddress();
   orig_params.active_connection_id_limit.set_value(
       kFakeActiveConnectionIdLimit);
+  orig_params.initial_source_connection_id =
+      CreateFakeInitialSourceConnectionId();
+  orig_params.retry_source_connection_id = CreateFakeRetrySourceConnectionId();
   orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime);
   orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
   orig_params.user_agent_id = CreateFakeUserAgentId();
@@ -280,6 +308,8 @@
   orig_params.disable_active_migration = kFakeDisableMigration;
   orig_params.active_connection_id_limit.set_value(
       kFakeActiveConnectionIdLimit);
+  orig_params.initial_source_connection_id =
+      CreateFakeInitialSourceConnectionId();
   orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime);
   orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
   orig_params.user_agent_id = CreateFakeUserAgentId();
@@ -326,6 +356,9 @@
   orig_params.preferred_address = CreateFakePreferredAddress();
   orig_params.active_connection_id_limit.set_value(
       kFakeActiveConnectionIdLimit);
+  orig_params.initial_source_connection_id =
+      CreateFakeInitialSourceConnectionId();
+  orig_params.retry_source_connection_id = CreateFakeRetrySourceConnectionId();
   orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
 
   std::vector<uint8_t> serialized;
@@ -454,7 +487,7 @@
 TEST_P(TransportParametersTest, ParseClientParams) {
   // clang-format off
   const uint8_t kClientParamsOld[] = {
-      0x00, 0x6a,              // length of the parameters array that follows
+      0x00, 0x76,              // length of the parameters array that follows
       // max_idle_timeout
       0x00, 0x01,  // parameter id
       0x00, 0x02,  // length
@@ -502,6 +535,10 @@
       0x00, 0x0e,  // parameter id
       0x00, 0x01,  // length
       0x34,  // value
+      // initial_source_connection_id
+      0x00, 0x0f,  // parameter id
+      0x00, 0x08,  // length
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45,
       // initial_round_trip_time_us
       0x31, 0x27,  // parameter id
       0x00, 0x01,  // length
@@ -569,6 +606,10 @@
       0x0e,  // parameter id
       0x01,  // length
       0x34,  // value
+      // initial_source_connection_id
+      0x0f,  // parameter id
+      0x08,  // length
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45,
       // initial_round_trip_time_us
       0x71, 0x27,  // parameter id
       0x01,  // length
@@ -627,6 +668,10 @@
   EXPECT_EQ(kFakeDisableMigration, new_params.disable_active_migration);
   EXPECT_EQ(kFakeActiveConnectionIdLimit,
             new_params.active_connection_id_limit.value());
+  ASSERT_TRUE(new_params.initial_source_connection_id.has_value());
+  EXPECT_EQ(CreateFakeInitialSourceConnectionId(),
+            new_params.initial_source_connection_id.value());
+  EXPECT_FALSE(new_params.retry_source_connection_id.has_value());
   EXPECT_EQ(kFakeInitialRoundTripTime,
             new_params.initial_round_trip_time_us.value());
   ASSERT_TRUE(new_params.google_connection_options.has_value());
@@ -801,7 +846,7 @@
 TEST_P(TransportParametersTest, ParseServerParams) {
   // clang-format off
   const uint8_t kServerParamsOld[] = {
-      0x00, 0xb7,  // length of parameters array that follows
+      0x00, 0xcf,  // length of parameters array that follows
       // original_destination_connection_id
       0x00, 0x00,  // parameter id
       0x00, 0x08,  // length
@@ -870,6 +915,14 @@
       0x00, 0x0e,  // parameter id
       0x00, 0x01,  // length
       0x34,  // value
+      // initial_source_connection_id
+      0x00, 0x0f,  // parameter id
+      0x00, 0x08,  // length
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45,
+      // retry_source_connection_id
+      0x00, 0x10,  // parameter id
+      0x00, 0x08,  // length
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x76,
       // google_connection_options
       0x31, 0x28,  // parameter id
       0x00, 0x0c,  // length
@@ -953,6 +1006,14 @@
       0x0e,  // parameter id
       0x01,  // length
       0x34,  // value
+      // initial_source_connection_id
+      0x0f,  // parameter id
+      0x08,  // length
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45,
+      // retry_source_connection_id
+      0x10,  // parameter id
+      0x08,  // length
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x76,
       // google_connection_options
       0x71, 0x28,  // parameter id
       0x0c,  // length
@@ -1019,6 +1080,12 @@
             new_params.preferred_address->stateless_reset_token);
   EXPECT_EQ(kFakeActiveConnectionIdLimit,
             new_params.active_connection_id_limit.value());
+  ASSERT_TRUE(new_params.initial_source_connection_id.has_value());
+  EXPECT_EQ(CreateFakeInitialSourceConnectionId(),
+            new_params.initial_source_connection_id.value());
+  ASSERT_TRUE(new_params.retry_source_connection_id.has_value());
+  EXPECT_EQ(CreateFakeRetrySourceConnectionId(),
+            new_params.retry_source_connection_id.value());
   ASSERT_TRUE(new_params.google_connection_options.has_value());
   EXPECT_EQ(CreateFakeGoogleConnectionOptions(),
             new_params.google_connection_options.value());