|  | // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "quic/core/quic_config.h" | 
|  |  | 
|  | #include <memory> | 
|  | #include <string> | 
|  |  | 
|  | #include "quic/core/crypto/crypto_handshake_message.h" | 
|  | #include "quic/core/crypto/crypto_protocol.h" | 
|  | #include "quic/core/crypto/transport_parameters.h" | 
|  | #include "quic/core/quic_constants.h" | 
|  | #include "quic/core/quic_packets.h" | 
|  | #include "quic/core/quic_time.h" | 
|  | #include "quic/core/quic_utils.h" | 
|  | #include "quic/platform/api/quic_expect_bug.h" | 
|  | #include "quic/platform/api/quic_flags.h" | 
|  | #include "quic/platform/api/quic_test.h" | 
|  | #include "quic/test_tools/quic_config_peer.h" | 
|  | #include "quic/test_tools/quic_test_utils.h" | 
|  |  | 
|  | namespace quic { | 
|  | namespace test { | 
|  | namespace { | 
|  |  | 
|  | class QuicConfigTest : public QuicTestWithParam<ParsedQuicVersion> { | 
|  | public: | 
|  | QuicConfigTest() : version_(GetParam()) {} | 
|  |  | 
|  | protected: | 
|  | ParsedQuicVersion version_; | 
|  | QuicConfig config_; | 
|  | }; | 
|  |  | 
|  | // Run all tests with all versions of QUIC. | 
|  | INSTANTIATE_TEST_SUITE_P(QuicConfigTests, | 
|  | QuicConfigTest, | 
|  | ::testing::ValuesIn(AllSupportedVersions()), | 
|  | ::testing::PrintToStringParamName()); | 
|  |  | 
|  | TEST_P(QuicConfigTest, SetDefaults) { | 
|  | EXPECT_EQ(kMinimumFlowControlSendWindow, | 
|  | config_.GetInitialStreamFlowControlWindowToSend()); | 
|  | EXPECT_EQ(kMinimumFlowControlSendWindow, | 
|  | config_.GetInitialMaxStreamDataBytesIncomingBidirectionalToSend()); | 
|  | EXPECT_EQ(kMinimumFlowControlSendWindow, | 
|  | config_.GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend()); | 
|  | EXPECT_EQ(kMinimumFlowControlSendWindow, | 
|  | config_.GetInitialMaxStreamDataBytesUnidirectionalToSend()); | 
|  | EXPECT_FALSE(config_.HasReceivedInitialStreamFlowControlWindowBytes()); | 
|  | EXPECT_FALSE( | 
|  | config_.HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()); | 
|  | EXPECT_FALSE( | 
|  | config_.HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional()); | 
|  | EXPECT_FALSE(config_.HasReceivedInitialMaxStreamDataBytesUnidirectional()); | 
|  | EXPECT_EQ(kMaxIncomingPacketSize, config_.GetMaxPacketSizeToSend()); | 
|  | EXPECT_FALSE(config_.HasReceivedMaxPacketSize()); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedForConnection()); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedLocally()); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedRemotely()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, AutoSetIetfFlowControl) { | 
|  | EXPECT_EQ(kMinimumFlowControlSendWindow, | 
|  | config_.GetInitialStreamFlowControlWindowToSend()); | 
|  | EXPECT_EQ(kMinimumFlowControlSendWindow, | 
|  | config_.GetInitialMaxStreamDataBytesIncomingBidirectionalToSend()); | 
|  | EXPECT_EQ(kMinimumFlowControlSendWindow, | 
|  | config_.GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend()); | 
|  | EXPECT_EQ(kMinimumFlowControlSendWindow, | 
|  | config_.GetInitialMaxStreamDataBytesUnidirectionalToSend()); | 
|  | static const uint32_t kTestWindowSize = 1234567; | 
|  | config_.SetInitialStreamFlowControlWindowToSend(kTestWindowSize); | 
|  | EXPECT_EQ(kTestWindowSize, config_.GetInitialStreamFlowControlWindowToSend()); | 
|  | EXPECT_EQ(kTestWindowSize, | 
|  | config_.GetInitialMaxStreamDataBytesIncomingBidirectionalToSend()); | 
|  | EXPECT_EQ(kTestWindowSize, | 
|  | config_.GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend()); | 
|  | EXPECT_EQ(kTestWindowSize, | 
|  | config_.GetInitialMaxStreamDataBytesUnidirectionalToSend()); | 
|  | static const uint32_t kTestWindowSizeTwo = 2345678; | 
|  | config_.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend( | 
|  | kTestWindowSizeTwo); | 
|  | EXPECT_EQ(kTestWindowSize, config_.GetInitialStreamFlowControlWindowToSend()); | 
|  | EXPECT_EQ(kTestWindowSizeTwo, | 
|  | config_.GetInitialMaxStreamDataBytesIncomingBidirectionalToSend()); | 
|  | EXPECT_EQ(kTestWindowSize, | 
|  | config_.GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend()); | 
|  | EXPECT_EQ(kTestWindowSize, | 
|  | config_.GetInitialMaxStreamDataBytesUnidirectionalToSend()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, ToHandshakeMessage) { | 
|  | if (version_.UsesTls()) { | 
|  | // CryptoHandshakeMessage is only used for QUIC_CRYPTO. | 
|  | return; | 
|  | } | 
|  | config_.SetInitialStreamFlowControlWindowToSend( | 
|  | kInitialStreamFlowControlWindowForTest); | 
|  | config_.SetInitialSessionFlowControlWindowToSend( | 
|  | kInitialSessionFlowControlWindowForTest); | 
|  | config_.SetIdleNetworkTimeout(QuicTime::Delta::FromSeconds(5)); | 
|  | CryptoHandshakeMessage msg; | 
|  | config_.ToHandshakeMessage(&msg, version_.transport_version); | 
|  |  | 
|  | uint32_t value; | 
|  | QuicErrorCode error = msg.GetUint32(kICSL, &value); | 
|  | EXPECT_THAT(error, IsQuicNoError()); | 
|  | EXPECT_EQ(5u, value); | 
|  |  | 
|  | error = msg.GetUint32(kSFCW, &value); | 
|  | EXPECT_THAT(error, IsQuicNoError()); | 
|  | EXPECT_EQ(kInitialStreamFlowControlWindowForTest, value); | 
|  |  | 
|  | error = msg.GetUint32(kCFCW, &value); | 
|  | EXPECT_THAT(error, IsQuicNoError()); | 
|  | EXPECT_EQ(kInitialSessionFlowControlWindowForTest, value); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, ProcessClientHello) { | 
|  | if (version_.UsesTls()) { | 
|  | // CryptoHandshakeMessage is only used for QUIC_CRYPTO. | 
|  | return; | 
|  | } | 
|  | const uint32_t kTestMaxAckDelayMs = | 
|  | static_cast<uint32_t>(kDefaultDelayedAckTimeMs + 1); | 
|  | QuicConfig client_config; | 
|  | QuicTagVector cgst; | 
|  | cgst.push_back(kQBIC); | 
|  | client_config.SetIdleNetworkTimeout( | 
|  | QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs)); | 
|  | client_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli); | 
|  | client_config.SetInitialStreamFlowControlWindowToSend( | 
|  | 2 * kInitialStreamFlowControlWindowForTest); | 
|  | client_config.SetInitialSessionFlowControlWindowToSend( | 
|  | 2 * kInitialSessionFlowControlWindowForTest); | 
|  | QuicTagVector copt; | 
|  | copt.push_back(kTBBR); | 
|  | client_config.SetConnectionOptionsToSend(copt); | 
|  | client_config.SetMaxAckDelayToSendMs(kTestMaxAckDelayMs); | 
|  | CryptoHandshakeMessage msg; | 
|  | client_config.ToHandshakeMessage(&msg, version_.transport_version); | 
|  |  | 
|  | std::string error_details; | 
|  | QuicTagVector initial_received_options; | 
|  | initial_received_options.push_back(kIW50); | 
|  | EXPECT_TRUE( | 
|  | config_.SetInitialReceivedConnectionOptions(initial_received_options)); | 
|  | EXPECT_FALSE( | 
|  | config_.SetInitialReceivedConnectionOptions(initial_received_options)) | 
|  | << "You can only set initial options once."; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, CLIENT, &error_details); | 
|  | EXPECT_FALSE( | 
|  | config_.SetInitialReceivedConnectionOptions(initial_received_options)) | 
|  | << "You cannot set initial options after the hello."; | 
|  | EXPECT_THAT(error, IsQuicNoError()); | 
|  | EXPECT_TRUE(config_.negotiated()); | 
|  | EXPECT_EQ(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs), | 
|  | config_.IdleNetworkTimeout()); | 
|  | EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs()); | 
|  | EXPECT_TRUE(config_.HasReceivedConnectionOptions()); | 
|  | EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size()); | 
|  | EXPECT_EQ(config_.ReceivedConnectionOptions()[0], kIW50); | 
|  | EXPECT_EQ(config_.ReceivedConnectionOptions()[1], kTBBR); | 
|  | EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(), | 
|  | 2 * kInitialStreamFlowControlWindowForTest); | 
|  | EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(), | 
|  | 2 * kInitialSessionFlowControlWindowForTest); | 
|  | EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs()); | 
|  | EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs()); | 
|  |  | 
|  | // IETF QUIC stream limits should not be received in QUIC crypto messages. | 
|  | EXPECT_FALSE( | 
|  | config_.HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()); | 
|  | EXPECT_FALSE( | 
|  | config_.HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional()); | 
|  | EXPECT_FALSE(config_.HasReceivedInitialMaxStreamDataBytesUnidirectional()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, ProcessServerHello) { | 
|  | if (version_.UsesTls()) { | 
|  | // CryptoHandshakeMessage is only used for QUIC_CRYPTO. | 
|  | return; | 
|  | } | 
|  | QuicIpAddress host; | 
|  | host.FromString("127.0.3.1"); | 
|  | const QuicSocketAddress kTestServerAddress = QuicSocketAddress(host, 1234); | 
|  | const StatelessResetToken kTestStatelessResetToken{ | 
|  | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, | 
|  | 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}; | 
|  | const uint32_t kTestMaxAckDelayMs = | 
|  | static_cast<uint32_t>(kDefaultDelayedAckTimeMs + 1); | 
|  | QuicConfig server_config; | 
|  | QuicTagVector cgst; | 
|  | cgst.push_back(kQBIC); | 
|  | server_config.SetIdleNetworkTimeout( | 
|  | QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2)); | 
|  | server_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli); | 
|  | server_config.SetInitialStreamFlowControlWindowToSend( | 
|  | 2 * kInitialStreamFlowControlWindowForTest); | 
|  | server_config.SetInitialSessionFlowControlWindowToSend( | 
|  | 2 * kInitialSessionFlowControlWindowForTest); | 
|  | server_config.SetIPv4AlternateServerAddressToSend(kTestServerAddress); | 
|  | server_config.SetStatelessResetTokenToSend(kTestStatelessResetToken); | 
|  | server_config.SetMaxAckDelayToSendMs(kTestMaxAckDelayMs); | 
|  | CryptoHandshakeMessage msg; | 
|  | server_config.ToHandshakeMessage(&msg, version_.transport_version); | 
|  | std::string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, SERVER, &error_details); | 
|  | EXPECT_THAT(error, IsQuicNoError()); | 
|  | EXPECT_TRUE(config_.negotiated()); | 
|  | EXPECT_EQ(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2), | 
|  | config_.IdleNetworkTimeout()); | 
|  | EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs()); | 
|  | EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(), | 
|  | 2 * kInitialStreamFlowControlWindowForTest); | 
|  | EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(), | 
|  | 2 * kInitialSessionFlowControlWindowForTest); | 
|  | EXPECT_TRUE(config_.HasReceivedIPv4AlternateServerAddress()); | 
|  | EXPECT_EQ(kTestServerAddress, config_.ReceivedIPv4AlternateServerAddress()); | 
|  | EXPECT_FALSE(config_.HasReceivedIPv6AlternateServerAddress()); | 
|  | EXPECT_TRUE(config_.HasReceivedStatelessResetToken()); | 
|  | EXPECT_EQ(kTestStatelessResetToken, config_.ReceivedStatelessResetToken()); | 
|  | EXPECT_TRUE(config_.HasReceivedMaxAckDelayMs()); | 
|  | EXPECT_EQ(kTestMaxAckDelayMs, config_.ReceivedMaxAckDelayMs()); | 
|  |  | 
|  | // IETF QUIC stream limits should not be received in QUIC crypto messages. | 
|  | EXPECT_FALSE( | 
|  | config_.HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()); | 
|  | EXPECT_FALSE( | 
|  | config_.HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional()); | 
|  | EXPECT_FALSE(config_.HasReceivedInitialMaxStreamDataBytesUnidirectional()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, MissingOptionalValuesInCHLO) { | 
|  | if (version_.UsesTls()) { | 
|  | // CryptoHandshakeMessage is only used for QUIC_CRYPTO. | 
|  | return; | 
|  | } | 
|  | CryptoHandshakeMessage msg; | 
|  | msg.SetValue(kICSL, 1); | 
|  |  | 
|  | // Set all REQUIRED tags. | 
|  | msg.SetValue(kICSL, 1); | 
|  | msg.SetValue(kMIBS, 1); | 
|  |  | 
|  | // No error, as rest are optional. | 
|  | std::string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, CLIENT, &error_details); | 
|  | EXPECT_THAT(error, IsQuicNoError()); | 
|  | EXPECT_TRUE(config_.negotiated()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, MissingOptionalValuesInSHLO) { | 
|  | if (version_.UsesTls()) { | 
|  | // CryptoHandshakeMessage is only used for QUIC_CRYPTO. | 
|  | return; | 
|  | } | 
|  | CryptoHandshakeMessage msg; | 
|  |  | 
|  | // Set all REQUIRED tags. | 
|  | msg.SetValue(kICSL, 1); | 
|  | msg.SetValue(kMIBS, 1); | 
|  |  | 
|  | // No error, as rest are optional. | 
|  | std::string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, SERVER, &error_details); | 
|  | EXPECT_THAT(error, IsQuicNoError()); | 
|  | EXPECT_TRUE(config_.negotiated()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, MissingValueInCHLO) { | 
|  | if (version_.UsesTls()) { | 
|  | // CryptoHandshakeMessage is only used for QUIC_CRYPTO. | 
|  | return; | 
|  | } | 
|  | // Server receives CHLO with missing kICSL. | 
|  | CryptoHandshakeMessage msg; | 
|  | std::string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, CLIENT, &error_details); | 
|  | EXPECT_THAT(error, IsError(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, MissingValueInSHLO) { | 
|  | if (version_.UsesTls()) { | 
|  | // CryptoHandshakeMessage is only used for QUIC_CRYPTO. | 
|  | return; | 
|  | } | 
|  | // Client receives SHLO with missing kICSL. | 
|  | CryptoHandshakeMessage msg; | 
|  | std::string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, SERVER, &error_details); | 
|  | EXPECT_THAT(error, IsError(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, OutOfBoundSHLO) { | 
|  | if (version_.UsesTls()) { | 
|  | // CryptoHandshakeMessage is only used for QUIC_CRYPTO. | 
|  | return; | 
|  | } | 
|  | QuicConfig server_config; | 
|  | server_config.SetIdleNetworkTimeout( | 
|  | QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs)); | 
|  |  | 
|  | CryptoHandshakeMessage msg; | 
|  | server_config.ToHandshakeMessage(&msg, version_.transport_version); | 
|  | std::string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, SERVER, &error_details); | 
|  | EXPECT_THAT(error, IsError(QUIC_INVALID_NEGOTIATED_VALUE)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, InvalidFlowControlWindow) { | 
|  | // QuicConfig should not accept an invalid flow control window to send to the | 
|  | // peer: the receive window must be at least the default of 16 Kb. | 
|  | QuicConfig config; | 
|  | const uint64_t kInvalidWindow = kMinimumFlowControlSendWindow - 1; | 
|  | EXPECT_QUIC_BUG( | 
|  | config.SetInitialStreamFlowControlWindowToSend(kInvalidWindow), | 
|  | "Initial stream flow control receive window"); | 
|  |  | 
|  | EXPECT_EQ(kMinimumFlowControlSendWindow, | 
|  | config.GetInitialStreamFlowControlWindowToSend()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, HasClientSentConnectionOption) { | 
|  | if (version_.UsesTls()) { | 
|  | // CryptoHandshakeMessage is only used for QUIC_CRYPTO. | 
|  | return; | 
|  | } | 
|  | QuicConfig client_config; | 
|  | QuicTagVector copt; | 
|  | copt.push_back(kTBBR); | 
|  | client_config.SetConnectionOptionsToSend(copt); | 
|  | EXPECT_TRUE(client_config.HasClientSentConnectionOption( | 
|  | kTBBR, Perspective::IS_CLIENT)); | 
|  |  | 
|  | CryptoHandshakeMessage msg; | 
|  | client_config.ToHandshakeMessage(&msg, version_.transport_version); | 
|  |  | 
|  | std::string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, CLIENT, &error_details); | 
|  | EXPECT_THAT(error, IsQuicNoError()); | 
|  | EXPECT_TRUE(config_.negotiated()); | 
|  |  | 
|  | EXPECT_TRUE(config_.HasReceivedConnectionOptions()); | 
|  | EXPECT_EQ(1u, config_.ReceivedConnectionOptions().size()); | 
|  | EXPECT_TRUE( | 
|  | config_.HasClientSentConnectionOption(kTBBR, Perspective::IS_SERVER)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, DontSendClientConnectionOptions) { | 
|  | if (version_.UsesTls()) { | 
|  | // CryptoHandshakeMessage is only used for QUIC_CRYPTO. | 
|  | return; | 
|  | } | 
|  | QuicConfig client_config; | 
|  | QuicTagVector copt; | 
|  | copt.push_back(kTBBR); | 
|  | client_config.SetClientConnectionOptions(copt); | 
|  |  | 
|  | CryptoHandshakeMessage msg; | 
|  | client_config.ToHandshakeMessage(&msg, version_.transport_version); | 
|  |  | 
|  | std::string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, CLIENT, &error_details); | 
|  | EXPECT_THAT(error, IsQuicNoError()); | 
|  | EXPECT_TRUE(config_.negotiated()); | 
|  |  | 
|  | EXPECT_FALSE(config_.HasReceivedConnectionOptions()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, HasClientRequestedIndependentOption) { | 
|  | if (version_.UsesTls()) { | 
|  | // CryptoHandshakeMessage is only used for QUIC_CRYPTO. | 
|  | return; | 
|  | } | 
|  | QuicConfig client_config; | 
|  | QuicTagVector client_opt; | 
|  | client_opt.push_back(kRENO); | 
|  | QuicTagVector copt; | 
|  | copt.push_back(kTBBR); | 
|  | client_config.SetClientConnectionOptions(client_opt); | 
|  | client_config.SetConnectionOptionsToSend(copt); | 
|  | EXPECT_TRUE(client_config.HasClientSentConnectionOption( | 
|  | kTBBR, Perspective::IS_CLIENT)); | 
|  | EXPECT_TRUE(client_config.HasClientRequestedIndependentOption( | 
|  | kRENO, Perspective::IS_CLIENT)); | 
|  | EXPECT_FALSE(client_config.HasClientRequestedIndependentOption( | 
|  | kTBBR, Perspective::IS_CLIENT)); | 
|  |  | 
|  | CryptoHandshakeMessage msg; | 
|  | client_config.ToHandshakeMessage(&msg, version_.transport_version); | 
|  |  | 
|  | std::string error_details; | 
|  | const QuicErrorCode error = | 
|  | config_.ProcessPeerHello(msg, CLIENT, &error_details); | 
|  | EXPECT_THAT(error, IsQuicNoError()); | 
|  | EXPECT_TRUE(config_.negotiated()); | 
|  |  | 
|  | EXPECT_TRUE(config_.HasReceivedConnectionOptions()); | 
|  | EXPECT_EQ(1u, config_.ReceivedConnectionOptions().size()); | 
|  | EXPECT_FALSE(config_.HasClientRequestedIndependentOption( | 
|  | kRENO, Perspective::IS_SERVER)); | 
|  | EXPECT_TRUE(config_.HasClientRequestedIndependentOption( | 
|  | kTBBR, Perspective::IS_SERVER)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, IncomingLargeIdleTimeoutTransportParameter) { | 
|  | if (!version_.UsesTls()) { | 
|  | // TransportParameters are only used for QUIC+TLS. | 
|  | return; | 
|  | } | 
|  | // Configure our idle timeout to 60s, then receive 120s from peer. | 
|  | // Since the received value is above ours, we should then use ours. | 
|  | config_.SetIdleNetworkTimeout(quic::QuicTime::Delta::FromSeconds(60)); | 
|  | TransportParameters params; | 
|  | params.max_idle_timeout_ms.set_value(120000); | 
|  |  | 
|  | std::string error_details = "foobar"; | 
|  | EXPECT_THAT(config_.ProcessTransportParameters( | 
|  | params, /* is_resumption = */ false, &error_details), | 
|  | IsQuicNoError()); | 
|  | EXPECT_EQ("", error_details); | 
|  | EXPECT_EQ(quic::QuicTime::Delta::FromSeconds(60), | 
|  | config_.IdleNetworkTimeout()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, ReceivedInvalidMinAckDelayInTransportParameter) { | 
|  | if (!version_.UsesTls()) { | 
|  | // TransportParameters are only used for QUIC+TLS. | 
|  | return; | 
|  | } | 
|  | TransportParameters params; | 
|  |  | 
|  | params.max_ack_delay.set_value(25 /*ms*/); | 
|  | params.min_ack_delay_us.set_value(25 * kNumMicrosPerMilli + 1); | 
|  | std::string error_details = "foobar"; | 
|  | EXPECT_THAT(config_.ProcessTransportParameters( | 
|  | params, /* is_resumption = */ false, &error_details), | 
|  | IsError(IETF_QUIC_PROTOCOL_VIOLATION)); | 
|  | EXPECT_EQ("MinAckDelay is greater than MaxAckDelay.", error_details); | 
|  |  | 
|  | params.max_ack_delay.set_value(25 /*ms*/); | 
|  | params.min_ack_delay_us.set_value(25 * kNumMicrosPerMilli); | 
|  | EXPECT_THAT(config_.ProcessTransportParameters( | 
|  | params, /* is_resumption = */ false, &error_details), | 
|  | IsQuicNoError()); | 
|  | EXPECT_TRUE(error_details.empty()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, FillTransportParams) { | 
|  | if (!version_.UsesTls()) { | 
|  | // TransportParameters are only used for QUIC+TLS. | 
|  | return; | 
|  | } | 
|  | config_.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend( | 
|  | 2 * kMinimumFlowControlSendWindow); | 
|  | config_.SetInitialMaxStreamDataBytesOutgoingBidirectionalToSend( | 
|  | 3 * kMinimumFlowControlSendWindow); | 
|  | config_.SetInitialMaxStreamDataBytesUnidirectionalToSend( | 
|  | 4 * kMinimumFlowControlSendWindow); | 
|  | config_.SetMaxPacketSizeToSend(kMaxPacketSizeForTest); | 
|  | config_.SetMaxDatagramFrameSizeToSend(kMaxDatagramFrameSizeForTest); | 
|  | config_.SetActiveConnectionIdLimitToSend(kActiveConnectionIdLimitForTest); | 
|  |  | 
|  | config_.SetOriginalConnectionIdToSend(TestConnectionId(0x1111)); | 
|  | config_.SetInitialSourceConnectionIdToSend(TestConnectionId(0x2222)); | 
|  | config_.SetRetrySourceConnectionIdToSend(TestConnectionId(0x3333)); | 
|  | config_.SetMinAckDelayMs(kDefaultMinAckDelayTimeMs); | 
|  |  | 
|  | QuicIpAddress host; | 
|  | host.FromString("127.0.3.1"); | 
|  | QuicSocketAddress kTestServerAddress = QuicSocketAddress(host, 1234); | 
|  | QuicConnectionId new_connection_id = TestConnectionId(5); | 
|  | StatelessResetToken new_stateless_reset_token = | 
|  | QuicUtils::GenerateStatelessResetToken(new_connection_id); | 
|  | config_.SetIPv4AlternateServerAddressToSend( | 
|  | kTestServerAddress, new_connection_id, new_stateless_reset_token); | 
|  |  | 
|  | TransportParameters params; | 
|  | config_.FillTransportParameters(¶ms); | 
|  |  | 
|  | EXPECT_EQ(2 * kMinimumFlowControlSendWindow, | 
|  | params.initial_max_stream_data_bidi_remote.value()); | 
|  | EXPECT_EQ(3 * kMinimumFlowControlSendWindow, | 
|  | params.initial_max_stream_data_bidi_local.value()); | 
|  | EXPECT_EQ(4 * kMinimumFlowControlSendWindow, | 
|  | params.initial_max_stream_data_uni.value()); | 
|  |  | 
|  | EXPECT_EQ(static_cast<uint64_t>(kMaximumIdleTimeoutSecs * 1000), | 
|  | params.max_idle_timeout_ms.value()); | 
|  |  | 
|  | EXPECT_EQ(kMaxPacketSizeForTest, params.max_udp_payload_size.value()); | 
|  | EXPECT_EQ(kMaxDatagramFrameSizeForTest, | 
|  | params.max_datagram_frame_size.value()); | 
|  | EXPECT_EQ(kActiveConnectionIdLimitForTest, | 
|  | params.active_connection_id_limit.value()); | 
|  |  | 
|  | ASSERT_TRUE(params.original_destination_connection_id.has_value()); | 
|  | EXPECT_EQ(TestConnectionId(0x1111), | 
|  | params.original_destination_connection_id.value()); | 
|  | ASSERT_TRUE(params.initial_source_connection_id.has_value()); | 
|  | EXPECT_EQ(TestConnectionId(0x2222), | 
|  | params.initial_source_connection_id.value()); | 
|  | ASSERT_TRUE(params.retry_source_connection_id.has_value()); | 
|  | EXPECT_EQ(TestConnectionId(0x3333), | 
|  | params.retry_source_connection_id.value()); | 
|  |  | 
|  | EXPECT_EQ( | 
|  | static_cast<uint64_t>(kDefaultMinAckDelayTimeMs) * kNumMicrosPerMilli, | 
|  | params.min_ack_delay_us.value()); | 
|  | EXPECT_TRUE(params.key_update_not_yet_supported); | 
|  |  | 
|  | EXPECT_EQ(params.preferred_address->ipv4_socket_address, kTestServerAddress); | 
|  | EXPECT_EQ(*reinterpret_cast<StatelessResetToken*>( | 
|  | ¶ms.preferred_address->stateless_reset_token.front()), | 
|  | new_stateless_reset_token); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, ProcessTransportParametersServer) { | 
|  | if (!version_.UsesTls()) { | 
|  | // TransportParameters are only used for QUIC+TLS. | 
|  | return; | 
|  | } | 
|  | TransportParameters params; | 
|  |  | 
|  | params.initial_max_stream_data_bidi_local.set_value( | 
|  | 2 * kMinimumFlowControlSendWindow); | 
|  | params.initial_max_stream_data_bidi_remote.set_value( | 
|  | 3 * kMinimumFlowControlSendWindow); | 
|  | params.initial_max_stream_data_uni.set_value(4 * | 
|  | kMinimumFlowControlSendWindow); | 
|  | params.max_udp_payload_size.set_value(kMaxPacketSizeForTest); | 
|  | params.max_datagram_frame_size.set_value(kMaxDatagramFrameSizeForTest); | 
|  | params.initial_max_streams_bidi.set_value(kDefaultMaxStreamsPerConnection); | 
|  | params.stateless_reset_token = CreateStatelessResetTokenForTest(); | 
|  | params.max_ack_delay.set_value(kMaxAckDelayForTest); | 
|  | params.min_ack_delay_us.set_value(kMinAckDelayUsForTest); | 
|  | params.ack_delay_exponent.set_value(kAckDelayExponentForTest); | 
|  | params.active_connection_id_limit.set_value(kActiveConnectionIdLimitForTest); | 
|  | params.original_destination_connection_id = TestConnectionId(0x1111); | 
|  | params.initial_source_connection_id = TestConnectionId(0x2222); | 
|  | params.retry_source_connection_id = TestConnectionId(0x3333); | 
|  |  | 
|  | std::string error_details; | 
|  | EXPECT_THAT(config_.ProcessTransportParameters( | 
|  | params, /* is_resumption = */ true, &error_details), | 
|  | IsQuicNoError()) | 
|  | << error_details; | 
|  |  | 
|  | EXPECT_FALSE(config_.negotiated()); | 
|  |  | 
|  | ASSERT_TRUE( | 
|  | config_.HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()); | 
|  | EXPECT_EQ(2 * kMinimumFlowControlSendWindow, | 
|  | config_.ReceivedInitialMaxStreamDataBytesIncomingBidirectional()); | 
|  |  | 
|  | ASSERT_TRUE( | 
|  | config_.HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional()); | 
|  | EXPECT_EQ(3 * kMinimumFlowControlSendWindow, | 
|  | config_.ReceivedInitialMaxStreamDataBytesOutgoingBidirectional()); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedInitialMaxStreamDataBytesUnidirectional()); | 
|  | EXPECT_EQ(4 * kMinimumFlowControlSendWindow, | 
|  | config_.ReceivedInitialMaxStreamDataBytesUnidirectional()); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedMaxPacketSize()); | 
|  | EXPECT_EQ(kMaxPacketSizeForTest, config_.ReceivedMaxPacketSize()); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedMaxDatagramFrameSize()); | 
|  | EXPECT_EQ(kMaxDatagramFrameSizeForTest, | 
|  | config_.ReceivedMaxDatagramFrameSize()); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedMaxBidirectionalStreams()); | 
|  | EXPECT_EQ(kDefaultMaxStreamsPerConnection, | 
|  | config_.ReceivedMaxBidirectionalStreams()); | 
|  |  | 
|  | EXPECT_FALSE(config_.DisableConnectionMigration()); | 
|  |  | 
|  | // The following config shouldn't be processed because of resumption. | 
|  | EXPECT_FALSE(config_.HasReceivedStatelessResetToken()); | 
|  | EXPECT_FALSE(config_.HasReceivedMaxAckDelayMs()); | 
|  | EXPECT_FALSE(config_.HasReceivedAckDelayExponent()); | 
|  | EXPECT_FALSE(config_.HasReceivedMinAckDelayMs()); | 
|  | EXPECT_FALSE(config_.HasReceivedOriginalConnectionId()); | 
|  | EXPECT_FALSE(config_.HasReceivedInitialSourceConnectionId()); | 
|  | EXPECT_FALSE(config_.HasReceivedRetrySourceConnectionId()); | 
|  |  | 
|  | // Let the config process another slightly tweaked transport paramters. | 
|  | // Note that the values for flow control and stream limit cannot be smaller | 
|  | // than before. This rule is enforced in QuicSession::OnConfigNegotiated(). | 
|  | params.initial_max_stream_data_bidi_local.set_value( | 
|  | 2 * kMinimumFlowControlSendWindow + 1); | 
|  | params.initial_max_stream_data_bidi_remote.set_value( | 
|  | 4 * kMinimumFlowControlSendWindow); | 
|  | params.initial_max_stream_data_uni.set_value(5 * | 
|  | kMinimumFlowControlSendWindow); | 
|  | params.max_udp_payload_size.set_value(2 * kMaxPacketSizeForTest); | 
|  | params.max_datagram_frame_size.set_value(2 * kMaxDatagramFrameSizeForTest); | 
|  | params.initial_max_streams_bidi.set_value(2 * | 
|  | kDefaultMaxStreamsPerConnection); | 
|  | params.disable_active_migration = true; | 
|  |  | 
|  | EXPECT_THAT(config_.ProcessTransportParameters( | 
|  | params, /* is_resumption = */ false, &error_details), | 
|  | IsQuicNoError()) | 
|  | << error_details; | 
|  |  | 
|  | EXPECT_TRUE(config_.negotiated()); | 
|  |  | 
|  | ASSERT_TRUE( | 
|  | config_.HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()); | 
|  | EXPECT_EQ(2 * kMinimumFlowControlSendWindow + 1, | 
|  | config_.ReceivedInitialMaxStreamDataBytesIncomingBidirectional()); | 
|  |  | 
|  | ASSERT_TRUE( | 
|  | config_.HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional()); | 
|  | EXPECT_EQ(4 * kMinimumFlowControlSendWindow, | 
|  | config_.ReceivedInitialMaxStreamDataBytesOutgoingBidirectional()); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedInitialMaxStreamDataBytesUnidirectional()); | 
|  | EXPECT_EQ(5 * kMinimumFlowControlSendWindow, | 
|  | config_.ReceivedInitialMaxStreamDataBytesUnidirectional()); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedMaxPacketSize()); | 
|  | EXPECT_EQ(2 * kMaxPacketSizeForTest, config_.ReceivedMaxPacketSize()); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedMaxDatagramFrameSize()); | 
|  | EXPECT_EQ(2 * kMaxDatagramFrameSizeForTest, | 
|  | config_.ReceivedMaxDatagramFrameSize()); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedMaxBidirectionalStreams()); | 
|  | EXPECT_EQ(2 * kDefaultMaxStreamsPerConnection, | 
|  | config_.ReceivedMaxBidirectionalStreams()); | 
|  |  | 
|  | EXPECT_TRUE(config_.DisableConnectionMigration()); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedStatelessResetToken()); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedMaxAckDelayMs()); | 
|  | EXPECT_EQ(config_.ReceivedMaxAckDelayMs(), kMaxAckDelayForTest); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedMinAckDelayMs()); | 
|  | EXPECT_EQ(config_.ReceivedMinAckDelayMs(), | 
|  | kMinAckDelayUsForTest / kNumMicrosPerMilli); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedAckDelayExponent()); | 
|  | EXPECT_EQ(config_.ReceivedAckDelayExponent(), kAckDelayExponentForTest); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedActiveConnectionIdLimit()); | 
|  | EXPECT_EQ(config_.ReceivedActiveConnectionIdLimit(), | 
|  | kActiveConnectionIdLimitForTest); | 
|  |  | 
|  | ASSERT_TRUE(config_.HasReceivedOriginalConnectionId()); | 
|  | EXPECT_EQ(config_.ReceivedOriginalConnectionId(), TestConnectionId(0x1111)); | 
|  | ASSERT_TRUE(config_.HasReceivedInitialSourceConnectionId()); | 
|  | EXPECT_EQ(config_.ReceivedInitialSourceConnectionId(), | 
|  | TestConnectionId(0x2222)); | 
|  | ASSERT_TRUE(config_.HasReceivedRetrySourceConnectionId()); | 
|  | EXPECT_EQ(config_.ReceivedRetrySourceConnectionId(), | 
|  | TestConnectionId(0x3333)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, DisableMigrationTransportParameter) { | 
|  | if (!version_.UsesTls()) { | 
|  | // TransportParameters are only used for QUIC+TLS. | 
|  | return; | 
|  | } | 
|  | TransportParameters params; | 
|  | params.disable_active_migration = true; | 
|  | std::string error_details; | 
|  | EXPECT_THAT(config_.ProcessTransportParameters( | 
|  | params, /* is_resumption = */ false, &error_details), | 
|  | IsQuicNoError()); | 
|  | EXPECT_TRUE(config_.DisableConnectionMigration()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, KeyUpdateNotYetSupportedTransportParameterNorLocally) { | 
|  | if (!version_.UsesTls()) { | 
|  | // TransportParameters are only used for QUIC+TLS. | 
|  | return; | 
|  | } | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedForConnection()); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedLocally()); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedRemotely()); | 
|  | TransportParameters params; | 
|  | params.key_update_not_yet_supported = true; | 
|  | std::string error_details; | 
|  | EXPECT_THAT(config_.ProcessTransportParameters( | 
|  | params, /* is_resumption = */ false, &error_details), | 
|  | IsQuicNoError()); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedForConnection()); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedLocally()); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedRemotely()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, KeyUpdateNotYetSupportedTransportParameter) { | 
|  | if (!version_.UsesTls()) { | 
|  | // TransportParameters are only used for QUIC+TLS. | 
|  | return; | 
|  | } | 
|  | config_.SetKeyUpdateSupportedLocally(); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedForConnection()); | 
|  | EXPECT_TRUE(config_.KeyUpdateSupportedLocally()); | 
|  |  | 
|  | TransportParameters params; | 
|  | params.key_update_not_yet_supported = true; | 
|  | std::string error_details; | 
|  | EXPECT_THAT(config_.ProcessTransportParameters( | 
|  | params, /* is_resumption = */ false, &error_details), | 
|  | IsQuicNoError()); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedForConnection()); | 
|  | EXPECT_TRUE(config_.KeyUpdateSupportedLocally()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, KeyUpdateSupportedRemotelyButNotLocally) { | 
|  | if (!version_.UsesTls()) { | 
|  | // TransportParameters are only used for QUIC+TLS. | 
|  | return; | 
|  | } | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedLocally()); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedForConnection()); | 
|  |  | 
|  | TransportParameters params; | 
|  | params.key_update_not_yet_supported = false; | 
|  | std::string error_details; | 
|  | EXPECT_THAT(config_.ProcessTransportParameters( | 
|  | params, /* is_resumption = */ false, &error_details), | 
|  | IsQuicNoError()); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedForConnection()); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedLocally()); | 
|  | EXPECT_TRUE(config_.KeyUpdateSupportedRemotely()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, KeyUpdateSupported) { | 
|  | if (!version_.UsesTls()) { | 
|  | // TransportParameters are only used for QUIC+TLS. | 
|  | return; | 
|  | } | 
|  | config_.SetKeyUpdateSupportedLocally(); | 
|  | EXPECT_TRUE(config_.KeyUpdateSupportedLocally()); | 
|  | EXPECT_FALSE(config_.KeyUpdateSupportedForConnection()); | 
|  |  | 
|  | TransportParameters params; | 
|  | params.key_update_not_yet_supported = false; | 
|  | std::string error_details; | 
|  | EXPECT_THAT(config_.ProcessTransportParameters( | 
|  | params, /* is_resumption = */ false, &error_details), | 
|  | IsQuicNoError()); | 
|  | EXPECT_TRUE(config_.KeyUpdateSupportedForConnection()); | 
|  | EXPECT_TRUE(config_.KeyUpdateSupportedLocally()); | 
|  | EXPECT_TRUE(config_.KeyUpdateSupportedRemotely()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicConfigTest, SendPreferredIPv4Address) { | 
|  | if (!version_.UsesTls()) { | 
|  | // TransportParameters are only used for QUIC+TLS. | 
|  | return; | 
|  | } | 
|  |  | 
|  | EXPECT_FALSE(config_.HasReceivedPreferredAddressConnectionIdAndToken()); | 
|  |  | 
|  | TransportParameters params; | 
|  | QuicIpAddress host; | 
|  | host.FromString("::ffff:192.0.2.128"); | 
|  | QuicSocketAddress kTestServerAddress = QuicSocketAddress(host, 1234); | 
|  | QuicConnectionId new_connection_id = TestConnectionId(5); | 
|  | StatelessResetToken new_stateless_reset_token = | 
|  | QuicUtils::GenerateStatelessResetToken(new_connection_id); | 
|  | auto preferred_address = | 
|  | std::make_unique<TransportParameters::PreferredAddress>(); | 
|  | preferred_address->ipv6_socket_address = kTestServerAddress; | 
|  | preferred_address->connection_id = new_connection_id; | 
|  | preferred_address->stateless_reset_token.assign( | 
|  | reinterpret_cast<const char*>(&new_stateless_reset_token), | 
|  | reinterpret_cast<const char*>(&new_stateless_reset_token) + | 
|  | sizeof(new_stateless_reset_token)); | 
|  | params.preferred_address = std::move(preferred_address); | 
|  |  | 
|  | std::string error_details; | 
|  | EXPECT_THAT(config_.ProcessTransportParameters( | 
|  | params, /* is_resumption = */ false, &error_details), | 
|  | IsQuicNoError()); | 
|  |  | 
|  | EXPECT_TRUE(config_.HasReceivedIPv6AlternateServerAddress()); | 
|  | EXPECT_EQ(config_.ReceivedIPv6AlternateServerAddress(), kTestServerAddress); | 
|  | EXPECT_TRUE(config_.HasReceivedPreferredAddressConnectionIdAndToken()); | 
|  | const std::pair<QuicConnectionId, StatelessResetToken>& | 
|  | preferred_address_connection_id_and_token = | 
|  | config_.ReceivedPreferredAddressConnectionIdAndToken(); | 
|  | EXPECT_EQ(preferred_address_connection_id_and_token.first, new_connection_id); | 
|  | EXPECT_EQ(preferred_address_connection_id_and_token.second, | 
|  | new_stateless_reset_token); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace test | 
|  | }  // namespace quic |