summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quiche/quic/core/quic_config.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/third_party/quiche/src/quiche/quic/core/quic_config.cc')
-rw-r--r--chromium/net/third_party/quiche/src/quiche/quic/core/quic_config.cc1397
1 files changed, 1397 insertions, 0 deletions
diff --git a/chromium/net/third_party/quiche/src/quiche/quic/core/quic_config.cc b/chromium/net/third_party/quiche/src/quiche/quic/core/quic_config.cc
new file mode 100644
index 00000000000..c48001ac907
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quiche/quic/core/quic_config.cc
@@ -0,0 +1,1397 @@
+// 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 "quiche/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 "quiche/quic/core/crypto/crypto_handshake_message.h"
+#include "quiche/quic/core/crypto/crypto_protocol.h"
+#include "quiche/quic/core/quic_connection_id.h"
+#include "quiche/quic/core/quic_constants.h"
+#include "quiche/quic/core/quic_socket_address_coder.h"
+#include "quiche/quic/core/quic_types.h"
+#include "quiche/quic/core/quic_utils.h"
+#include "quiche/quic/platform/api/quic_bug_tracker.h"
+#include "quiche/quic/platform/api/quic_flag_utils.h"
+#include "quiche/quic/platform/api/quic_flags.h"
+#include "quiche/quic/platform/api/quic_logging.h"
+#include "quiche/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),
+ 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::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();
+ }
+
+ 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*>(
+ &params.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);
+ }
+
+ 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