// 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. #ifndef QUICHE_QUIC_CORE_QUIC_CONFIG_H_ #define QUICHE_QUIC_CORE_QUIC_CONFIG_H_ #include #include #include #include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_time.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" namespace quic { namespace test { class QuicConfigPeer; } // namespace test class CryptoHandshakeMessage; // Describes whether or not a given QuicTag is required or optional in the // handshake message. enum QuicConfigPresence { // This negotiable value can be absent from the handshake message. Default // value is selected as the negotiated value in such a case. PRESENCE_OPTIONAL, // This negotiable value is required in the handshake message otherwise the // Process*Hello function returns an error. PRESENCE_REQUIRED, }; // Whether the CryptoHandshakeMessage is from the client or server. enum HelloType { CLIENT, SERVER, }; // An abstract base class that stores a value that can be sent in CHLO/SHLO // message. These values can be OPTIONAL or REQUIRED, depending on |presence_|. class QUIC_EXPORT_PRIVATE QuicConfigValue { public: QuicConfigValue(QuicTag tag, QuicConfigPresence presence); virtual ~QuicConfigValue(); // Serialises tag name and value(s) to |out|. virtual void ToHandshakeMessage(CryptoHandshakeMessage* out) const = 0; // Selects a mutually acceptable value from those offered in |peer_hello| // and those defined in the subclass. virtual QuicErrorCode ProcessPeerHello( const CryptoHandshakeMessage& peer_hello, HelloType hello_type, std::string* error_details) = 0; protected: const QuicTag tag_; const QuicConfigPresence presence_; }; class QUIC_EXPORT_PRIVATE QuicNegotiableValue : public QuicConfigValue { public: QuicNegotiableValue(QuicTag tag, QuicConfigPresence presence); ~QuicNegotiableValue() override; bool negotiated() const { return negotiated_; } protected: void set_negotiated(bool negotiated) { negotiated_ = negotiated; } private: bool negotiated_; }; class QUIC_EXPORT_PRIVATE QuicNegotiableUint32 : public QuicNegotiableValue { // TODO(fayang): some negotiated values use uint32 as bool (e.g., silent // close). Consider adding a QuicNegotiableBool type. public: // Default and max values default to 0. QuicNegotiableUint32(QuicTag name, QuicConfigPresence presence); ~QuicNegotiableUint32() override; // Sets the maximum possible value that can be achieved after negotiation and // also the default values to be assumed if PRESENCE_OPTIONAL and the *HLO msg // doesn't contain a value corresponding to |name_|. |max| is serialised via // ToHandshakeMessage call if |negotiated_| is false. void set(uint32_t max, uint32_t default_value); // Returns the value negotiated if |negotiated_| is true, otherwise returns // default_value_ (used to set default values before negotiation finishes). uint32_t GetUint32() const; // Returns the maximum value negotiable. uint32_t GetMax() const; // Serialises |name_| and value to |out|. If |negotiated_| is true then // |negotiated_value_| is serialised, otherwise |max_value_| is serialised. void ToHandshakeMessage(CryptoHandshakeMessage* out) const override; // Processes the corresponding value from |peer_hello| and if present calls // ReceiveValue with it. If the corresponding value is missing and // PRESENCE_OPTIONAL then |negotiated_value_| is set to |default_value_|. QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello, HelloType hello_type, std::string* error_details) override; // Takes a value |value| parsed from a handshake message (whether a TLS // ClientHello/ServerHello or a CryptoHandshakeMessage) whose sender was // |hello_type|, and sets |negotiated_value_| to the minimum of |value| and // |max_value_|. On success this function returns QUIC_NO_ERROR; if there is // an error, details are put in |*error_details|. QuicErrorCode ReceiveValue(uint32_t value, HelloType hello_type, std::string* error_details); private: uint32_t max_value_; uint32_t default_value_; uint32_t negotiated_value_; }; // Stores uint32_t from CHLO or SHLO messages that are not negotiated. class QUIC_EXPORT_PRIVATE QuicFixedUint32 : public QuicConfigValue { public: QuicFixedUint32(QuicTag name, QuicConfigPresence presence); ~QuicFixedUint32() override; bool HasSendValue() const; uint32_t GetSendValue() const; void SetSendValue(uint32_t value); bool HasReceivedValue() const; uint32_t GetReceivedValue() const; void SetReceivedValue(uint32_t value); // If has_send_value is true, serialises |tag_| and |send_value_| to |out|. void ToHandshakeMessage(CryptoHandshakeMessage* out) const override; // Sets |value_| to the corresponding value from |peer_hello_| if it exists. QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello, HelloType hello_type, std::string* error_details) override; private: uint32_t send_value_; bool has_send_value_; uint32_t receive_value_; bool has_receive_value_; }; // Stores uint128 from CHLO or SHLO messages that are not negotiated. class QUIC_EXPORT_PRIVATE QuicFixedUint128 : public QuicConfigValue { public: QuicFixedUint128(QuicTag tag, QuicConfigPresence presence); ~QuicFixedUint128() override; bool HasSendValue() const; QuicUint128 GetSendValue() const; void SetSendValue(QuicUint128 value); bool HasReceivedValue() const; QuicUint128 GetReceivedValue() const; void SetReceivedValue(QuicUint128 value); // If has_send_value is true, serialises |tag_| and |send_value_| to |out|. void ToHandshakeMessage(CryptoHandshakeMessage* out) const override; // Sets |value_| to the corresponding value from |peer_hello_| if it exists. QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello, HelloType hello_type, std::string* error_details) override; private: QuicUint128 send_value_; bool has_send_value_; QuicUint128 receive_value_; bool has_receive_value_; }; // Stores tag from CHLO or SHLO messages that are not negotiated. class QUIC_EXPORT_PRIVATE QuicFixedTagVector : public QuicConfigValue { public: QuicFixedTagVector(QuicTag name, QuicConfigPresence presence); QuicFixedTagVector(const QuicFixedTagVector& other); ~QuicFixedTagVector() override; bool HasSendValues() const; QuicTagVector GetSendValues() const; void SetSendValues(const QuicTagVector& values); bool HasReceivedValues() const; QuicTagVector GetReceivedValues() const; void SetReceivedValues(const QuicTagVector& values); // If has_send_value is true, serialises |tag_vector_| and |send_value_| to // |out|. void ToHandshakeMessage(CryptoHandshakeMessage* out) const override; // Sets |receive_values_| to the corresponding value from |client_hello_| if // it exists. QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello, HelloType hello_type, std::string* error_details) override; private: QuicTagVector send_values_; bool has_send_values_; QuicTagVector receive_values_; bool has_receive_values_; }; // Stores QuicSocketAddress from CHLO or SHLO messages that are not negotiated. class QUIC_EXPORT_PRIVATE QuicFixedSocketAddress : public QuicConfigValue { public: QuicFixedSocketAddress(QuicTag tag, QuicConfigPresence presence); ~QuicFixedSocketAddress() override; bool HasSendValue() const; const QuicSocketAddress& GetSendValue() const; void SetSendValue(const QuicSocketAddress& value); bool HasReceivedValue() const; const QuicSocketAddress& GetReceivedValue() const; void SetReceivedValue(const QuicSocketAddress& value); void ToHandshakeMessage(CryptoHandshakeMessage* out) const override; QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello, HelloType hello_type, std::string* error_details) override; private: QuicSocketAddress send_value_; bool has_send_value_; QuicSocketAddress receive_value_; bool has_receive_value_; }; // QuicConfig contains non-crypto configuration options that are negotiated in // the crypto handshake. class QUIC_EXPORT_PRIVATE QuicConfig { public: QuicConfig(); QuicConfig(const QuicConfig& other); ~QuicConfig(); void SetConnectionOptionsToSend(const QuicTagVector& connection_options); bool HasReceivedConnectionOptions() const; // Sets initial received connection options. All received connection options // will be initialized with these fields. Initial received options may only be // set once per config, prior to the setting of any other options. If options // have already been set (either by previous calls or via handshake), this // function does nothing and returns false. bool SetInitialReceivedConnectionOptions(const QuicTagVector& tags); QuicTagVector ReceivedConnectionOptions() const; bool HasSendConnectionOptions() const; QuicTagVector SendConnectionOptions() const; // Returns true if the client is sending or the server has received a // connection option. // TODO(ianswett): Rename to HasClientRequestedSharedOption bool HasClientSentConnectionOption(QuicTag tag, Perspective perspective) const; void SetClientConnectionOptions( const QuicTagVector& client_connection_options); // Returns true if the client has requested the specified connection option. // Checks the client connection options if the |perspective| is client and // connection options if the |perspective| is the server. bool HasClientRequestedIndependentOption(QuicTag tag, Perspective perspective) const; void SetIdleNetworkTimeout(QuicTime::Delta max_idle_network_timeout, QuicTime::Delta default_idle_network_timeout); QuicTime::Delta IdleNetworkTimeout() const; void SetSilentClose(bool silent_close); bool SilentClose() const; void SetMaxIncomingDynamicStreamsToSend( uint32_t max_incoming_dynamic_streams); uint32_t GetMaxIncomingDynamicStreamsToSend(); bool HasReceivedMaxIncomingDynamicStreams(); uint32_t ReceivedMaxIncomingDynamicStreams(); void set_max_time_before_crypto_handshake( QuicTime::Delta max_time_before_crypto_handshake) { max_time_before_crypto_handshake_ = max_time_before_crypto_handshake; } QuicTime::Delta max_time_before_crypto_handshake() const { return max_time_before_crypto_handshake_; } void set_max_idle_time_before_crypto_handshake( QuicTime::Delta max_idle_time_before_crypto_handshake) { max_idle_time_before_crypto_handshake_ = max_idle_time_before_crypto_handshake; } QuicTime::Delta max_idle_time_before_crypto_handshake() const { return max_idle_time_before_crypto_handshake_; } QuicNegotiableUint32 idle_network_timeout_seconds() const { return idle_network_timeout_seconds_; } void set_max_undecryptable_packets(size_t max_undecryptable_packets) { max_undecryptable_packets_ = max_undecryptable_packets; } size_t max_undecryptable_packets() const { return max_undecryptable_packets_; } bool HasSetBytesForConnectionIdToSend() const; // Sets the peer's connection id length, in bytes. void SetBytesForConnectionIdToSend(uint32_t bytes); bool HasReceivedBytesForConnectionId() const; uint32_t ReceivedBytesForConnectionId() const; // Sets an estimated initial round trip time in us. void SetInitialRoundTripTimeUsToSend(uint32_t rtt_us); bool HasReceivedInitialRoundTripTimeUs() const; uint32_t ReceivedInitialRoundTripTimeUs() const; bool HasInitialRoundTripTimeUsToSend() const; uint32_t GetInitialRoundTripTimeUsToSend() const; // Sets an initial stream flow control window size to transmit to the peer. void SetInitialStreamFlowControlWindowToSend(uint32_t window_bytes); uint32_t GetInitialStreamFlowControlWindowToSend() const; bool HasReceivedInitialStreamFlowControlWindowBytes() const; uint32_t ReceivedInitialStreamFlowControlWindowBytes() const; // Sets an initial session flow control window size to transmit to the peer. void SetInitialSessionFlowControlWindowToSend(uint32_t window_bytes); uint32_t GetInitialSessionFlowControlWindowToSend() const; bool HasReceivedInitialSessionFlowControlWindowBytes() const; uint32_t ReceivedInitialSessionFlowControlWindowBytes() const; void SetDisableConnectionMigration(); bool DisableConnectionMigration() const; void SetAlternateServerAddressToSend( const QuicSocketAddress& alternate_server_address); bool HasReceivedAlternateServerAddress() const; const QuicSocketAddress& ReceivedAlternateServerAddress() const; void SetSupportMaxHeaderListSize(); bool SupportMaxHeaderListSize() const; void SetStatelessResetTokenToSend(QuicUint128 stateless_reset_token); bool HasReceivedStatelessResetToken() const; QuicUint128 ReceivedStatelessResetToken() const; bool negotiated() const; void SetCreateSessionTagIndicators(QuicTagVector tags); const QuicTagVector& create_session_tag_indicators() const; // ToHandshakeMessage serialises the settings in this object as a series of // tags /value pairs and adds them to |out|. void ToHandshakeMessage(CryptoHandshakeMessage* out) const; // Calls ProcessPeerHello on each negotiable parameter. On failure returns // the corresponding QuicErrorCode and sets detailed error in |error_details|. QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello, HelloType hello_type, std::string* error_details); // FillTransportParameters writes the values to send for ICSL, MIDS, CFCW, and // SFCW to |*params|, returning true if the values could be written and false // if something prevents them from being written (e.g. a value is too large). bool FillTransportParameters(TransportParameters* params) const; // ProcessTransportParameters reads from |params| which was received from a // peer operating as a |hello_type|. It processes values for ICSL, MIDS, CFCW, // and SFCW and sets the corresponding members of this QuicConfig. On failure, // it returns a QuicErrorCode and puts a detailed error in |*error_details|. QuicErrorCode ProcessTransportParameters(const TransportParameters& params, HelloType hello_type, std::string* error_details); private: friend class test::QuicConfigPeer; // SetDefaults sets the members to sensible, default values. void SetDefaults(); // Configurations options that are not negotiated. // Maximum time the session can be alive before crypto handshake is finished. QuicTime::Delta max_time_before_crypto_handshake_; // Maximum idle time before the crypto handshake has completed. QuicTime::Delta max_idle_time_before_crypto_handshake_; // Maximum number of undecryptable packets stored before CHLO/SHLO. size_t max_undecryptable_packets_; // Connection options which affect the server side. May also affect the // client side in cases when identical behavior is desirable. QuicFixedTagVector connection_options_; // Connection options which only affect the client side. QuicFixedTagVector client_connection_options_; // Idle network timeout in seconds. QuicNegotiableUint32 idle_network_timeout_seconds_; // Whether to use silent close. Defaults to 0 (false) and is otherwise true. QuicNegotiableUint32 silent_close_; // Maximum number of incoming dynamic streams that the connection can support. QuicFixedUint32 max_incoming_dynamic_streams_; // The number of bytes required for the connection ID. QuicFixedUint32 bytes_for_connection_id_; // Initial round trip time estimate in microseconds. QuicFixedUint32 initial_round_trip_time_us_; // Initial stream flow control receive window in bytes. QuicFixedUint32 initial_stream_flow_control_window_bytes_; // Initial session flow control receive window in bytes. QuicFixedUint32 initial_session_flow_control_window_bytes_; // Whether tell peer not to attempt connection migration. QuicFixedUint32 connection_migration_disabled_; // An alternate server address the client could connect to. QuicFixedSocketAddress alternate_server_address_; // Whether support HTTP/2 SETTINGS_MAX_HEADER_LIST_SIZE SETTINGS frame. QuicFixedUint32 support_max_header_list_size_; // Stateless reset token used in IETF public reset packet. QuicFixedUint128 stateless_reset_token_; // List of QuicTags whose presence immediately causes the session to // be created. This allows for CHLOs that are larger than a single // packet to be processed. QuicTagVector create_session_tag_indicators_; }; } // namespace quic #endif // QUICHE_QUIC_CORE_QUIC_CONFIG_H_