| // 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 <cstring> | |
| #include <string> | |
| #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_constants.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_socket_address.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_uint128.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) { | |
| 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, | |
| std::string* 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, | |
| std::string* 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*/, | |
| std::string* 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*/, | |
| std::string* 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*/, | |
| std::string* 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*/, | |
| std::string* 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_bidirectional_streams_(kMIBS, PRESENCE_REQUIRED), | |
| 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), | |
| alternate_server_address_(kASAD, PRESENCE_OPTIONAL), | |
| support_max_header_list_size_(kSMHL, PRESENCE_OPTIONAL), | |
| stateless_reset_token_(kSRST, PRESENCE_OPTIONAL), | |
| max_incoming_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL), | |
| max_ack_delay_ms_(kMAD, PRESENCE_OPTIONAL), | |
| ack_delay_exponent_(kADE, 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::SetMaxIncomingBidirectionalStreamsToSend( | |
| uint32_t max_streams) { | |
| max_incoming_bidirectional_streams_.SetSendValue(max_streams); | |
| } | |
| uint32_t QuicConfig::GetMaxIncomingBidirectionalStreamsToSend() { | |
| return max_incoming_bidirectional_streams_.GetSendValue(); | |
| } | |
| bool QuicConfig::HasReceivedMaxIncomingBidirectionalStreams() { | |
| return max_incoming_bidirectional_streams_.HasReceivedValue(); | |
| } | |
| uint32_t QuicConfig::ReceivedMaxIncomingBidirectionalStreams() { | |
| return max_incoming_bidirectional_streams_.GetReceivedValue(); | |
| } | |
| void QuicConfig::SetMaxIncomingUnidirectionalStreamsToSend( | |
| uint32_t max_streams) { | |
| max_incoming_unidirectional_streams_.SetSendValue(max_streams); | |
| } | |
| uint32_t QuicConfig::GetMaxIncomingUnidirectionalStreamsToSend() { | |
| return max_incoming_unidirectional_streams_.GetSendValue(); | |
| } | |
| bool QuicConfig::HasReceivedMaxIncomingUnidirectionalStreams() { | |
| return max_incoming_unidirectional_streams_.HasReceivedValue(); | |
| } | |
| uint32_t QuicConfig::ReceivedMaxIncomingUnidirectionalStreams() { | |
| return max_incoming_unidirectional_streams_.GetReceivedValue(); | |
| } | |
| void QuicConfig::SetMaxAckDelayToSendMs(uint32_t max_ack_delay_ms) { | |
| return max_ack_delay_ms_.SetSendValue(max_ack_delay_ms); | |
| } | |
| uint32_t QuicConfig::GetMaxAckDelayToToSendMs() 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::SetAckDelayExponentToSend(uint32_t exponent) { | |
| ack_delay_exponent_.SetSendValue(exponent); | |
| } | |
| uint32_t QuicConfig::GetAckDelayExponentToSend() { | |
| return ack_delay_exponent_.GetSendValue(); | |
| } | |
| bool QuicConfig::HasReceivedAckDelayExponent() const { | |
| return ack_delay_exponent_.HasReceivedValue(); | |
| } | |
| uint32_t QuicConfig::ReceivedAckDelayExponent() const { | |
| return ack_delay_exponent_.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 minimum (" | |
| << 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::SetInitialMaxStreamDataBytesIncomingBidirectionalToSend( | |
| uint32_t window_bytes) { | |
| if (window_bytes < kMinimumFlowControlSendWindow) { | |
| QUIC_BUG << "Initial stream flow control receive window (" << window_bytes | |
| << ") cannot be set lower than minimum (" | |
| << kMinimumFlowControlSendWindow << ")."; | |
| window_bytes = kMinimumFlowControlSendWindow; | |
| } | |
| initial_max_stream_data_bytes_incoming_bidirectional_.SetSendValue( | |
| window_bytes); | |
| } | |
| uint32_t QuicConfig::GetInitialMaxStreamDataBytesIncomingBidirectionalToSend() | |
| const { | |
| return initial_max_stream_data_bytes_incoming_bidirectional_.GetSendValue(); | |
| } | |
| bool QuicConfig::HasReceivedInitialMaxStreamDataBytesIncomingBidirectional() | |
| const { | |
| return initial_max_stream_data_bytes_incoming_bidirectional_ | |
| .HasReceivedValue(); | |
| } | |
| uint32_t QuicConfig::ReceivedInitialMaxStreamDataBytesIncomingBidirectional() | |
| const { | |
| return initial_max_stream_data_bytes_incoming_bidirectional_ | |
| .GetReceivedValue(); | |
| } | |
| void QuicConfig::SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend( | |
| uint32_t window_bytes) { | |
| if (window_bytes < kMinimumFlowControlSendWindow) { | |
| QUIC_BUG << "Initial stream flow control receive window (" << window_bytes | |
| << ") cannot be set lower than minimum (" | |
| << kMinimumFlowControlSendWindow << ")."; | |
| window_bytes = kMinimumFlowControlSendWindow; | |
| } | |
| initial_max_stream_data_bytes_outgoing_bidirectional_.SetSendValue( | |
| window_bytes); | |
| } | |
| uint32_t QuicConfig::GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend() | |
| const { | |
| return initial_max_stream_data_bytes_outgoing_bidirectional_.GetSendValue(); | |
| } | |
| bool QuicConfig::HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional() | |
| const { | |
| return initial_max_stream_data_bytes_outgoing_bidirectional_ | |
| .HasReceivedValue(); | |
| } | |
| uint32_t QuicConfig::ReceivedInitialMaxStreamDataBytesOutgoingBidirectional() | |
| const { | |
| return initial_max_stream_data_bytes_outgoing_bidirectional_ | |
| .GetReceivedValue(); | |
| } | |
| void QuicConfig::SetInitialMaxStreamDataBytesUnidirectionalToSend( | |
| uint32_t window_bytes) { | |
| if (window_bytes < kMinimumFlowControlSendWindow) { | |
| QUIC_BUG << "Initial stream flow control receive window (" << window_bytes | |
| << ") cannot be set lower than minimum (" | |
| << kMinimumFlowControlSendWindow << ")."; | |
| window_bytes = kMinimumFlowControlSendWindow; | |
| } | |
| initial_max_stream_data_bytes_unidirectional_.SetSendValue(window_bytes); | |
| } | |
| uint32_t QuicConfig::GetInitialMaxStreamDataBytesUnidirectionalToSend() const { | |
| return initial_max_stream_data_bytes_unidirectional_.GetSendValue(); | |
| } | |
| bool QuicConfig::HasReceivedInitialMaxStreamDataBytesUnidirectional() const { | |
| return initial_max_stream_data_bytes_unidirectional_.HasReceivedValue(); | |
| } | |
| uint32_t QuicConfig::ReceivedInitialMaxStreamDataBytesUnidirectional() const { | |
| return initial_max_stream_data_bytes_unidirectional_.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); | |
| SetMaxIncomingBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection); | |
| SetMaxIncomingUnidirectionalStreamsToSend(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); | |
| SetInitialMaxStreamDataBytesIncomingBidirectionalToSend( | |
| kMinimumFlowControlSendWindow); | |
| SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend( | |
| kMinimumFlowControlSendWindow); | |
| SetInitialMaxStreamDataBytesUnidirectionalToSend( | |
| kMinimumFlowControlSendWindow); | |
| SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow); | |
| SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs); | |
| SetSupportMaxHeaderListSize(); | |
| SetAckDelayExponentToSend(kDefaultAckDelayExponent); | |
| } | |
| void QuicConfig::ToHandshakeMessage( | |
| CryptoHandshakeMessage* out, | |
| QuicTransportVersion transport_version) const { | |
| idle_network_timeout_seconds_.ToHandshakeMessage(out); | |
| silent_close_.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_incoming_bidirectional_streams_.ToHandshakeMessage(out); | |
| if (VersionHasIetfQuicFrames(transport_version)) { | |
| max_incoming_unidirectional_streams_.ToHandshakeMessage(out); | |
| ack_delay_exponent_.ToHandshakeMessage(out); | |
| } | |
| if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) { | |
| QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 1, 4); | |
| 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); | |
| 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, | |
| std::string* 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_bidirectional_streams_.ProcessPeerHello( | |
| peer_hello, hello_type, error_details); | |
| } | |
| if (error == QUIC_NO_ERROR) { | |
| error = max_incoming_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) { | |
| 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); | |
| } | |
| if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time) && | |
| error == QUIC_NO_ERROR) { | |
| QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 2, 4); | |
| 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); | |
| } | |
| return error; | |
| } | |
| bool QuicConfig::FillTransportParameters(TransportParameters* params) const { | |
| params->idle_timeout_milliseconds.set_value( | |
| idle_network_timeout_seconds_.GetUint32() * kNumMillisPerSecond); | |
| if (stateless_reset_token_.HasSendValue()) { | |
| QuicUint128 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_packet_size.set_value(kMaxIncomingPacketSize); | |
| params->initial_max_data.set_value( | |
| initial_session_flow_control_window_bytes_.GetSendValue()); | |
| params->initial_max_stream_data_bidi_local.set_value( | |
| initial_max_stream_data_bytes_incoming_bidirectional_.GetSendValue()); | |
| params->initial_max_stream_data_bidi_remote.set_value( | |
| initial_max_stream_data_bytes_outgoing_bidirectional_.GetSendValue()); | |
| params->initial_max_stream_data_uni.set_value( | |
| initial_max_stream_data_bytes_unidirectional_.GetSendValue()); | |
| params->initial_max_streams_bidi.set_value( | |
| max_incoming_bidirectional_streams_.GetSendValue()); | |
| params->initial_max_streams_uni.set_value( | |
| max_incoming_unidirectional_streams_.GetSendValue()); | |
| if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) { | |
| QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 3, 4); | |
| params->max_ack_delay.set_value(kDefaultDelayedAckTimeMs); | |
| } | |
| params->ack_delay_exponent.set_value(ack_delay_exponent_.GetSendValue()); | |
| params->disable_migration = | |
| connection_migration_disabled_.HasSendValue() && | |
| connection_migration_disabled_.GetSendValue() != 0; | |
| if (alternate_server_address_.HasSendValue()) { | |
| TransportParameters::PreferredAddress preferred_address; | |
| QuicSocketAddress socket_address = alternate_server_address_.GetSendValue(); | |
| if (socket_address.host().IsIPv6()) { | |
| preferred_address.ipv6_socket_address = socket_address; | |
| } else { | |
| preferred_address.ipv4_socket_address = socket_address; | |
| } | |
| params->preferred_address = | |
| std::make_unique<TransportParameters::PreferredAddress>( | |
| preferred_address); | |
| } | |
| if (!params->google_quic_params) { | |
| params->google_quic_params = std::make_unique<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()); | |
| params->custom_parameters = custom_transport_parameters_to_send_; | |
| return true; | |
| } | |
| QuicErrorCode QuicConfig::ProcessTransportParameters( | |
| const TransportParameters& params, | |
| HelloType hello_type, | |
| std::string* error_details) { | |
| // Intentionally round down to probe too often rather than not often enough. | |
| uint64_t idle_timeout_seconds = | |
| params.idle_timeout_milliseconds.value() / kNumMillisPerSecond; | |
| // An idle timeout of zero indicates it is disabled (in other words, it is | |
| // set to infinity). When the idle timeout is very high, we set it to our | |
| // preferred maximum and still probe that often. | |
| if (idle_timeout_seconds > idle_network_timeout_seconds_.GetMax() || | |
| idle_timeout_seconds == 0) { | |
| idle_timeout_seconds = idle_network_timeout_seconds_.GetMax(); | |
| } | |
| QuicErrorCode error = idle_network_timeout_seconds_.ReceiveValue( | |
| idle_timeout_seconds, hello_type, error_details); | |
| if (error != QUIC_NO_ERROR) { | |
| DCHECK(!error_details->empty()); | |
| return error; | |
| } | |
| if (!params.stateless_reset_token.empty()) { | |
| QuicUint128 stateless_reset_token; | |
| if (params.stateless_reset_token.size() != sizeof(stateless_reset_token)) { | |
| QUIC_BUG << "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_packet_size.value() < kMaxOutgoingPacketSize) { | |
| // TODO(dschinazi) act on this. | |
| QUIC_DLOG(ERROR) << "Ignoring peer's requested max packet size of " | |
| << params.max_packet_size.value(); | |
| } | |
| initial_session_flow_control_window_bytes_.SetReceivedValue( | |
| std::min<uint64_t>(params.initial_max_data.value(), | |
| std::numeric_limits<uint32_t>::max())); | |
| max_incoming_bidirectional_streams_.SetReceivedValue( | |
| std::min<uint64_t>(params.initial_max_streams_bidi.value(), | |
| std::numeric_limits<uint32_t>::max())); | |
| max_incoming_unidirectional_streams_.SetReceivedValue( | |
| std::min<uint64_t>(params.initial_max_streams_uni.value(), | |
| std::numeric_limits<uint32_t>::max())); | |
| initial_max_stream_data_bytes_incoming_bidirectional_.SetReceivedValue( | |
| std::min<uint64_t>(params.initial_max_stream_data_bidi_local.value(), | |
| std::numeric_limits<uint32_t>::max())); | |
| initial_max_stream_data_bytes_outgoing_bidirectional_.SetReceivedValue( | |
| std::min<uint64_t>(params.initial_max_stream_data_bidi_remote.value(), | |
| std::numeric_limits<uint32_t>::max())); | |
| initial_max_stream_data_bytes_unidirectional_.SetReceivedValue( | |
| std::min<uint64_t>(params.initial_max_stream_data_uni.value(), | |
| std::numeric_limits<uint32_t>::max())); | |
| if (GetQuicReloadableFlag(quic_negotiate_ack_delay_time)) { | |
| QUIC_RELOADABLE_FLAG_COUNT_N(quic_negotiate_ack_delay_time, 4, 4); | |
| max_ack_delay_ms_.SetReceivedValue(std::min<uint32_t>( | |
| params.max_ack_delay.value(), std::numeric_limits<uint32_t>::max())); | |
| } | |
| if (params.ack_delay_exponent.IsValid()) { | |
| ack_delay_exponent_.SetReceivedValue(params.ack_delay_exponent.value()); | |
| } | |
| connection_migration_disabled_.SetReceivedValue( | |
| params.disable_migration ? 1u : 0u); | |
| if (params.preferred_address != nullptr) { | |
| if (params.preferred_address->ipv6_socket_address.port() != 0) { | |
| alternate_server_address_.SetReceivedValue( | |
| params.preferred_address->ipv6_socket_address); | |
| } else if (params.preferred_address->ipv4_socket_address.port() != 0) { | |
| alternate_server_address_.SetReceivedValue( | |
| params.preferred_address->ipv4_socket_address); | |
| } | |
| } | |
| const CryptoHandshakeMessage* peer_params = params.google_quic_params.get(); | |
| if (peer_params != nullptr) { | |
| error = | |
| silent_close_.ProcessPeerHello(*peer_params, hello_type, error_details); | |
| if (error != QUIC_NO_ERROR) { | |
| DCHECK(!error_details->empty()); | |
| return error; | |
| } | |
| error = initial_round_trip_time_us_.ProcessPeerHello( | |
| *peer_params, hello_type, error_details); | |
| if (error != QUIC_NO_ERROR) { | |
| DCHECK(!error_details->empty()); | |
| return error; | |
| } | |
| error = connection_options_.ProcessPeerHello(*peer_params, hello_type, | |
| error_details); | |
| if (error != QUIC_NO_ERROR) { | |
| DCHECK(!error_details->empty()); | |
| return error; | |
| } | |
| } | |
| received_custom_transport_parameters_ = params.custom_parameters; | |
| *error_details = ""; | |
| return QUIC_NO_ERROR; | |
| } | |
| } // namespace quic |