Project import generated by Copybara.

PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/quic_config.cc b/quic/core/quic_config.cc
new file mode 100644
index 0000000..e53719c
--- /dev/null
+++ b/quic/core/quic_config.cc
@@ -0,0 +1,823 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/quic_config.h"
+
+#include <algorithm>
+
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+// Reads the value corresponding to |name_| from |msg| into |out|. If the
+// |name_| is absent in |msg| and |presence| is set to OPTIONAL |out| is set
+// to |default_value|.
+QuicErrorCode ReadUint32(const CryptoHandshakeMessage& msg,
+                         QuicTag tag,
+                         QuicConfigPresence presence,
+                         uint32_t default_value,
+                         uint32_t* out,
+                         QuicString* error_details) {
+  DCHECK(error_details != nullptr);
+  QuicErrorCode error = msg.GetUint32(tag, out);
+  switch (error) {
+    case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+      if (presence == PRESENCE_REQUIRED) {
+        *error_details = "Missing " + QuicTagToString(tag);
+        break;
+      }
+      error = QUIC_NO_ERROR;
+      *out = default_value;
+      break;
+    case QUIC_NO_ERROR:
+      break;
+    default:
+      *error_details = "Bad " + QuicTagToString(tag);
+      break;
+  }
+  return error;
+}
+
+QuicConfigValue::QuicConfigValue(QuicTag tag, QuicConfigPresence presence)
+    : tag_(tag), presence_(presence) {}
+QuicConfigValue::~QuicConfigValue() {}
+
+QuicNegotiableValue::QuicNegotiableValue(QuicTag tag,
+                                         QuicConfigPresence presence)
+    : QuicConfigValue(tag, presence), negotiated_(false) {}
+QuicNegotiableValue::~QuicNegotiableValue() {}
+
+QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag,
+                                           QuicConfigPresence presence)
+    : QuicNegotiableValue(tag, presence),
+      max_value_(0),
+      default_value_(0),
+      negotiated_value_(0) {}
+QuicNegotiableUint32::~QuicNegotiableUint32() {}
+
+void QuicNegotiableUint32::set(uint32_t max, uint32_t default_value) {
+  DCHECK_LE(default_value, max);
+  max_value_ = max;
+  default_value_ = default_value;
+}
+
+uint32_t QuicNegotiableUint32::GetUint32() const {
+  if (negotiated()) {
+    return negotiated_value_;
+  }
+  return default_value_;
+}
+
+// Returns the maximum value negotiable.
+uint32_t QuicNegotiableUint32::GetMax() const {
+  return max_value_;
+}
+
+void QuicNegotiableUint32::ToHandshakeMessage(
+    CryptoHandshakeMessage* out) const {
+  if (negotiated()) {
+    out->SetValue(tag_, negotiated_value_);
+  } else {
+    out->SetValue(tag_, max_value_);
+  }
+}
+
+QuicErrorCode QuicNegotiableUint32::ProcessPeerHello(
+    const CryptoHandshakeMessage& peer_hello,
+    HelloType hello_type,
+    QuicString* error_details) {
+  DCHECK(!negotiated());
+  DCHECK(error_details != nullptr);
+  uint32_t value;
+  QuicErrorCode error = ReadUint32(peer_hello, tag_, presence_, default_value_,
+                                   &value, error_details);
+  if (error != QUIC_NO_ERROR) {
+    return error;
+  }
+  return ReceiveValue(value, hello_type, error_details);
+}
+
+QuicErrorCode QuicNegotiableUint32::ReceiveValue(uint32_t value,
+                                                 HelloType hello_type,
+                                                 QuicString* error_details) {
+  if (hello_type == SERVER && value > max_value_) {
+    *error_details = "Invalid value received for " + QuicTagToString(tag_);
+    return QUIC_INVALID_NEGOTIATED_VALUE;
+  }
+
+  set_negotiated(true);
+  negotiated_value_ = std::min(value, max_value_);
+  return QUIC_NO_ERROR;
+}
+
+QuicFixedUint32::QuicFixedUint32(QuicTag tag, QuicConfigPresence presence)
+    : QuicConfigValue(tag, presence),
+      has_send_value_(false),
+      has_receive_value_(false) {}
+QuicFixedUint32::~QuicFixedUint32() {}
+
+bool QuicFixedUint32::HasSendValue() const {
+  return has_send_value_;
+}
+
+uint32_t QuicFixedUint32::GetSendValue() const {
+  QUIC_BUG_IF(!has_send_value_)
+      << "No send value to get for tag:" << QuicTagToString(tag_);
+  return send_value_;
+}
+
+void QuicFixedUint32::SetSendValue(uint32_t value) {
+  has_send_value_ = true;
+  send_value_ = value;
+}
+
+bool QuicFixedUint32::HasReceivedValue() const {
+  return has_receive_value_;
+}
+
+uint32_t QuicFixedUint32::GetReceivedValue() const {
+  QUIC_BUG_IF(!has_receive_value_)
+      << "No receive value to get for tag:" << QuicTagToString(tag_);
+  return receive_value_;
+}
+
+void QuicFixedUint32::SetReceivedValue(uint32_t value) {
+  has_receive_value_ = true;
+  receive_value_ = value;
+}
+
+void QuicFixedUint32::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
+  if (has_send_value_) {
+    out->SetValue(tag_, send_value_);
+  }
+}
+
+QuicErrorCode QuicFixedUint32::ProcessPeerHello(
+    const CryptoHandshakeMessage& peer_hello,
+    HelloType hello_type,
+    QuicString* error_details) {
+  DCHECK(error_details != nullptr);
+  QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value_);
+  switch (error) {
+    case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+      if (presence_ == PRESENCE_OPTIONAL) {
+        return QUIC_NO_ERROR;
+      }
+      *error_details = "Missing " + QuicTagToString(tag_);
+      break;
+    case QUIC_NO_ERROR:
+      has_receive_value_ = true;
+      break;
+    default:
+      *error_details = "Bad " + QuicTagToString(tag_);
+      break;
+  }
+  return error;
+}
+
+QuicFixedUint128::QuicFixedUint128(QuicTag tag, QuicConfigPresence presence)
+    : QuicConfigValue(tag, presence),
+      has_send_value_(false),
+      has_receive_value_(false) {}
+QuicFixedUint128::~QuicFixedUint128() {}
+
+bool QuicFixedUint128::HasSendValue() const {
+  return has_send_value_;
+}
+
+QuicUint128 QuicFixedUint128::GetSendValue() const {
+  QUIC_BUG_IF(!has_send_value_)
+      << "No send value to get for tag:" << QuicTagToString(tag_);
+  return send_value_;
+}
+
+void QuicFixedUint128::SetSendValue(QuicUint128 value) {
+  has_send_value_ = true;
+  send_value_ = value;
+}
+
+bool QuicFixedUint128::HasReceivedValue() const {
+  return has_receive_value_;
+}
+
+QuicUint128 QuicFixedUint128::GetReceivedValue() const {
+  QUIC_BUG_IF(!has_receive_value_)
+      << "No receive value to get for tag:" << QuicTagToString(tag_);
+  return receive_value_;
+}
+
+void QuicFixedUint128::SetReceivedValue(QuicUint128 value) {
+  has_receive_value_ = true;
+  receive_value_ = value;
+}
+
+void QuicFixedUint128::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
+  if (has_send_value_) {
+    out->SetValue(tag_, send_value_);
+  }
+}
+
+QuicErrorCode QuicFixedUint128::ProcessPeerHello(
+    const CryptoHandshakeMessage& peer_hello,
+    HelloType hello_type,
+    QuicString* error_details) {
+  DCHECK(error_details != nullptr);
+  QuicErrorCode error = peer_hello.GetUint128(tag_, &receive_value_);
+  switch (error) {
+    case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+      if (presence_ == PRESENCE_OPTIONAL) {
+        return QUIC_NO_ERROR;
+      }
+      *error_details = "Missing " + QuicTagToString(tag_);
+      break;
+    case QUIC_NO_ERROR:
+      has_receive_value_ = true;
+      break;
+    default:
+      *error_details = "Bad " + QuicTagToString(tag_);
+      break;
+  }
+  return error;
+}
+
+QuicFixedTagVector::QuicFixedTagVector(QuicTag name,
+                                       QuicConfigPresence presence)
+    : QuicConfigValue(name, presence),
+      has_send_values_(false),
+      has_receive_values_(false) {}
+
+QuicFixedTagVector::QuicFixedTagVector(const QuicFixedTagVector& other) =
+    default;
+
+QuicFixedTagVector::~QuicFixedTagVector() {}
+
+bool QuicFixedTagVector::HasSendValues() const {
+  return has_send_values_;
+}
+
+QuicTagVector QuicFixedTagVector::GetSendValues() const {
+  QUIC_BUG_IF(!has_send_values_)
+      << "No send values to get for tag:" << QuicTagToString(tag_);
+  return send_values_;
+}
+
+void QuicFixedTagVector::SetSendValues(const QuicTagVector& values) {
+  has_send_values_ = true;
+  send_values_ = values;
+}
+
+bool QuicFixedTagVector::HasReceivedValues() const {
+  return has_receive_values_;
+}
+
+QuicTagVector QuicFixedTagVector::GetReceivedValues() const {
+  QUIC_BUG_IF(!has_receive_values_)
+      << "No receive value to get for tag:" << QuicTagToString(tag_);
+  return receive_values_;
+}
+
+void QuicFixedTagVector::SetReceivedValues(const QuicTagVector& values) {
+  has_receive_values_ = true;
+  receive_values_ = values;
+}
+
+void QuicFixedTagVector::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
+  if (has_send_values_) {
+    out->SetVector(tag_, send_values_);
+  }
+}
+
+QuicErrorCode QuicFixedTagVector::ProcessPeerHello(
+    const CryptoHandshakeMessage& peer_hello,
+    HelloType hello_type,
+    QuicString* error_details) {
+  DCHECK(error_details != nullptr);
+  QuicTagVector values;
+  QuicErrorCode error = peer_hello.GetTaglist(tag_, &values);
+  switch (error) {
+    case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+      if (presence_ == PRESENCE_OPTIONAL) {
+        return QUIC_NO_ERROR;
+      }
+      *error_details = "Missing " + QuicTagToString(tag_);
+      break;
+    case QUIC_NO_ERROR:
+      QUIC_DVLOG(1) << "Received Connection Option tags from receiver.";
+      has_receive_values_ = true;
+      receive_values_.insert(receive_values_.end(), values.begin(),
+                             values.end());
+      break;
+    default:
+      *error_details = "Bad " + QuicTagToString(tag_);
+      break;
+  }
+  return error;
+}
+
+QuicFixedSocketAddress::QuicFixedSocketAddress(QuicTag tag,
+                                               QuicConfigPresence presence)
+    : QuicConfigValue(tag, presence),
+      has_send_value_(false),
+      has_receive_value_(false) {}
+
+QuicFixedSocketAddress::~QuicFixedSocketAddress() {}
+
+bool QuicFixedSocketAddress::HasSendValue() const {
+  return has_send_value_;
+}
+
+const QuicSocketAddress& QuicFixedSocketAddress::GetSendValue() const {
+  QUIC_BUG_IF(!has_send_value_)
+      << "No send value to get for tag:" << QuicTagToString(tag_);
+  return send_value_;
+}
+
+void QuicFixedSocketAddress::SetSendValue(const QuicSocketAddress& value) {
+  has_send_value_ = true;
+  send_value_ = value;
+}
+
+bool QuicFixedSocketAddress::HasReceivedValue() const {
+  return has_receive_value_;
+}
+
+const QuicSocketAddress& QuicFixedSocketAddress::GetReceivedValue() const {
+  QUIC_BUG_IF(!has_receive_value_)
+      << "No receive value to get for tag:" << QuicTagToString(tag_);
+  return receive_value_;
+}
+
+void QuicFixedSocketAddress::SetReceivedValue(const QuicSocketAddress& value) {
+  has_receive_value_ = true;
+  receive_value_ = value;
+}
+
+void QuicFixedSocketAddress::ToHandshakeMessage(
+    CryptoHandshakeMessage* out) const {
+  if (has_send_value_) {
+    QuicSocketAddressCoder address_coder(send_value_);
+    out->SetStringPiece(tag_, address_coder.Encode());
+  }
+}
+
+QuicErrorCode QuicFixedSocketAddress::ProcessPeerHello(
+    const CryptoHandshakeMessage& peer_hello,
+    HelloType hello_type,
+    QuicString* error_details) {
+  QuicStringPiece address;
+  if (!peer_hello.GetStringPiece(tag_, &address)) {
+    if (presence_ == PRESENCE_REQUIRED) {
+      *error_details = "Missing " + QuicTagToString(tag_);
+      return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+    }
+  } else {
+    QuicSocketAddressCoder address_coder;
+    if (address_coder.Decode(address.data(), address.length())) {
+      SetReceivedValue(
+          QuicSocketAddress(address_coder.ip(), address_coder.port()));
+    }
+  }
+  return QUIC_NO_ERROR;
+}
+
+QuicConfig::QuicConfig()
+    : max_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
+      max_idle_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
+      max_undecryptable_packets_(0),
+      connection_options_(kCOPT, PRESENCE_OPTIONAL),
+      client_connection_options_(kCLOP, PRESENCE_OPTIONAL),
+      idle_network_timeout_seconds_(kICSL, PRESENCE_REQUIRED),
+      silent_close_(kSCLS, PRESENCE_OPTIONAL),
+      max_incoming_dynamic_streams_(kMIDS, PRESENCE_REQUIRED),
+      bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL),
+      initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL),
+      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),
+      support_max_header_list_size_(kSMHL, PRESENCE_OPTIONAL),
+      stateless_reset_token_(kSRST, PRESENCE_OPTIONAL) {
+  SetDefaults();
+}
+
+QuicConfig::QuicConfig(const QuicConfig& other) = default;
+
+QuicConfig::~QuicConfig() {}
+
+bool QuicConfig::SetInitialReceivedConnectionOptions(
+    const QuicTagVector& tags) {
+  if (HasReceivedConnectionOptions()) {
+    // If we have already received connection options (via handshake or due to
+    // a previous call), don't re-initialize.
+    return false;
+  }
+  connection_options_.SetReceivedValues(tags);
+  return true;
+}
+
+void QuicConfig::SetConnectionOptionsToSend(
+    const QuicTagVector& connection_options) {
+  connection_options_.SetSendValues(connection_options);
+}
+
+bool QuicConfig::HasReceivedConnectionOptions() const {
+  return connection_options_.HasReceivedValues();
+}
+
+QuicTagVector QuicConfig::ReceivedConnectionOptions() const {
+  return connection_options_.GetReceivedValues();
+}
+
+bool QuicConfig::HasSendConnectionOptions() const {
+  return connection_options_.HasSendValues();
+}
+
+QuicTagVector QuicConfig::SendConnectionOptions() const {
+  return connection_options_.GetSendValues();
+}
+
+bool QuicConfig::HasClientSentConnectionOption(QuicTag tag,
+                                               Perspective perspective) const {
+  if (perspective == Perspective::IS_SERVER) {
+    if (HasReceivedConnectionOptions() &&
+        ContainsQuicTag(ReceivedConnectionOptions(), tag)) {
+      return true;
+    }
+  } else if (HasSendConnectionOptions() &&
+             ContainsQuicTag(SendConnectionOptions(), tag)) {
+    return true;
+  }
+  return false;
+}
+
+void QuicConfig::SetClientConnectionOptions(
+    const QuicTagVector& client_connection_options) {
+  client_connection_options_.SetSendValues(client_connection_options);
+}
+
+bool QuicConfig::HasClientRequestedIndependentOption(
+    QuicTag tag,
+    Perspective perspective) const {
+  if (perspective == Perspective::IS_SERVER) {
+    return (HasReceivedConnectionOptions() &&
+            ContainsQuicTag(ReceivedConnectionOptions(), tag));
+  }
+
+  return (client_connection_options_.HasSendValues() &&
+          ContainsQuicTag(client_connection_options_.GetSendValues(), tag));
+}
+
+void QuicConfig::SetIdleNetworkTimeout(
+    QuicTime::Delta max_idle_network_timeout,
+    QuicTime::Delta default_idle_network_timeout) {
+  idle_network_timeout_seconds_.set(
+      static_cast<uint32_t>(max_idle_network_timeout.ToSeconds()),
+      static_cast<uint32_t>(default_idle_network_timeout.ToSeconds()));
+}
+
+QuicTime::Delta QuicConfig::IdleNetworkTimeout() const {
+  return QuicTime::Delta::FromSeconds(
+      idle_network_timeout_seconds_.GetUint32());
+}
+
+// TODO(ianswett) Use this for silent close on mobile, or delete.
+QUIC_UNUSED void QuicConfig::SetSilentClose(bool silent_close) {
+  silent_close_.set(silent_close ? 1 : 0, silent_close ? 1 : 0);
+}
+
+bool QuicConfig::SilentClose() const {
+  return silent_close_.GetUint32() > 0;
+}
+
+void QuicConfig::SetMaxIncomingDynamicStreamsToSend(
+    uint32_t max_incoming_dynamic_streams) {
+  max_incoming_dynamic_streams_.SetSendValue(max_incoming_dynamic_streams);
+}
+
+uint32_t QuicConfig::GetMaxIncomingDynamicStreamsToSend() {
+  return max_incoming_dynamic_streams_.GetSendValue();
+}
+
+bool QuicConfig::HasReceivedMaxIncomingDynamicStreams() {
+  return max_incoming_dynamic_streams_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedMaxIncomingDynamicStreams() {
+  return max_incoming_dynamic_streams_.GetReceivedValue();
+}
+
+bool QuicConfig::HasSetBytesForConnectionIdToSend() const {
+  return bytes_for_connection_id_.HasSendValue();
+}
+
+void QuicConfig::SetBytesForConnectionIdToSend(uint32_t bytes) {
+  bytes_for_connection_id_.SetSendValue(bytes);
+}
+
+bool QuicConfig::HasReceivedBytesForConnectionId() const {
+  return bytes_for_connection_id_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedBytesForConnectionId() const {
+  return bytes_for_connection_id_.GetReceivedValue();
+}
+
+void QuicConfig::SetInitialRoundTripTimeUsToSend(uint32_t rtt) {
+  initial_round_trip_time_us_.SetSendValue(rtt);
+}
+
+bool QuicConfig::HasReceivedInitialRoundTripTimeUs() const {
+  return initial_round_trip_time_us_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedInitialRoundTripTimeUs() const {
+  return initial_round_trip_time_us_.GetReceivedValue();
+}
+
+bool QuicConfig::HasInitialRoundTripTimeUsToSend() const {
+  return initial_round_trip_time_us_.HasSendValue();
+}
+
+uint32_t QuicConfig::GetInitialRoundTripTimeUsToSend() const {
+  return initial_round_trip_time_us_.GetSendValue();
+}
+
+void QuicConfig::SetInitialStreamFlowControlWindowToSend(
+    uint32_t window_bytes) {
+  if (window_bytes < kMinimumFlowControlSendWindow) {
+    QUIC_BUG << "Initial stream flow control receive window (" << window_bytes
+             << ") cannot be set lower than default ("
+             << kMinimumFlowControlSendWindow << ").";
+    window_bytes = kMinimumFlowControlSendWindow;
+  }
+  initial_stream_flow_control_window_bytes_.SetSendValue(window_bytes);
+}
+
+uint32_t QuicConfig::GetInitialStreamFlowControlWindowToSend() const {
+  return initial_stream_flow_control_window_bytes_.GetSendValue();
+}
+
+bool QuicConfig::HasReceivedInitialStreamFlowControlWindowBytes() const {
+  return initial_stream_flow_control_window_bytes_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedInitialStreamFlowControlWindowBytes() const {
+  return initial_stream_flow_control_window_bytes_.GetReceivedValue();
+}
+
+void QuicConfig::SetInitialSessionFlowControlWindowToSend(
+    uint32_t window_bytes) {
+  if (window_bytes < kMinimumFlowControlSendWindow) {
+    QUIC_BUG << "Initial session flow control receive window (" << window_bytes
+             << ") cannot be set lower than default ("
+             << kMinimumFlowControlSendWindow << ").";
+    window_bytes = kMinimumFlowControlSendWindow;
+  }
+  initial_session_flow_control_window_bytes_.SetSendValue(window_bytes);
+}
+
+uint32_t QuicConfig::GetInitialSessionFlowControlWindowToSend() const {
+  return initial_session_flow_control_window_bytes_.GetSendValue();
+}
+
+bool QuicConfig::HasReceivedInitialSessionFlowControlWindowBytes() const {
+  return initial_session_flow_control_window_bytes_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedInitialSessionFlowControlWindowBytes() const {
+  return initial_session_flow_control_window_bytes_.GetReceivedValue();
+}
+
+void QuicConfig::SetDisableConnectionMigration() {
+  connection_migration_disabled_.SetSendValue(1);
+}
+
+bool QuicConfig::DisableConnectionMigration() const {
+  return connection_migration_disabled_.HasReceivedValue();
+}
+
+void QuicConfig::SetAlternateServerAddressToSend(
+    const QuicSocketAddress& alternate_server_address) {
+  alternate_server_address_.SetSendValue(alternate_server_address);
+}
+
+bool QuicConfig::HasReceivedAlternateServerAddress() const {
+  return alternate_server_address_.HasReceivedValue();
+}
+
+const QuicSocketAddress& QuicConfig::ReceivedAlternateServerAddress() const {
+  return alternate_server_address_.GetReceivedValue();
+}
+
+void QuicConfig::SetSupportMaxHeaderListSize() {
+  support_max_header_list_size_.SetSendValue(1);
+}
+
+bool QuicConfig::SupportMaxHeaderListSize() const {
+  return support_max_header_list_size_.HasReceivedValue();
+}
+
+void QuicConfig::SetStatelessResetTokenToSend(
+    QuicUint128 stateless_reset_token) {
+  stateless_reset_token_.SetSendValue(stateless_reset_token);
+}
+
+bool QuicConfig::HasReceivedStatelessResetToken() const {
+  return stateless_reset_token_.HasReceivedValue();
+}
+
+QuicUint128 QuicConfig::ReceivedStatelessResetToken() const {
+  return stateless_reset_token_.GetReceivedValue();
+}
+
+bool QuicConfig::negotiated() const {
+  // TODO(ianswett): Add the negotiated parameters once and iterate over all
+  // of them in negotiated, ToHandshakeMessage, and ProcessPeerHello.
+  return idle_network_timeout_seconds_.negotiated();
+}
+
+void QuicConfig::SetCreateSessionTagIndicators(QuicTagVector tags) {
+  create_session_tag_indicators_ = std::move(tags);
+}
+
+const QuicTagVector& QuicConfig::create_session_tag_indicators() const {
+  return create_session_tag_indicators_;
+}
+
+void QuicConfig::SetDefaults() {
+  idle_network_timeout_seconds_.set(kMaximumIdleTimeoutSecs,
+                                    kDefaultIdleTimeoutSecs);
+  silent_close_.set(1, 0);
+  SetMaxIncomingDynamicStreamsToSend(kDefaultMaxStreamsPerConnection);
+  max_time_before_crypto_handshake_ =
+      QuicTime::Delta::FromSeconds(kMaxTimeForCryptoHandshakeSecs);
+  max_idle_time_before_crypto_handshake_ =
+      QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs);
+  max_undecryptable_packets_ = kDefaultMaxUndecryptablePackets;
+
+  SetInitialStreamFlowControlWindowToSend(kMinimumFlowControlSendWindow);
+  SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow);
+  SetSupportMaxHeaderListSize();
+}
+
+void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
+  idle_network_timeout_seconds_.ToHandshakeMessage(out);
+  silent_close_.ToHandshakeMessage(out);
+  max_incoming_dynamic_streams_.ToHandshakeMessage(out);
+  bytes_for_connection_id_.ToHandshakeMessage(out);
+  initial_round_trip_time_us_.ToHandshakeMessage(out);
+  initial_stream_flow_control_window_bytes_.ToHandshakeMessage(out);
+  initial_session_flow_control_window_bytes_.ToHandshakeMessage(out);
+  connection_migration_disabled_.ToHandshakeMessage(out);
+  connection_options_.ToHandshakeMessage(out);
+  alternate_server_address_.ToHandshakeMessage(out);
+  support_max_header_list_size_.ToHandshakeMessage(out);
+  stateless_reset_token_.ToHandshakeMessage(out);
+}
+
+QuicErrorCode QuicConfig::ProcessPeerHello(
+    const CryptoHandshakeMessage& peer_hello,
+    HelloType hello_type,
+    QuicString* error_details) {
+  DCHECK(error_details != nullptr);
+
+  QuicErrorCode error = QUIC_NO_ERROR;
+  if (error == QUIC_NO_ERROR) {
+    error = idle_network_timeout_seconds_.ProcessPeerHello(
+        peer_hello, hello_type, error_details);
+  }
+  if (error == QUIC_NO_ERROR) {
+    error =
+        silent_close_.ProcessPeerHello(peer_hello, hello_type, error_details);
+  }
+  if (error == QUIC_NO_ERROR) {
+    error = max_incoming_dynamic_streams_.ProcessPeerHello(
+        peer_hello, hello_type, error_details);
+  }
+  if (error == QUIC_NO_ERROR) {
+    error = bytes_for_connection_id_.ProcessPeerHello(peer_hello, hello_type,
+                                                      error_details);
+  }
+  if (error == QUIC_NO_ERROR) {
+    error = initial_round_trip_time_us_.ProcessPeerHello(peer_hello, hello_type,
+                                                         error_details);
+  }
+  if (error == QUIC_NO_ERROR) {
+    error = initial_stream_flow_control_window_bytes_.ProcessPeerHello(
+        peer_hello, hello_type, error_details);
+  }
+  if (error == QUIC_NO_ERROR) {
+    error = initial_session_flow_control_window_bytes_.ProcessPeerHello(
+        peer_hello, hello_type, error_details);
+  }
+  if (error == QUIC_NO_ERROR) {
+    error = connection_migration_disabled_.ProcessPeerHello(
+        peer_hello, hello_type, error_details);
+  }
+  if (error == QUIC_NO_ERROR) {
+    error = connection_options_.ProcessPeerHello(peer_hello, hello_type,
+                                                 error_details);
+  }
+  if (error == QUIC_NO_ERROR) {
+    error = alternate_server_address_.ProcessPeerHello(peer_hello, hello_type,
+                                                       error_details);
+  }
+  if (error == QUIC_NO_ERROR) {
+    error = support_max_header_list_size_.ProcessPeerHello(
+        peer_hello, hello_type, error_details);
+  }
+  if (error == QUIC_NO_ERROR) {
+    error = stateless_reset_token_.ProcessPeerHello(peer_hello, hello_type,
+                                                    error_details);
+  }
+  return error;
+}
+
+bool QuicConfig::FillTransportParameters(TransportParameters* params) const {
+  params->initial_max_stream_data =
+      initial_stream_flow_control_window_bytes_.GetSendValue();
+  params->initial_max_data =
+      initial_session_flow_control_window_bytes_.GetSendValue();
+
+  uint32_t idle_timeout = idle_network_timeout_seconds_.GetUint32();
+  if (idle_timeout > std::numeric_limits<uint16_t>::max()) {
+    QUIC_BUG << "idle network timeout set too large";
+    return false;
+  }
+  params->idle_timeout = idle_timeout;
+
+  uint32_t initial_max_streams = max_incoming_dynamic_streams_.GetSendValue();
+  if (initial_max_streams > std::numeric_limits<uint16_t>::max()) {
+    QUIC_BUG << "max incoming streams set too large";
+    return false;
+  }
+  params->initial_max_bidi_streams.present = true;
+  params->initial_max_bidi_streams.value = initial_max_streams;
+
+  if (!params->google_quic_params) {
+    params->google_quic_params = QuicMakeUnique<CryptoHandshakeMessage>();
+  }
+  silent_close_.ToHandshakeMessage(params->google_quic_params.get());
+  initial_round_trip_time_us_.ToHandshakeMessage(
+      params->google_quic_params.get());
+  connection_options_.ToHandshakeMessage(params->google_quic_params.get());
+  return true;
+}
+
+QuicErrorCode QuicConfig::ProcessTransportParameters(
+    const TransportParameters& params,
+    HelloType hello_type,
+    QuicString* error_details) {
+  QuicErrorCode error = idle_network_timeout_seconds_.ReceiveValue(
+      params.idle_timeout, hello_type, error_details);
+  if (error != QUIC_NO_ERROR) {
+    return error;
+  }
+  const CryptoHandshakeMessage* peer_params = params.google_quic_params.get();
+  if (!peer_params) {
+    return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+  }
+  error =
+      silent_close_.ProcessPeerHello(*peer_params, hello_type, error_details);
+  if (error != QUIC_NO_ERROR) {
+    return error;
+  }
+  error = initial_round_trip_time_us_.ProcessPeerHello(*peer_params, hello_type,
+                                                       error_details);
+  if (error != QUIC_NO_ERROR) {
+    return error;
+  }
+  error = connection_options_.ProcessPeerHello(*peer_params, hello_type,
+                                               error_details);
+  if (error != QUIC_NO_ERROR) {
+    return error;
+  }
+
+  initial_stream_flow_control_window_bytes_.SetReceivedValue(
+      params.initial_max_stream_data);
+  initial_session_flow_control_window_bytes_.SetReceivedValue(
+      params.initial_max_data);
+  if (params.initial_max_bidi_streams.present) {
+    max_incoming_dynamic_streams_.SetReceivedValue(
+        params.initial_max_bidi_streams.value);
+  } else {
+    // An absent value for initial_max_bidi_streams is treated as a value of 0.
+    max_incoming_dynamic_streams_.SetReceivedValue(0);
+  }
+
+  return QUIC_NO_ERROR;
+}
+
+}  // namespace quic