Refactor QuicConfig AlternateServerAddress

QUIC_CRYPTO only allows encoding one alternate server address. QUIC+TLS allows encoding two: one IPv4 and one IPv6. This CL modifies QuicConfig to allow accessing both. This CL does not change any existing behavior because the only existing caller only sets one address today.

gfe-relnote: refactor QuicConfig, no behavior change, not flag protected
PiperOrigin-RevId: 309326620
Change-Id: I980aba15378bb72847a032e97b1081df5ad0b244
diff --git a/quic/core/quic_config.cc b/quic/core/quic_config.cc
index 52de65d..ba7413f 100644
--- a/quic/core/quic_config.cc
+++ b/quic/core/quic_config.cc
@@ -513,7 +513,8 @@
       initial_stream_flow_control_window_bytes_(kSFCW, PRESENCE_OPTIONAL),
       initial_session_flow_control_window_bytes_(kCFCW, PRESENCE_OPTIONAL),
       connection_migration_disabled_(kNCMR, PRESENCE_OPTIONAL),
-      alternate_server_address_(kASAD, PRESENCE_OPTIONAL),
+      alternate_server_address_ipv6_(kASAD, PRESENCE_OPTIONAL),
+      alternate_server_address_ipv4_(kASAD, PRESENCE_OPTIONAL),
       stateless_reset_token_(kSRST, PRESENCE_OPTIONAL),
       max_ack_delay_ms_(kMAD, PRESENCE_OPTIONAL),
       ack_delay_exponent_(kADE, PRESENCE_OPTIONAL),
@@ -861,17 +862,66 @@
   return connection_migration_disabled_.HasReceivedValue();
 }
 
+void QuicConfig::SetIPv6AlternateServerAddressToSend(
+    const QuicSocketAddress& alternate_server_address_ipv6) {
+  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);
+}
+
+bool QuicConfig::HasReceivedIPv6AlternateServerAddress() const {
+  return alternate_server_address_ipv6_.HasReceivedValue();
+}
+
+const QuicSocketAddress& QuicConfig::ReceivedIPv6AlternateServerAddress()
+    const {
+  return alternate_server_address_ipv6_.GetReceivedValue();
+}
+
+void QuicConfig::SetIPv4AlternateServerAddressToSend(
+    const QuicSocketAddress& alternate_server_address_ipv4) {
+  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);
+}
+
+bool QuicConfig::HasReceivedIPv4AlternateServerAddress() const {
+  return alternate_server_address_ipv4_.HasReceivedValue();
+}
+
+const QuicSocketAddress& QuicConfig::ReceivedIPv4AlternateServerAddress()
+    const {
+  return alternate_server_address_ipv4_.GetReceivedValue();
+}
+
 void QuicConfig::SetAlternateServerAddressToSend(
     const QuicSocketAddress& alternate_server_address) {
-  alternate_server_address_.SetSendValue(alternate_server_address);
+  if (alternate_server_address.host().IsIPv6()) {
+    SetIPv6AlternateServerAddressToSend(alternate_server_address);
+  } else if (alternate_server_address.host().IsIPv4()) {
+    SetIPv4AlternateServerAddressToSend(alternate_server_address);
+  } else {
+    QUIC_BUG << "Cannot use SetAlternateServerAddressToSend with "
+             << alternate_server_address;
+  }
 }
 
 bool QuicConfig::HasReceivedAlternateServerAddress() const {
-  return alternate_server_address_.HasReceivedValue();
+  return HasReceivedIPv6AlternateServerAddress() ||
+         HasReceivedIPv4AlternateServerAddress();
 }
 
 const QuicSocketAddress& QuicConfig::ReceivedAlternateServerAddress() const {
-  return alternate_server_address_.GetReceivedValue();
+  if (HasReceivedIPv6AlternateServerAddress()) {
+    return ReceivedIPv6AlternateServerAddress();
+  }
+  return ReceivedIPv4AlternateServerAddress();
 }
 
 void QuicConfig::SetStatelessResetTokenToSend(
@@ -942,7 +992,11 @@
   initial_session_flow_control_window_bytes_.ToHandshakeMessage(out);
   connection_migration_disabled_.ToHandshakeMessage(out);
   connection_options_.ToHandshakeMessage(out);
-  alternate_server_address_.ToHandshakeMessage(out);
+  if (alternate_server_address_ipv6_.HasSendValue()) {
+    alternate_server_address_ipv6_.ToHandshakeMessage(out);
+  } else {
+    alternate_server_address_ipv4_.ToHandshakeMessage(out);
+  }
   stateless_reset_token_.ToHandshakeMessage(out);
 }
 
@@ -990,8 +1044,18 @@
                                                  error_details);
   }
   if (error == QUIC_NO_ERROR) {
-    error = alternate_server_address_.ProcessPeerHello(peer_hello, hello_type,
-                                                       error_details);
+    QuicFixedSocketAddress alternate_server_address(kASAD, PRESENCE_OPTIONAL);
+    error = alternate_server_address.ProcessPeerHello(peer_hello, hello_type,
+                                                      error_details);
+    if (error == QUIC_NO_ERROR && alternate_server_address.HasReceivedValue()) {
+      const QuicSocketAddress& received_address =
+          alternate_server_address.GetReceivedValue();
+      if (received_address.host().IsIPv6()) {
+        alternate_server_address_ipv6_.SetReceivedValue(received_address);
+      } else if (received_address.host().IsIPv4()) {
+        alternate_server_address_ipv4_.SetReceivedValue(received_address);
+      }
+    }
   }
   if (error == QUIC_NO_ERROR) {
     error = stateless_reset_token_.ProcessPeerHello(peer_hello, hello_type,
@@ -1052,13 +1116,16 @@
       connection_migration_disabled_.HasSendValue() &&
       connection_migration_disabled_.GetSendValue() != 0;
 
-  if (alternate_server_address_.HasSendValue()) {
+  if (alternate_server_address_ipv6_.HasSendValue() ||
+      alternate_server_address_ipv4_.HasSendValue()) {
     TransportParameters::PreferredAddress preferred_address;
-    QuicSocketAddress socket_address = alternate_server_address_.GetSendValue();
-    if (socket_address.host().IsIPv6()) {
-      preferred_address.ipv6_socket_address = socket_address;
-    } else {
-      preferred_address.ipv4_socket_address = socket_address;
+    if (alternate_server_address_ipv6_.HasSendValue()) {
+      preferred_address.ipv6_socket_address =
+          alternate_server_address_ipv6_.GetSendValue();
+    }
+    if (alternate_server_address_ipv4_.HasSendValue()) {
+      preferred_address.ipv4_socket_address =
+          alternate_server_address_ipv4_.GetSendValue();
     }
     params->preferred_address =
         std::make_unique<TransportParameters::PreferredAddress>(
@@ -1158,10 +1225,11 @@
 
   if (params.preferred_address != nullptr) {
     if (params.preferred_address->ipv6_socket_address.port() != 0) {
-      alternate_server_address_.SetReceivedValue(
+      alternate_server_address_ipv6_.SetReceivedValue(
           params.preferred_address->ipv6_socket_address);
-    } else if (params.preferred_address->ipv4_socket_address.port() != 0) {
-      alternate_server_address_.SetReceivedValue(
+    }
+    if (params.preferred_address->ipv4_socket_address.port() != 0) {
+      alternate_server_address_ipv4_.SetReceivedValue(
           params.preferred_address->ipv4_socket_address);
     }
   }
diff --git a/quic/core/quic_config.h b/quic/core/quic_config.h
index e39cf78..020c16c 100644
--- a/quic/core/quic_config.h
+++ b/quic/core/quic_config.h
@@ -453,11 +453,22 @@
 
   bool DisableConnectionMigration() const;
 
+  // IPv6 alternate server address.
+  void SetIPv6AlternateServerAddressToSend(
+      const QuicSocketAddress& alternate_server_address_ipv6);
+  bool HasReceivedIPv6AlternateServerAddress() const;
+  const QuicSocketAddress& ReceivedIPv6AlternateServerAddress() const;
+
+  // IPv4 alternate server address.
+  void SetIPv4AlternateServerAddressToSend(
+      const QuicSocketAddress& alternate_server_address_ipv4);
+  bool HasReceivedIPv4AlternateServerAddress() const;
+  const QuicSocketAddress& ReceivedIPv4AlternateServerAddress() const;
+
+  // DEPRECATED: use the variants that specify the address family (IPv4/IPv6).
   void SetAlternateServerAddressToSend(
       const QuicSocketAddress& alternate_server_address);
-
   bool HasReceivedAlternateServerAddress() const;
-
   const QuicSocketAddress& ReceivedAlternateServerAddress() const;
 
   void SetStatelessResetTokenToSend(QuicUint128 stateless_reset_token);
@@ -600,8 +611,11 @@
   // Uses the disable_active_migration transport parameter in IETF QUIC.
   QuicFixedUint32 connection_migration_disabled_;
 
-  // An alternate server address the client could connect to.
-  QuicFixedSocketAddress alternate_server_address_;
+  // Alternate server addresses the client could connect to.
+  // Uses the preferred_address transport parameter in IETF QUIC.
+  // 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_;
 
   // 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 28b56b9..2677e54 100644
--- a/quic/core/quic_config_test.cc
+++ b/quic/core/quic_config_test.cc
@@ -188,7 +188,7 @@
       2 * kInitialStreamFlowControlWindowForTest);
   server_config.SetInitialSessionFlowControlWindowToSend(
       2 * kInitialSessionFlowControlWindowForTest);
-  server_config.SetAlternateServerAddressToSend(kTestServerAddress);
+  server_config.SetIPv4AlternateServerAddressToSend(kTestServerAddress);
   server_config.SetStatelessResetTokenToSend(kTestResetToken);
   server_config.SetMaxAckDelayToSendMs(kTestMaxAckDelayMs);
   CryptoHandshakeMessage msg;
@@ -205,8 +205,9 @@
             2 * kInitialStreamFlowControlWindowForTest);
   EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(),
             2 * kInitialSessionFlowControlWindowForTest);
-  EXPECT_TRUE(config_.HasReceivedAlternateServerAddress());
-  EXPECT_EQ(kTestServerAddress, config_.ReceivedAlternateServerAddress());
+  EXPECT_TRUE(config_.HasReceivedIPv4AlternateServerAddress());
+  EXPECT_EQ(kTestServerAddress, config_.ReceivedIPv4AlternateServerAddress());
+  EXPECT_FALSE(config_.HasReceivedIPv6AlternateServerAddress());
   EXPECT_TRUE(config_.HasReceivedStatelessResetToken());
   EXPECT_EQ(kTestResetToken, config_.ReceivedStatelessResetToken());
   if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) {