| // 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 "quic/core/quic_config.h" | 
 |  | 
 | #include <algorithm> | 
 | #include <cstring> | 
 | #include <limits> | 
 | #include <string> | 
 | #include <utility> | 
 |  | 
 | #include "absl/base/attributes.h" | 
 | #include "absl/strings/string_view.h" | 
 | #include "quic/core/crypto/crypto_handshake_message.h" | 
 | #include "quic/core/crypto/crypto_protocol.h" | 
 | #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" | 
 | #include "quic/platform/api/quic_flags.h" | 
 | #include "quic/platform/api/quic_logging.h" | 
 | #include "quic/platform/api/quic_socket_address.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, | 
 |                          std::string* error_details) { | 
 |   QUICHE_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() {} | 
 |  | 
 | 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(quic_bug_12743_1, !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(quic_bug_12743_2, !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 (tag_ == 0) { | 
 |     QUIC_BUG(quic_bug_12743_3) | 
 |         << "This parameter does not support writing to CryptoHandshakeMessage"; | 
 |     return; | 
 |   } | 
 |   if (has_send_value_) { | 
 |     out->SetValue(tag_, send_value_); | 
 |   } | 
 | } | 
 |  | 
 | QuicErrorCode QuicFixedUint32::ProcessPeerHello( | 
 |     const CryptoHandshakeMessage& peer_hello, | 
 |     HelloType /*hello_type*/, | 
 |     std::string* error_details) { | 
 |   QUICHE_DCHECK(error_details != nullptr); | 
 |   if (tag_ == 0) { | 
 |     *error_details = | 
 |         "This parameter does not support reading from CryptoHandshakeMessage"; | 
 |     QUIC_BUG(quic_bug_10575_1) << *error_details; | 
 |     return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; | 
 |   } | 
 |   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; | 
 | } | 
 |  | 
 | QuicFixedUint62::QuicFixedUint62(QuicTag name, QuicConfigPresence presence) | 
 |     : QuicConfigValue(name, presence), | 
 |       has_send_value_(false), | 
 |       has_receive_value_(false) {} | 
 |  | 
 | QuicFixedUint62::~QuicFixedUint62() {} | 
 |  | 
 | bool QuicFixedUint62::HasSendValue() const { | 
 |   return has_send_value_; | 
 | } | 
 |  | 
 | uint64_t QuicFixedUint62::GetSendValue() const { | 
 |   if (!has_send_value_) { | 
 |     QUIC_BUG(quic_bug_10575_2) | 
 |         << "No send value to get for tag:" << QuicTagToString(tag_); | 
 |     return 0; | 
 |   } | 
 |   return send_value_; | 
 | } | 
 |  | 
 | void QuicFixedUint62::SetSendValue(uint64_t value) { | 
 |   if (value > kVarInt62MaxValue) { | 
 |     QUIC_BUG(quic_bug_10575_3) << "QuicFixedUint62 invalid value " << value; | 
 |     value = kVarInt62MaxValue; | 
 |   } | 
 |   has_send_value_ = true; | 
 |   send_value_ = value; | 
 | } | 
 |  | 
 | bool QuicFixedUint62::HasReceivedValue() const { | 
 |   return has_receive_value_; | 
 | } | 
 |  | 
 | uint64_t QuicFixedUint62::GetReceivedValue() const { | 
 |   if (!has_receive_value_) { | 
 |     QUIC_BUG(quic_bug_10575_4) | 
 |         << "No receive value to get for tag:" << QuicTagToString(tag_); | 
 |     return 0; | 
 |   } | 
 |   return receive_value_; | 
 | } | 
 |  | 
 | void QuicFixedUint62::SetReceivedValue(uint64_t value) { | 
 |   has_receive_value_ = true; | 
 |   receive_value_ = value; | 
 | } | 
 |  | 
 | void QuicFixedUint62::ToHandshakeMessage(CryptoHandshakeMessage* out) const { | 
 |   if (!has_send_value_) { | 
 |     return; | 
 |   } | 
 |   uint32_t send_value32; | 
 |   if (send_value_ > std::numeric_limits<uint32_t>::max()) { | 
 |     QUIC_BUG(quic_bug_10575_5) << "Attempting to send " << send_value_ | 
 |                                << " for tag:" << QuicTagToString(tag_); | 
 |     send_value32 = std::numeric_limits<uint32_t>::max(); | 
 |   } else { | 
 |     send_value32 = static_cast<uint32_t>(send_value_); | 
 |   } | 
 |   out->SetValue(tag_, send_value32); | 
 | } | 
 |  | 
 | QuicErrorCode QuicFixedUint62::ProcessPeerHello( | 
 |     const CryptoHandshakeMessage& peer_hello, | 
 |     HelloType /*hello_type*/, | 
 |     std::string* error_details) { | 
 |   QUICHE_DCHECK(error_details != nullptr); | 
 |   uint32_t receive_value32; | 
 |   QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value32); | 
 |   // GetUint32 is guaranteed to always initialize receive_value32. | 
 |   receive_value_ = receive_value32; | 
 |   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; | 
 | } | 
 |  | 
 | QuicFixedStatelessResetToken::QuicFixedStatelessResetToken( | 
 |     QuicTag tag, | 
 |     QuicConfigPresence presence) | 
 |     : QuicConfigValue(tag, presence), | 
 |       has_send_value_(false), | 
 |       has_receive_value_(false) {} | 
 | QuicFixedStatelessResetToken::~QuicFixedStatelessResetToken() {} | 
 |  | 
 | bool QuicFixedStatelessResetToken::HasSendValue() const { | 
 |   return has_send_value_; | 
 | } | 
 |  | 
 | const StatelessResetToken& QuicFixedStatelessResetToken::GetSendValue() const { | 
 |   QUIC_BUG_IF(quic_bug_12743_4, !has_send_value_) | 
 |       << "No send value to get for tag:" << QuicTagToString(tag_); | 
 |   return send_value_; | 
 | } | 
 |  | 
 | void QuicFixedStatelessResetToken::SetSendValue( | 
 |     const StatelessResetToken& value) { | 
 |   has_send_value_ = true; | 
 |   send_value_ = value; | 
 | } | 
 |  | 
 | bool QuicFixedStatelessResetToken::HasReceivedValue() const { | 
 |   return has_receive_value_; | 
 | } | 
 |  | 
 | const StatelessResetToken& QuicFixedStatelessResetToken::GetReceivedValue() | 
 |     const { | 
 |   QUIC_BUG_IF(quic_bug_12743_5, !has_receive_value_) | 
 |       << "No receive value to get for tag:" << QuicTagToString(tag_); | 
 |   return receive_value_; | 
 | } | 
 |  | 
 | void QuicFixedStatelessResetToken::SetReceivedValue( | 
 |     const StatelessResetToken& value) { | 
 |   has_receive_value_ = true; | 
 |   receive_value_ = value; | 
 | } | 
 |  | 
 | void QuicFixedStatelessResetToken::ToHandshakeMessage( | 
 |     CryptoHandshakeMessage* out) const { | 
 |   if (has_send_value_) { | 
 |     out->SetValue(tag_, send_value_); | 
 |   } | 
 | } | 
 |  | 
 | QuicErrorCode QuicFixedStatelessResetToken::ProcessPeerHello( | 
 |     const CryptoHandshakeMessage& peer_hello, | 
 |     HelloType /*hello_type*/, | 
 |     std::string* error_details) { | 
 |   QUICHE_DCHECK(error_details != nullptr); | 
 |   QuicErrorCode error = | 
 |       peer_hello.GetStatelessResetToken(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_; | 
 | } | 
 |  | 
 | const QuicTagVector& QuicFixedTagVector::GetSendValues() const { | 
 |   QUIC_BUG_IF(quic_bug_12743_6, !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_; | 
 | } | 
 |  | 
 | const QuicTagVector& QuicFixedTagVector::GetReceivedValues() const { | 
 |   QUIC_BUG_IF(quic_bug_12743_7, !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*/, | 
 |     std::string* error_details) { | 
 |   QUICHE_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(quic_bug_12743_8, !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(quic_bug_12743_9, !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*/, | 
 |     std::string* error_details) { | 
 |   absl::string_view 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() | 
 |     : negotiated_(false), | 
 |       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), | 
 |       max_idle_timeout_to_send_(QuicTime::Delta::Infinite()), | 
 |       max_bidirectional_streams_(kMIBS, PRESENCE_REQUIRED), | 
 |       max_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL), | 
 |       bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL), | 
 |       initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL), | 
 |       initial_max_stream_data_bytes_incoming_bidirectional_(0, | 
 |                                                             PRESENCE_OPTIONAL), | 
 |       initial_max_stream_data_bytes_outgoing_bidirectional_(0, | 
 |                                                             PRESENCE_OPTIONAL), | 
 |       initial_max_stream_data_bytes_unidirectional_(0, 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), | 
 |       key_update_supported_remotely_(false), | 
 |       key_update_supported_locally_(false), | 
 |       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), | 
 |       min_ack_delay_ms_(0, PRESENCE_OPTIONAL), | 
 |       ack_delay_exponent_(kADE, PRESENCE_OPTIONAL), | 
 |       max_udp_payload_size_(0, PRESENCE_OPTIONAL), | 
 |       max_datagram_frame_size_(0, PRESENCE_OPTIONAL), | 
 |       active_connection_id_limit_(0, 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(); | 
 | } | 
 |  | 
 | const QuicTagVector& QuicConfig::ReceivedConnectionOptions() const { | 
 |   return connection_options_.GetReceivedValues(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasSendConnectionOptions() const { | 
 |   return connection_options_.HasSendValues(); | 
 | } | 
 |  | 
 | const 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)); | 
 | } | 
 |  | 
 | const QuicTagVector& QuicConfig::ClientRequestedIndependentOptions( | 
 |     Perspective perspective) const { | 
 |   static const QuicTagVector* no_options = new QuicTagVector; | 
 |   if (perspective == Perspective::IS_SERVER) { | 
 |     return HasReceivedConnectionOptions() ? ReceivedConnectionOptions() | 
 |                                           : *no_options; | 
 |   } | 
 |  | 
 |   return client_connection_options_.HasSendValues() | 
 |              ? client_connection_options_.GetSendValues() | 
 |              : *no_options; | 
 | } | 
 |  | 
 | void QuicConfig::SetIdleNetworkTimeout(QuicTime::Delta idle_network_timeout) { | 
 |   if (idle_network_timeout.ToMicroseconds() <= 0) { | 
 |     QUIC_BUG(quic_bug_10575_6) | 
 |         << "Invalid idle network timeout " << idle_network_timeout; | 
 |     return; | 
 |   } | 
 |   max_idle_timeout_to_send_ = idle_network_timeout; | 
 | } | 
 |  | 
 | QuicTime::Delta QuicConfig::IdleNetworkTimeout() const { | 
 |   // TODO(b/152032210) add a QUIC_BUG to ensure that is not called before we've | 
 |   // received the peer's values. This is true in production code but not in all | 
 |   // of our tests that use a fake QuicConfig. | 
 |   if (!received_max_idle_timeout_.has_value()) { | 
 |     return max_idle_timeout_to_send_; | 
 |   } | 
 |   return received_max_idle_timeout_.value(); | 
 | } | 
 |  | 
 | void QuicConfig::SetMaxBidirectionalStreamsToSend(uint32_t max_streams) { | 
 |   max_bidirectional_streams_.SetSendValue(max_streams); | 
 | } | 
 |  | 
 | uint32_t QuicConfig::GetMaxBidirectionalStreamsToSend() const { | 
 |   return max_bidirectional_streams_.GetSendValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedMaxBidirectionalStreams() const { | 
 |   return max_bidirectional_streams_.HasReceivedValue(); | 
 | } | 
 |  | 
 | uint32_t QuicConfig::ReceivedMaxBidirectionalStreams() const { | 
 |   return max_bidirectional_streams_.GetReceivedValue(); | 
 | } | 
 |  | 
 | void QuicConfig::SetMaxUnidirectionalStreamsToSend(uint32_t max_streams) { | 
 |   max_unidirectional_streams_.SetSendValue(max_streams); | 
 | } | 
 |  | 
 | uint32_t QuicConfig::GetMaxUnidirectionalStreamsToSend() const { | 
 |   return max_unidirectional_streams_.GetSendValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedMaxUnidirectionalStreams() const { | 
 |   return max_unidirectional_streams_.HasReceivedValue(); | 
 | } | 
 |  | 
 | uint32_t QuicConfig::ReceivedMaxUnidirectionalStreams() const { | 
 |   return max_unidirectional_streams_.GetReceivedValue(); | 
 | } | 
 |  | 
 | void QuicConfig::SetMaxAckDelayToSendMs(uint32_t max_ack_delay_ms) { | 
 |   max_ack_delay_ms_.SetSendValue(max_ack_delay_ms); | 
 | } | 
 |  | 
 | uint32_t QuicConfig::GetMaxAckDelayToSendMs() const { | 
 |   return max_ack_delay_ms_.GetSendValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedMaxAckDelayMs() const { | 
 |   return max_ack_delay_ms_.HasReceivedValue(); | 
 | } | 
 |  | 
 | uint32_t QuicConfig::ReceivedMaxAckDelayMs() const { | 
 |   return max_ack_delay_ms_.GetReceivedValue(); | 
 | } | 
 |  | 
 | void QuicConfig::SetMinAckDelayMs(uint32_t min_ack_delay_ms) { | 
 |   min_ack_delay_ms_.SetSendValue(min_ack_delay_ms); | 
 | } | 
 |  | 
 | uint32_t QuicConfig::GetMinAckDelayToSendMs() const { | 
 |   return min_ack_delay_ms_.GetSendValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedMinAckDelayMs() const { | 
 |   return min_ack_delay_ms_.HasReceivedValue(); | 
 | } | 
 |  | 
 | uint32_t QuicConfig::ReceivedMinAckDelayMs() const { | 
 |   return min_ack_delay_ms_.GetReceivedValue(); | 
 | } | 
 |  | 
 | void QuicConfig::SetAckDelayExponentToSend(uint32_t exponent) { | 
 |   ack_delay_exponent_.SetSendValue(exponent); | 
 | } | 
 |  | 
 | uint32_t QuicConfig::GetAckDelayExponentToSend() const { | 
 |   return ack_delay_exponent_.GetSendValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedAckDelayExponent() const { | 
 |   return ack_delay_exponent_.HasReceivedValue(); | 
 | } | 
 |  | 
 | uint32_t QuicConfig::ReceivedAckDelayExponent() const { | 
 |   return ack_delay_exponent_.GetReceivedValue(); | 
 | } | 
 |  | 
 | void QuicConfig::SetMaxPacketSizeToSend(uint64_t max_udp_payload_size) { | 
 |   max_udp_payload_size_.SetSendValue(max_udp_payload_size); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::GetMaxPacketSizeToSend() const { | 
 |   return max_udp_payload_size_.GetSendValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedMaxPacketSize() const { | 
 |   return max_udp_payload_size_.HasReceivedValue(); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::ReceivedMaxPacketSize() const { | 
 |   return max_udp_payload_size_.GetReceivedValue(); | 
 | } | 
 |  | 
 | void QuicConfig::SetMaxDatagramFrameSizeToSend( | 
 |     uint64_t max_datagram_frame_size) { | 
 |   max_datagram_frame_size_.SetSendValue(max_datagram_frame_size); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::GetMaxDatagramFrameSizeToSend() const { | 
 |   return max_datagram_frame_size_.GetSendValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedMaxDatagramFrameSize() const { | 
 |   return max_datagram_frame_size_.HasReceivedValue(); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::ReceivedMaxDatagramFrameSize() const { | 
 |   return max_datagram_frame_size_.GetReceivedValue(); | 
 | } | 
 |  | 
 | void QuicConfig::SetActiveConnectionIdLimitToSend( | 
 |     uint64_t active_connection_id_limit) { | 
 |   active_connection_id_limit_.SetSendValue(active_connection_id_limit); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::GetActiveConnectionIdLimitToSend() const { | 
 |   return active_connection_id_limit_.GetSendValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedActiveConnectionIdLimit() const { | 
 |   return active_connection_id_limit_.HasReceivedValue(); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::ReceivedActiveConnectionIdLimit() const { | 
 |   return active_connection_id_limit_.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(uint64_t rtt) { | 
 |   initial_round_trip_time_us_.SetSendValue(rtt); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedInitialRoundTripTimeUs() const { | 
 |   return initial_round_trip_time_us_.HasReceivedValue(); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::ReceivedInitialRoundTripTimeUs() const { | 
 |   return initial_round_trip_time_us_.GetReceivedValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasInitialRoundTripTimeUsToSend() const { | 
 |   return initial_round_trip_time_us_.HasSendValue(); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::GetInitialRoundTripTimeUsToSend() const { | 
 |   return initial_round_trip_time_us_.GetSendValue(); | 
 | } | 
 |  | 
 | void QuicConfig::SetInitialStreamFlowControlWindowToSend( | 
 |     uint64_t window_bytes) { | 
 |   if (window_bytes < kMinimumFlowControlSendWindow) { | 
 |     QUIC_BUG(quic_bug_10575_7) | 
 |         << "Initial stream flow control receive window (" << window_bytes | 
 |         << ") cannot be set lower than minimum (" | 
 |         << kMinimumFlowControlSendWindow << ")."; | 
 |     window_bytes = kMinimumFlowControlSendWindow; | 
 |   } | 
 |   initial_stream_flow_control_window_bytes_.SetSendValue(window_bytes); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::GetInitialStreamFlowControlWindowToSend() const { | 
 |   return initial_stream_flow_control_window_bytes_.GetSendValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedInitialStreamFlowControlWindowBytes() const { | 
 |   return initial_stream_flow_control_window_bytes_.HasReceivedValue(); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::ReceivedInitialStreamFlowControlWindowBytes() const { | 
 |   return initial_stream_flow_control_window_bytes_.GetReceivedValue(); | 
 | } | 
 |  | 
 | void QuicConfig::SetInitialMaxStreamDataBytesIncomingBidirectionalToSend( | 
 |     uint64_t window_bytes) { | 
 |   initial_max_stream_data_bytes_incoming_bidirectional_.SetSendValue( | 
 |       window_bytes); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::GetInitialMaxStreamDataBytesIncomingBidirectionalToSend() | 
 |     const { | 
 |   if (initial_max_stream_data_bytes_incoming_bidirectional_.HasSendValue()) { | 
 |     return initial_max_stream_data_bytes_incoming_bidirectional_.GetSendValue(); | 
 |   } | 
 |   return initial_stream_flow_control_window_bytes_.GetSendValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedInitialMaxStreamDataBytesIncomingBidirectional() | 
 |     const { | 
 |   return initial_max_stream_data_bytes_incoming_bidirectional_ | 
 |       .HasReceivedValue(); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::ReceivedInitialMaxStreamDataBytesIncomingBidirectional() | 
 |     const { | 
 |   return initial_max_stream_data_bytes_incoming_bidirectional_ | 
 |       .GetReceivedValue(); | 
 | } | 
 |  | 
 | void QuicConfig::SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend( | 
 |     uint64_t window_bytes) { | 
 |   initial_max_stream_data_bytes_outgoing_bidirectional_.SetSendValue( | 
 |       window_bytes); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend() | 
 |     const { | 
 |   if (initial_max_stream_data_bytes_outgoing_bidirectional_.HasSendValue()) { | 
 |     return initial_max_stream_data_bytes_outgoing_bidirectional_.GetSendValue(); | 
 |   } | 
 |   return initial_stream_flow_control_window_bytes_.GetSendValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional() | 
 |     const { | 
 |   return initial_max_stream_data_bytes_outgoing_bidirectional_ | 
 |       .HasReceivedValue(); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::ReceivedInitialMaxStreamDataBytesOutgoingBidirectional() | 
 |     const { | 
 |   return initial_max_stream_data_bytes_outgoing_bidirectional_ | 
 |       .GetReceivedValue(); | 
 | } | 
 |  | 
 | void QuicConfig::SetInitialMaxStreamDataBytesUnidirectionalToSend( | 
 |     uint64_t window_bytes) { | 
 |   initial_max_stream_data_bytes_unidirectional_.SetSendValue(window_bytes); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::GetInitialMaxStreamDataBytesUnidirectionalToSend() const { | 
 |   if (initial_max_stream_data_bytes_unidirectional_.HasSendValue()) { | 
 |     return initial_max_stream_data_bytes_unidirectional_.GetSendValue(); | 
 |   } | 
 |   return initial_stream_flow_control_window_bytes_.GetSendValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedInitialMaxStreamDataBytesUnidirectional() const { | 
 |   return initial_max_stream_data_bytes_unidirectional_.HasReceivedValue(); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::ReceivedInitialMaxStreamDataBytesUnidirectional() const { | 
 |   return initial_max_stream_data_bytes_unidirectional_.GetReceivedValue(); | 
 | } | 
 |  | 
 | void QuicConfig::SetInitialSessionFlowControlWindowToSend( | 
 |     uint64_t window_bytes) { | 
 |   if (window_bytes < kMinimumFlowControlSendWindow) { | 
 |     QUIC_BUG(quic_bug_10575_8) | 
 |         << "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); | 
 | } | 
 |  | 
 | uint64_t QuicConfig::GetInitialSessionFlowControlWindowToSend() const { | 
 |   return initial_session_flow_control_window_bytes_.GetSendValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedInitialSessionFlowControlWindowBytes() const { | 
 |   return initial_session_flow_control_window_bytes_.HasReceivedValue(); | 
 | } | 
 |  | 
 | uint64_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::SetKeyUpdateSupportedLocally() { | 
 |   key_update_supported_locally_ = true; | 
 | } | 
 |  | 
 | bool QuicConfig::KeyUpdateSupportedForConnection() const { | 
 |   return KeyUpdateSupportedRemotely() && KeyUpdateSupportedLocally(); | 
 | } | 
 |  | 
 | bool QuicConfig::KeyUpdateSupportedLocally() const { | 
 |   return key_update_supported_locally_; | 
 | } | 
 |  | 
 | bool QuicConfig::KeyUpdateSupportedRemotely() const { | 
 |   return key_update_supported_remotely_; | 
 | } | 
 |  | 
 | void QuicConfig::SetIPv6AlternateServerAddressToSend( | 
 |     const QuicSocketAddress& alternate_server_address_ipv6) { | 
 |   if (!alternate_server_address_ipv6.host().IsIPv6()) { | 
 |     QUIC_BUG(quic_bug_10575_9) | 
 |         << "Cannot use SetIPv6AlternateServerAddressToSend with " | 
 |         << alternate_server_address_ipv6; | 
 |     return; | 
 |   } | 
 |   alternate_server_address_ipv6_.SetSendValue(alternate_server_address_ipv6); | 
 | } | 
 |  | 
 | void QuicConfig::SetIPv6AlternateServerAddressToSend( | 
 |     const QuicSocketAddress& alternate_server_address_ipv6, | 
 |     const QuicConnectionId& connection_id, | 
 |     const StatelessResetToken& stateless_reset_token) { | 
 |   if (!alternate_server_address_ipv6.host().IsIPv6()) { | 
 |     QUIC_BUG(quic_bug_10575_10) | 
 |         << "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(); | 
 | } | 
 |  | 
 | 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(quic_bug_10575_11) | 
 |         << "Cannot use SetIPv4AlternateServerAddressToSend with " | 
 |         << alternate_server_address_ipv4; | 
 |     return; | 
 |   } | 
 |   alternate_server_address_ipv4_.SetSendValue(alternate_server_address_ipv4); | 
 | } | 
 |  | 
 | void QuicConfig::SetIPv4AlternateServerAddressToSend( | 
 |     const QuicSocketAddress& alternate_server_address_ipv4, | 
 |     const QuicConnectionId& connection_id, | 
 |     const StatelessResetToken& stateless_reset_token) { | 
 |   if (!alternate_server_address_ipv4.host().IsIPv4()) { | 
 |     QUIC_BUG(quic_bug_10575_12) | 
 |         << "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(); | 
 | } | 
 |  | 
 | const QuicSocketAddress& QuicConfig::ReceivedIPv4AlternateServerAddress() | 
 |     const { | 
 |   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, StatelessResetToken>& | 
 | QuicConfig::ReceivedPreferredAddressConnectionIdAndToken() const { | 
 |   QUICHE_DCHECK(HasReceivedPreferredAddressConnectionIdAndToken()); | 
 |   return *preferred_address_connection_id_and_token_; | 
 | } | 
 |  | 
 | void QuicConfig::SetOriginalConnectionIdToSend( | 
 |     const QuicConnectionId& original_destination_connection_id) { | 
 |   original_destination_connection_id_to_send_ = | 
 |       original_destination_connection_id; | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedOriginalConnectionId() const { | 
 |   return received_original_destination_connection_id_.has_value(); | 
 | } | 
 |  | 
 | QuicConnectionId QuicConfig::ReceivedOriginalConnectionId() const { | 
 |   if (!HasReceivedOriginalConnectionId()) { | 
 |     QUIC_BUG(quic_bug_10575_13) << "No received original connection ID"; | 
 |     return EmptyQuicConnectionId(); | 
 |   } | 
 |   return received_original_destination_connection_id_.value(); | 
 | } | 
 |  | 
 | void QuicConfig::SetInitialSourceConnectionIdToSend( | 
 |     const QuicConnectionId& initial_source_connection_id) { | 
 |   initial_source_connection_id_to_send_ = initial_source_connection_id; | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedInitialSourceConnectionId() const { | 
 |   return received_initial_source_connection_id_.has_value(); | 
 | } | 
 |  | 
 | QuicConnectionId QuicConfig::ReceivedInitialSourceConnectionId() const { | 
 |   if (!HasReceivedInitialSourceConnectionId()) { | 
 |     QUIC_BUG(quic_bug_10575_14) << "No received initial source connection ID"; | 
 |     return EmptyQuicConnectionId(); | 
 |   } | 
 |   return received_initial_source_connection_id_.value(); | 
 | } | 
 |  | 
 | void QuicConfig::SetRetrySourceConnectionIdToSend( | 
 |     const QuicConnectionId& retry_source_connection_id) { | 
 |   retry_source_connection_id_to_send_ = retry_source_connection_id; | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedRetrySourceConnectionId() const { | 
 |   return received_retry_source_connection_id_.has_value(); | 
 | } | 
 |  | 
 | QuicConnectionId QuicConfig::ReceivedRetrySourceConnectionId() const { | 
 |   if (!HasReceivedRetrySourceConnectionId()) { | 
 |     QUIC_BUG(quic_bug_10575_15) << "No received retry source connection ID"; | 
 |     return EmptyQuicConnectionId(); | 
 |   } | 
 |   return received_retry_source_connection_id_.value(); | 
 | } | 
 |  | 
 | void QuicConfig::SetStatelessResetTokenToSend( | 
 |     const StatelessResetToken& stateless_reset_token) { | 
 |   stateless_reset_token_.SetSendValue(stateless_reset_token); | 
 | } | 
 |  | 
 | bool QuicConfig::HasReceivedStatelessResetToken() const { | 
 |   return stateless_reset_token_.HasReceivedValue(); | 
 | } | 
 |  | 
 | const StatelessResetToken& QuicConfig::ReceivedStatelessResetToken() const { | 
 |   return stateless_reset_token_.GetReceivedValue(); | 
 | } | 
 |  | 
 | bool QuicConfig::negotiated() const { | 
 |   return 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() { | 
 |   SetIdleNetworkTimeout(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs)); | 
 |   SetMaxBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection); | 
 |   SetMaxUnidirectionalStreamsToSend(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); | 
 |   SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs); | 
 |   SetAckDelayExponentToSend(kDefaultAckDelayExponent); | 
 |   SetMaxPacketSizeToSend(kMaxIncomingPacketSize); | 
 |   SetMaxDatagramFrameSizeToSend(kMaxAcceptedDatagramFrameSize); | 
 | } | 
 |  | 
 | void QuicConfig::ToHandshakeMessage( | 
 |     CryptoHandshakeMessage* out, | 
 |     QuicTransportVersion transport_version) const { | 
 |   // Idle timeout has custom rules that are different from other values. | 
 |   // We configure ourselves with the minumum value between the one sent and | 
 |   // the one received. Additionally, when QUIC_CRYPTO is used, the server | 
 |   // MUST send an idle timeout no greater than the idle timeout it received | 
 |   // from the client. We therefore send the received value if it is lower. | 
 |   QuicFixedUint32 max_idle_timeout_seconds(kICSL, PRESENCE_REQUIRED); | 
 |   uint32_t max_idle_timeout_to_send_seconds = | 
 |       max_idle_timeout_to_send_.ToSeconds(); | 
 |   if (received_max_idle_timeout_.has_value() && | 
 |       received_max_idle_timeout_->ToSeconds() < | 
 |           max_idle_timeout_to_send_seconds) { | 
 |     max_idle_timeout_to_send_seconds = received_max_idle_timeout_->ToSeconds(); | 
 |   } | 
 |   max_idle_timeout_seconds.SetSendValue(max_idle_timeout_to_send_seconds); | 
 |   max_idle_timeout_seconds.ToHandshakeMessage(out); | 
 |  | 
 |   // Do not need a version check here, max...bi... will encode | 
 |   // as "MIDS" -- the max initial dynamic streams tag -- if | 
 |   // doing some version other than IETF QUIC. | 
 |   max_bidirectional_streams_.ToHandshakeMessage(out); | 
 |   if (VersionHasIetfQuicFrames(transport_version)) { | 
 |     max_unidirectional_streams_.ToHandshakeMessage(out); | 
 |     ack_delay_exponent_.ToHandshakeMessage(out); | 
 |   } | 
 |   if (max_ack_delay_ms_.GetSendValue() != kDefaultDelayedAckTimeMs) { | 
 |     // Only send max ack delay if it is using a non-default value, because | 
 |     // the default value is used by QuicSentPacketManager if it is not | 
 |     // sent during the handshake, and we want to save bytes. | 
 |     max_ack_delay_ms_.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); | 
 |   if (alternate_server_address_ipv6_.HasSendValue()) { | 
 |     alternate_server_address_ipv6_.ToHandshakeMessage(out); | 
 |   } else { | 
 |     alternate_server_address_ipv4_.ToHandshakeMessage(out); | 
 |   } | 
 |   stateless_reset_token_.ToHandshakeMessage(out); | 
 | } | 
 |  | 
 | QuicErrorCode QuicConfig::ProcessPeerHello( | 
 |     const CryptoHandshakeMessage& peer_hello, | 
 |     HelloType hello_type, | 
 |     std::string* error_details) { | 
 |   QUICHE_DCHECK(error_details != nullptr); | 
 |  | 
 |   QuicErrorCode error = QUIC_NO_ERROR; | 
 |   if (error == QUIC_NO_ERROR) { | 
 |     // Idle timeout has custom rules that are different from other values. | 
 |     // We configure ourselves with the minumum value between the one sent and | 
 |     // the one received. Additionally, when QUIC_CRYPTO is used, the server | 
 |     // MUST send an idle timeout no greater than the idle timeout it received | 
 |     // from the client. | 
 |     QuicFixedUint32 max_idle_timeout_seconds(kICSL, PRESENCE_REQUIRED); | 
 |     error = max_idle_timeout_seconds.ProcessPeerHello(peer_hello, hello_type, | 
 |                                                       error_details); | 
 |     if (error == QUIC_NO_ERROR) { | 
 |       if (max_idle_timeout_seconds.GetReceivedValue() > | 
 |           max_idle_timeout_to_send_.ToSeconds()) { | 
 |         // The received value is higher than ours, ignore it if from the client | 
 |         // and raise an error if from the server. | 
 |         if (hello_type == SERVER) { | 
 |           error = QUIC_INVALID_NEGOTIATED_VALUE; | 
 |           *error_details = | 
 |               "Invalid value received for " + QuicTagToString(kICSL); | 
 |         } | 
 |       } else { | 
 |         received_max_idle_timeout_ = QuicTime::Delta::FromSeconds( | 
 |             max_idle_timeout_seconds.GetReceivedValue()); | 
 |       } | 
 |     } | 
 |   } | 
 |   if (error == QUIC_NO_ERROR) { | 
 |     error = max_bidirectional_streams_.ProcessPeerHello(peer_hello, hello_type, | 
 |                                                         error_details); | 
 |   } | 
 |   if (error == QUIC_NO_ERROR) { | 
 |     error = max_unidirectional_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) { | 
 |     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, | 
 |                                                     error_details); | 
 |   } | 
 |  | 
 |   if (error == QUIC_NO_ERROR) { | 
 |     error = max_ack_delay_ms_.ProcessPeerHello(peer_hello, hello_type, | 
 |                                                error_details); | 
 |   } | 
 |   if (error == QUIC_NO_ERROR) { | 
 |     error = ack_delay_exponent_.ProcessPeerHello(peer_hello, hello_type, | 
 |                                                  error_details); | 
 |   } | 
 |   if (error == QUIC_NO_ERROR) { | 
 |     negotiated_ = true; | 
 |   } | 
 |   return error; | 
 | } | 
 |  | 
 | bool QuicConfig::FillTransportParameters(TransportParameters* params) const { | 
 |   if (original_destination_connection_id_to_send_.has_value()) { | 
 |     params->original_destination_connection_id = | 
 |         original_destination_connection_id_to_send_.value(); | 
 |   } | 
 |  | 
 |   params->max_idle_timeout_ms.set_value( | 
 |       max_idle_timeout_to_send_.ToMilliseconds()); | 
 |  | 
 |   if (stateless_reset_token_.HasSendValue()) { | 
 |     StatelessResetToken stateless_reset_token = | 
 |         stateless_reset_token_.GetSendValue(); | 
 |     params->stateless_reset_token.assign( | 
 |         reinterpret_cast<const char*>(&stateless_reset_token), | 
 |         reinterpret_cast<const char*>(&stateless_reset_token) + | 
 |             sizeof(stateless_reset_token)); | 
 |   } | 
 |  | 
 |   params->max_udp_payload_size.set_value(GetMaxPacketSizeToSend()); | 
 |   params->max_datagram_frame_size.set_value(GetMaxDatagramFrameSizeToSend()); | 
 |   params->initial_max_data.set_value( | 
 |       GetInitialSessionFlowControlWindowToSend()); | 
 |   // The max stream data bidirectional transport parameters can be either local | 
 |   // or remote. A stream is local iff it is initiated by the endpoint that sent | 
 |   // the transport parameter (see the Transport Parameter Definitions section of | 
 |   // draft-ietf-quic-transport). In this function we are sending transport | 
 |   // parameters, so a local stream is one we initiated, which means an outgoing | 
 |   // stream. | 
 |   params->initial_max_stream_data_bidi_local.set_value( | 
 |       GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend()); | 
 |   params->initial_max_stream_data_bidi_remote.set_value( | 
 |       GetInitialMaxStreamDataBytesIncomingBidirectionalToSend()); | 
 |   params->initial_max_stream_data_uni.set_value( | 
 |       GetInitialMaxStreamDataBytesUnidirectionalToSend()); | 
 |   params->initial_max_streams_bidi.set_value( | 
 |       GetMaxBidirectionalStreamsToSend()); | 
 |   params->initial_max_streams_uni.set_value( | 
 |       GetMaxUnidirectionalStreamsToSend()); | 
 |   params->max_ack_delay.set_value(GetMaxAckDelayToSendMs()); | 
 |   if (min_ack_delay_ms_.HasSendValue()) { | 
 |     params->min_ack_delay_us.set_value(min_ack_delay_ms_.GetSendValue() * | 
 |                                        kNumMicrosPerMilli); | 
 |   } | 
 |   params->ack_delay_exponent.set_value(GetAckDelayExponentToSend()); | 
 |   params->disable_active_migration = | 
 |       connection_migration_disabled_.HasSendValue() && | 
 |       connection_migration_disabled_.GetSendValue() != 0; | 
 |  | 
 |   if (alternate_server_address_ipv6_.HasSendValue() || | 
 |       alternate_server_address_ipv4_.HasSendValue()) { | 
 |     TransportParameters::PreferredAddress preferred_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(); | 
 |     } | 
 |     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); | 
 |   } | 
 |  | 
 |   if (active_connection_id_limit_.HasSendValue()) { | 
 |     params->active_connection_id_limit.set_value( | 
 |         active_connection_id_limit_.GetSendValue()); | 
 |   } | 
 |  | 
 |   if (initial_source_connection_id_to_send_.has_value()) { | 
 |     params->initial_source_connection_id = | 
 |         initial_source_connection_id_to_send_.value(); | 
 |   } | 
 |  | 
 |   if (retry_source_connection_id_to_send_.has_value()) { | 
 |     params->retry_source_connection_id = | 
 |         retry_source_connection_id_to_send_.value(); | 
 |   } | 
 |  | 
 |   if (initial_round_trip_time_us_.HasSendValue()) { | 
 |     params->initial_round_trip_time_us.set_value( | 
 |         initial_round_trip_time_us_.GetSendValue()); | 
 |   } | 
 |   if (connection_options_.HasSendValues() && | 
 |       !connection_options_.GetSendValues().empty()) { | 
 |     params->google_connection_options = connection_options_.GetSendValues(); | 
 |   } | 
 |  | 
 |   if (!KeyUpdateSupportedLocally()) { | 
 |     params->key_update_not_yet_supported = true; | 
 |   } | 
 |  | 
 |   params->custom_parameters = custom_transport_parameters_to_send_; | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | QuicErrorCode QuicConfig::ProcessTransportParameters( | 
 |     const TransportParameters& params, | 
 |     bool is_resumption, | 
 |     std::string* error_details) { | 
 |   if (!is_resumption && params.original_destination_connection_id.has_value()) { | 
 |     received_original_destination_connection_id_ = | 
 |         params.original_destination_connection_id.value(); | 
 |   } | 
 |  | 
 |   if (params.max_idle_timeout_ms.value() > 0 && | 
 |       params.max_idle_timeout_ms.value() < | 
 |           static_cast<uint64_t>(max_idle_timeout_to_send_.ToMilliseconds())) { | 
 |     // An idle timeout of zero indicates it is disabled. | 
 |     // We also ignore values higher than ours which will cause us to use the | 
 |     // smallest value between ours and our peer's. | 
 |     received_max_idle_timeout_ = | 
 |         QuicTime::Delta::FromMilliseconds(params.max_idle_timeout_ms.value()); | 
 |   } | 
 |  | 
 |   if (!is_resumption && !params.stateless_reset_token.empty()) { | 
 |     StatelessResetToken stateless_reset_token; | 
 |     if (params.stateless_reset_token.size() != sizeof(stateless_reset_token)) { | 
 |       QUIC_BUG(quic_bug_10575_16) << "Bad stateless reset token length " | 
 |                                   << params.stateless_reset_token.size(); | 
 |       *error_details = "Bad stateless reset token length"; | 
 |       return QUIC_INTERNAL_ERROR; | 
 |     } | 
 |     memcpy(&stateless_reset_token, params.stateless_reset_token.data(), | 
 |            params.stateless_reset_token.size()); | 
 |     stateless_reset_token_.SetReceivedValue(stateless_reset_token); | 
 |   } | 
 |  | 
 |   if (params.max_udp_payload_size.IsValid()) { | 
 |     max_udp_payload_size_.SetReceivedValue(params.max_udp_payload_size.value()); | 
 |   } | 
 |  | 
 |   if (params.max_datagram_frame_size.IsValid()) { | 
 |     max_datagram_frame_size_.SetReceivedValue( | 
 |         params.max_datagram_frame_size.value()); | 
 |   } | 
 |  | 
 |   initial_session_flow_control_window_bytes_.SetReceivedValue( | 
 |       params.initial_max_data.value()); | 
 |  | 
 |   // IETF QUIC specifies stream IDs and stream counts as 62-bit integers but | 
 |   // our implementation uses uint32_t to represent them to save memory. | 
 |   max_bidirectional_streams_.SetReceivedValue( | 
 |       std::min<uint64_t>(params.initial_max_streams_bidi.value(), | 
 |                          std::numeric_limits<uint32_t>::max())); | 
 |   max_unidirectional_streams_.SetReceivedValue( | 
 |       std::min<uint64_t>(params.initial_max_streams_uni.value(), | 
 |                          std::numeric_limits<uint32_t>::max())); | 
 |  | 
 |   // The max stream data bidirectional transport parameters can be either local | 
 |   // or remote. A stream is local iff it is initiated by the endpoint that sent | 
 |   // the transport parameter (see the Transport Parameter Definitions section of | 
 |   // draft-ietf-quic-transport). However in this function we are processing | 
 |   // received transport parameters, so a local stream is one initiated by our | 
 |   // peer, which means an incoming stream. | 
 |   initial_max_stream_data_bytes_incoming_bidirectional_.SetReceivedValue( | 
 |       params.initial_max_stream_data_bidi_local.value()); | 
 |   initial_max_stream_data_bytes_outgoing_bidirectional_.SetReceivedValue( | 
 |       params.initial_max_stream_data_bidi_remote.value()); | 
 |   initial_max_stream_data_bytes_unidirectional_.SetReceivedValue( | 
 |       params.initial_max_stream_data_uni.value()); | 
 |  | 
 |   if (!is_resumption) { | 
 |     max_ack_delay_ms_.SetReceivedValue(params.max_ack_delay.value()); | 
 |     if (params.ack_delay_exponent.IsValid()) { | 
 |       ack_delay_exponent_.SetReceivedValue(params.ack_delay_exponent.value()); | 
 |     } | 
 |     if (params.preferred_address != nullptr) { | 
 |       if (params.preferred_address->ipv6_socket_address.port() != 0) { | 
 |         alternate_server_address_ipv6_.SetReceivedValue( | 
 |             params.preferred_address->ipv6_socket_address); | 
 |       } | 
 |       if (params.preferred_address->ipv4_socket_address.port() != 0) { | 
 |         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 StatelessResetToken*>( | 
 |                 ¶ms.preferred_address->stateless_reset_token.front())); | 
 |       } | 
 |     } | 
 |     if (params.min_ack_delay_us.value() != 0) { | 
 |       if (params.min_ack_delay_us.value() > | 
 |           params.max_ack_delay.value() * kNumMicrosPerMilli) { | 
 |         *error_details = "MinAckDelay is greater than MaxAckDelay."; | 
 |         return IETF_QUIC_PROTOCOL_VIOLATION; | 
 |       } | 
 |       min_ack_delay_ms_.SetReceivedValue(params.min_ack_delay_us.value() / | 
 |                                          kNumMicrosPerMilli); | 
 |     } | 
 |   } | 
 |  | 
 |   if (params.disable_active_migration) { | 
 |     connection_migration_disabled_.SetReceivedValue(1u); | 
 |   } | 
 |   if (!is_resumption && !params.key_update_not_yet_supported) { | 
 |     key_update_supported_remotely_ = true; | 
 |   } | 
 |  | 
 |   active_connection_id_limit_.SetReceivedValue( | 
 |       params.active_connection_id_limit.value()); | 
 |  | 
 |   if (!is_resumption) { | 
 |     if (params.initial_source_connection_id.has_value()) { | 
 |       received_initial_source_connection_id_ = | 
 |           params.initial_source_connection_id.value(); | 
 |     } | 
 |     if (params.retry_source_connection_id.has_value()) { | 
 |       received_retry_source_connection_id_ = | 
 |           params.retry_source_connection_id.value(); | 
 |     } | 
 |   } | 
 |  | 
 |   if (params.initial_round_trip_time_us.value() > 0) { | 
 |     initial_round_trip_time_us_.SetReceivedValue( | 
 |         params.initial_round_trip_time_us.value()); | 
 |   } | 
 |   if (params.google_connection_options.has_value()) { | 
 |     connection_options_.SetReceivedValues( | 
 |         params.google_connection_options.value()); | 
 |   } | 
 |  | 
 |   received_custom_transport_parameters_ = params.custom_parameters; | 
 |  | 
 |   if (!is_resumption) { | 
 |     negotiated_ = true; | 
 |   } | 
 |   *error_details = ""; | 
 |   return QUIC_NO_ERROR; | 
 | } | 
 |  | 
 | }  // namespace quic |