More plumbing for fallback configs

This CL adds a 'fallback_config_' member to QuicCryptoServerConfig along with plumbing for setting it and passing it around.  Nobody sets it to anything other than nullptr yet - a subsequent flag-protected change will modify GFE to set it.

gfe-relnote: More no-op-refactoring, not flag-protected.
PiperOrigin-RevId: 239831495
Change-Id: I6fcab2fac6c51180ec994944ebc2cb8850a19663
diff --git a/quic/core/crypto/quic_crypto_server_config.cc b/quic/core/crypto/quic_crypto_server_config.cc
index 253fb0e..da84c24 100644
--- a/quic/core/crypto/quic_crypto_server_config.cc
+++ b/quic/core/crypto/quic_crypto_server_config.cc
@@ -394,7 +394,8 @@
     return nullptr;
   }
 
-  QuicReferenceCountedPointer<Config> config(ParseConfigProtobuf(protobuf));
+  QuicReferenceCountedPointer<Config> config =
+      ParseConfigProtobuf(protobuf, /* is_fallback = */ false);
   if (!config.get()) {
     QUIC_LOG(WARNING) << "Failed to parse server config message";
     return nullptr;
@@ -428,10 +429,12 @@
 
 bool QuicCryptoServerConfig::SetConfigs(
     const std::vector<QuicServerConfigProtobuf>& protobufs,
+    const QuicServerConfigProtobuf* fallback_protobuf,
     const QuicWallTime now) {
   std::vector<QuicReferenceCountedPointer<Config>> parsed_configs;
   for (auto& protobuf : protobufs) {
-    QuicReferenceCountedPointer<Config> config(ParseConfigProtobuf(protobuf));
+    QuicReferenceCountedPointer<Config> config =
+        ParseConfigProtobuf(protobuf, /* is_fallback = */ false);
     if (!config) {
       QUIC_LOG(WARNING) << "Rejecting QUIC configs because of above errors";
       return false;
@@ -440,6 +443,21 @@
     parsed_configs.push_back(config);
   }
 
+  QuicReferenceCountedPointer<Config> fallback_config;
+  if (fallback_protobuf != nullptr) {
+    fallback_config =
+        ParseConfigProtobuf(*fallback_protobuf, /* is_fallback = */ true);
+    if (!fallback_config) {
+      QUIC_LOG(WARNING) << "Rejecting QUIC configs because of above errors";
+      return false;
+    }
+    QUIC_LOG(INFO) << "Fallback config has scid "
+                   << QuicTextUtils::HexEncode(fallback_config->id);
+    parsed_configs.push_back(fallback_config);
+  } else {
+    QUIC_LOG(INFO) << "No fallback config provided";
+  }
+
   if (parsed_configs.empty()) {
     QUIC_LOG(WARNING)
         << "Rejecting QUIC configs because new config list is empty.";
@@ -482,6 +500,7 @@
   }
 
   configs_ = std::move(new_configs);
+  fallback_config_ = fallback_config;
   SelectNewPrimaryConfig(now);
   DCHECK(primary_config_.get());
   DCHECK_EQ(configs_.find(primary_config_->id)->second.get(),
@@ -593,9 +612,9 @@
  private:
   const QuicCryptoServerConfig* config_;
   std::unique_ptr<ProofSource::Details> proof_source_details_;
-  QuicTag key_exchange_type_;
+  const QuicTag key_exchange_type_;
   std::unique_ptr<CryptoHandshakeMessage> out_;
-  std::string public_value_;
+  const std::string public_value_;
   std::unique_ptr<ProcessClientHelloContext> context_;
   const Configs configs_;
 };
@@ -1007,6 +1026,7 @@
     configs->primary = primary_config_;
   }
   configs->requested = GetConfigWithScid(requested_scid);
+  configs->fallback = fallback_config_;
 
   return true;
 }
@@ -1492,7 +1512,8 @@
 
 QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
 QuicCryptoServerConfig::ParseConfigProtobuf(
-    const QuicServerConfigProtobuf& protobuf) {
+    const QuicServerConfigProtobuf& protobuf,
+    bool is_fallback) const {
   std::unique_ptr<CryptoHandshakeMessage> msg =
       CryptoFramer::ParseMessage(protobuf.config());
 
@@ -1585,8 +1606,8 @@
       }
     }
 
-    std::unique_ptr<AsynchronousKeyExchange> ka = key_exchange_source_->Create(
-        config->id, /* is_fallback = */ false, tag, private_key);
+    std::unique_ptr<AsynchronousKeyExchange> ka =
+        key_exchange_source_->Create(config->id, is_fallback, tag, private_key);
     if (!ka) {
       return nullptr;
     }
diff --git a/quic/core/crypto/quic_crypto_server_config.h b/quic/core/crypto/quic_crypto_server_config.h
index 651195b..91fe60d 100644
--- a/quic/core/crypto/quic_crypto_server_config.h
+++ b/quic/core/crypto/quic_crypto_server_config.h
@@ -258,6 +258,7 @@
   // currently the primary config. SetConfigs returns false if any errors were
   // encountered and no changes to the QuicCryptoServerConfig will occur.
   bool SetConfigs(const std::vector<QuicServerConfigProtobuf>& protobufs,
+                  const QuicServerConfigProtobuf* fallback_protobuf,
                   QuicWallTime now);
 
   // SetSourceAddressTokenKeys sets the keys to be tried, in order, when
@@ -519,6 +520,7 @@
   struct Configs {
     QuicReferenceCountedPointer<Config> requested;
     QuicReferenceCountedPointer<Config> primary;
+    QuicReferenceCountedPointer<Config> fallback;
   };
 
   // Get a snapshot of the current configs associated with a handshake.  If this
@@ -724,7 +726,8 @@
   // QuicReferenceCountedPointer<Config> if successful. The caller adopts the
   // reference to the Config. On error, ParseConfigProtobuf returns nullptr.
   QuicReferenceCountedPointer<Config> ParseConfigProtobuf(
-      const QuicServerConfigProtobuf& protobuf);
+      const QuicServerConfigProtobuf& protobuf,
+      bool is_fallback) const;
 
   // NewSourceAddressToken returns a fresh source address token for the given
   // IP address. |cached_network_params| is optional, and can be nullptr.
@@ -867,6 +870,14 @@
   mutable QuicReferenceCountedPointer<Config> primary_config_
       GUARDED_BY(configs_lock_);
 
+  // fallback_config_ points to a Config (which is also in |configs_|) which is
+  // the fallback config, which will be used if the other configs are unuseable
+  // for some reason.
+  //
+  // TODO(b/112548056): This is currently always nullptr.
+  QuicReferenceCountedPointer<Config> fallback_config_
+      GUARDED_BY(configs_lock_);
+
   // next_config_promotion_time_ contains the nearest, future time when an
   // active config will be promoted to primary.
   mutable QuicWallTime next_config_promotion_time_ GUARDED_BY(configs_lock_);
diff --git a/quic/core/crypto/quic_crypto_server_config_test.cc b/quic/core/crypto/quic_crypto_server_config_test.cc
index 61f8006..cedd249 100644
--- a/quic/core/crypto/quic_crypto_server_config_test.cc
+++ b/quic/core/crypto/quic_crypto_server_config_test.cc
@@ -355,7 +355,8 @@
     }
 
     ASSERT_EQ(!has_invalid && !configs.empty(),
-              config_.SetConfigs(protobufs, clock_.WallNow()));
+              config_.SetConfigs(protobufs, /* fallback_protobuf = */ nullptr,
+                                 clock_.WallNow()));
   }
 
  protected: