summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrtenneti <rtenneti@chromium.org>2014-12-19 13:11:01 -0800
committerCommit bot <commit-bot@chromium.org>2014-12-19 21:12:16 +0000
commit59338df454a296a6d4c7202390d0f1214a605c3b (patch)
treea936c41482a9e2f3f2bfe9c9e05315c60c7b5848
parent5d6a416f73c9750d65996ee12a79a772a7b8d28a (diff)
downloadchromium_src-59338df454a296a6d4c7202390d0f1214a605c3b.zip
chromium_src-59338df454a296a6d4c7202390d0f1214a605c3b.tar.gz
chromium_src-59338df454a296a6d4c7202390d0f1214a605c3b.tar.bz2
Land Recent QUIC Changes.
Clean up source address token tests in quic_crypto_server_config_test.cc Merge internal change: 82257112 https://codereview.chromium.org/809903003/ If using QUIC bandwidth resumption, then set initial RTT estimate from provided CachedNetworkParameters. Flag protected with existing, ENABLEd, FLAGS_quic_enable_bandwidth_resumption_experiment This will override an RTT estimate provided in the CHLO; but as this is min_rtt, not srtt provided in the CHLO, this is probably better as an initial setting. Merge internal change: 82256698 https://codereview.chromium.org/788403006/ remove deprecated FLAGS_enable_quic_delay_forward_security Merge internal change: 82247940 https://codereview.chromium.org/811903002/ Use <cmath> instead of <math.h> for cbrt function. Fixes comments for Merge internal change: 82182140 Allow the QUIC source address token to contain information about multiple address, to help improve the 0-RTT rate. Merge internal change: 82162516 https://codereview.chromium.org/812563003/ Adding spdy framing error details to the quic error string. Merge internal change: 82148428 https://codereview.chromium.org/802633004/ Increase the min_rtt threshold for hybrid slow start from 1/16th of min rtt to 1/8th. This is motivated by the fact that a min_rtt increase of 1/16th of an rtt is too small, particularly in QUIC's more noisy userspace implementations. Merge internal change: 82021742 https://codereview.chromium.org/787763009/ No behavior change, update QuicAckNotifier to use range-based loops, and std::unordered_{set,map} Merge internal change: 82021332 https://codereview.chromium.org/808453004/ Fix use-after-free crash when multiple ACKs are added to the QUIC packet generator. Protected behind ENABLEd FLAGS_quic_disallow_multiple_pending_ack_frames Merge internal change: 81821249 BUG=439600 https://codereview.chromium.org/810603002/ Remove the deprecated quic_too_many_outstanding_packets reloadable flag. Merge internal change: 81787580 https://codereview.chromium.org/806913004/ R=rch@chromium.org Review URL: https://codereview.chromium.org/811633007 Cr-Commit-Position: refs/heads/master@{#309260}
-rw-r--r--net/quic/congestion_control/cubic.cc2
-rw-r--r--net/quic/congestion_control/hybrid_slow_start.cc3
-rw-r--r--net/quic/congestion_control/hybrid_slow_start_test.cc8
-rw-r--r--net/quic/crypto/cached_network_parameters.cc1
-rw-r--r--net/quic/crypto/cached_network_parameters.h4
-rw-r--r--net/quic/crypto/quic_crypto_server_config.cc182
-rw-r--r--net/quic/crypto/quic_crypto_server_config.h52
-rw-r--r--net/quic/crypto/quic_crypto_server_config_test.cc394
-rw-r--r--net/quic/crypto/source_address_token.cc24
-rw-r--r--net/quic/crypto/source_address_token.h31
-rw-r--r--net/quic/quic_ack_notifier.cc3
-rw-r--r--net/quic/quic_ack_notifier_manager.cc80
-rw-r--r--net/quic/quic_connection.cc15
-rw-r--r--net/quic/quic_connection_test.cc19
-rw-r--r--net/quic/quic_crypto_server_stream.cc7
-rw-r--r--net/quic/quic_crypto_server_stream.h4
-rw-r--r--net/quic/quic_flags.cc16
-rw-r--r--net/quic/quic_flags.h3
-rw-r--r--net/quic/quic_headers_stream.cc5
-rw-r--r--net/quic/quic_headers_stream_test.cc9
-rw-r--r--net/quic/quic_packet_generator.cc25
-rw-r--r--net/quic/quic_packet_generator_test.cc25
-rw-r--r--net/quic/quic_sent_packet_manager.cc7
-rw-r--r--net/quic/quic_sent_packet_manager_test.cc13
-rw-r--r--net/quic/quic_session_test.cc6
25 files changed, 720 insertions, 218 deletions
diff --git a/net/quic/congestion_control/cubic.cc b/net/quic/congestion_control/cubic.cc
index 58b5385..7b99057 100644
--- a/net/quic/congestion_control/cubic.cc
+++ b/net/quic/congestion_control/cubic.cc
@@ -4,8 +4,8 @@
#include "net/quic/congestion_control/cubic.h"
-#include <math.h>
#include <algorithm>
+#include <cmath>
#include "base/basictypes.h"
#include "base/logging.h"
diff --git a/net/quic/congestion_control/hybrid_slow_start.cc b/net/quic/congestion_control/hybrid_slow_start.cc
index e3789b4..b7e10b9f 100644
--- a/net/quic/congestion_control/hybrid_slow_start.cc
+++ b/net/quic/congestion_control/hybrid_slow_start.cc
@@ -16,7 +16,8 @@ namespace net {
const int64 kHybridStartLowWindow = 16;
// Number of delay samples for detecting the increase of delay.
const uint32 kHybridStartMinSamples = 8;
-const int kHybridStartDelayFactorExp = 4; // 2^4 = 16
+// Exit slow start if the min rtt has increased by more than 1/8th.
+const int kHybridStartDelayFactorExp = 3; // 2^3 = 8
// The original paper specifies 2 and 8ms, but those have changed over time.
const int64 kHybridStartDelayMinThresholdUs = 4000;
const int64 kHybridStartDelayMaxThresholdUs = 16000;
diff --git a/net/quic/congestion_control/hybrid_slow_start_test.cc b/net/quic/congestion_control/hybrid_slow_start_test.cc
index bcdf8d9..5b98733 100644
--- a/net/quic/congestion_control/hybrid_slow_start_test.cc
+++ b/net/quic/congestion_control/hybrid_slow_start_test.cc
@@ -84,8 +84,8 @@ TEST_F(HybridSlowStartTest, AckTrain) {
}
TEST_F(HybridSlowStartTest, Delay) {
- // We expect to detect the increase at +1/16 of the RTT; hence at a typical
- // RTT of 60ms the detection will happen at 63.75 ms.
+ // We expect to detect the increase at +1/8 of the RTT; hence at a typical
+ // RTT of 60ms the detection will happen at 67.5 ms.
const int kHybridStartMinSamples = 8; // Number of acks required to trigger.
QuicPacketSequenceNumber end_sequence_number = 1;
@@ -100,12 +100,12 @@ TEST_F(HybridSlowStartTest, Delay) {
slow_start_->StartReceiveRound(end_sequence_number++);
for (int n = 1; n < kHybridStartMinSamples; ++n) {
EXPECT_FALSE(slow_start_->ShouldExitSlowStart(
- rtt_.Add(QuicTime::Delta::FromMilliseconds(n + 5)), rtt_, 100));
+ rtt_.Add(QuicTime::Delta::FromMilliseconds(n + 10)), rtt_, 100));
}
// Expect to trigger since all packets in this burst was above the long term
// RTT provided.
EXPECT_TRUE(slow_start_->ShouldExitSlowStart(
- rtt_.Add(QuicTime::Delta::FromMilliseconds(5)), rtt_, 100));
+ rtt_.Add(QuicTime::Delta::FromMilliseconds(10)), rtt_, 100));
}
} // namespace test
diff --git a/net/quic/crypto/cached_network_parameters.cc b/net/quic/crypto/cached_network_parameters.cc
index 20a438b7..c9582f1 100644
--- a/net/quic/crypto/cached_network_parameters.cc
+++ b/net/quic/crypto/cached_network_parameters.cc
@@ -11,6 +11,7 @@ CachedNetworkParameters::CachedNetworkParameters()
max_bandwidth_estimate_bytes_per_second_(0),
max_bandwidth_timestamp_seconds_(0),
min_rtt_ms_(0),
+ has_min_rtt_ms_(false),
previous_connection_state_(0),
timestamp_(0) {
}
diff --git a/net/quic/crypto/cached_network_parameters.h b/net/quic/crypto/cached_network_parameters.h
index 5f22070..34c8917 100644
--- a/net/quic/crypto/cached_network_parameters.h
+++ b/net/quic/crypto/cached_network_parameters.h
@@ -68,7 +68,9 @@ class NET_EXPORT_PRIVATE CachedNetworkParameters {
}
void set_min_rtt_ms(int32 min_rtt_ms) {
min_rtt_ms_ = min_rtt_ms;
+ has_min_rtt_ms_ = true;
}
+ bool has_min_rtt_ms() const { return has_min_rtt_ms_; }
int32 previous_connection_state() const {
return previous_connection_state_;
@@ -98,6 +100,8 @@ class NET_EXPORT_PRIVATE CachedNetworkParameters {
// The min RTT seen on a previous connection can be used by the server to
// inform initial connection parameters for new connections.
int32 min_rtt_ms_;
+ // Whenever min_rtt_ms_ is updated, it is set to true.
+ bool has_min_rtt_ms_;
// Encodes the PreviousConnectionState enum.
int32 previous_connection_state_;
// UNIX timestamp when this bandwidth estimate was created.
diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc
index f752a9e..4a5dc8a 100644
--- a/net/quic/crypto/quic_crypto_server_config.cc
+++ b/net/quic/crypto/quic_crypto_server_config.cc
@@ -50,6 +50,8 @@ namespace net {
namespace {
+const size_t kMaxTokenAddresses = 4;
+
string DeriveSourceAddressTokenKey(StringPiece source_address_token_secret) {
crypto::HKDF hkdf(source_address_token_secret,
StringPiece() /* no salt */,
@@ -765,12 +767,10 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
(QuicVersionToQuicTag(supported_versions[i]));
}
out->SetVector(kVER, supported_version_tags);
- out->SetStringPiece(kSourceAddressTokenTag,
- NewSourceAddressToken(*requested_config.get(),
- client_address,
- rand,
- info.now,
- nullptr));
+ out->SetStringPiece(
+ kSourceAddressTokenTag,
+ NewSourceAddressToken(*requested_config.get(), info.source_address_tokens,
+ client_address, rand, info.now, nullptr));
QuicSocketAddressCoder address_coder(client_address);
out->SetStringPiece(kCADR, address_coder.Encode());
out->SetStringPiece(kPUBS, forward_secure_public_value);
@@ -940,12 +940,20 @@ void QuicCryptoServerConfig::EvaluateClientHello(
HandshakeFailureReason source_address_token_error;
StringPiece srct;
if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) {
- source_address_token_error =
- ValidateSourceAddressToken(*requested_config.get(),
- srct,
- info->client_ip,
- info->now,
- &client_hello_state->cached_network_params);
+ if (!FLAGS_quic_use_multiple_address_in_source_tokens) {
+ source_address_token_error = ValidateSourceAddressToken(
+ *requested_config.get(), srct, info->client_ip, info->now,
+ &client_hello_state->cached_network_params);
+ } else {
+ source_address_token_error = ParseSourceAddressToken(
+ *requested_config.get(), srct, &info->source_address_tokens);
+
+ if (source_address_token_error == HANDSHAKE_OK) {
+ source_address_token_error = ValidateSourceAddressTokens(
+ info->source_address_tokens, info->client_ip, info->now,
+ &client_hello_state->cached_network_params);
+ }
+ }
info->valid_source_address_token =
(source_address_token_error == HANDSHAKE_OK);
} else {
@@ -1035,6 +1043,7 @@ void QuicCryptoServerConfig::EvaluateClientHello(
}
bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
+ const SourceAddressTokens& previous_source_address_tokens,
const IPEndPoint& server_ip,
const IPEndPoint& client_ip,
const QuicClock* clock,
@@ -1045,12 +1054,11 @@ bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
base::AutoLock locked(configs_lock_);
out->set_tag(kSCUP);
out->SetStringPiece(kSCFG, primary_config_->serialized);
- out->SetStringPiece(kSourceAddressTokenTag,
- NewSourceAddressToken(*primary_config_.get(),
- client_ip,
- rand,
- clock->WallNow(),
- cached_network_params));
+ out->SetStringPiece(
+ kSourceAddressTokenTag,
+ NewSourceAddressToken(*primary_config_.get(),
+ previous_source_address_tokens, client_ip, rand,
+ clock->WallNow(), cached_network_params));
if (proof_source_ == nullptr) {
// Insecure QUIC, can send SCFG without proof.
@@ -1086,13 +1094,10 @@ void QuicCryptoServerConfig::BuildRejection(
CryptoHandshakeMessage* out) const {
out->set_tag(kREJ);
out->SetStringPiece(kSCFG, config.serialized);
- out->SetStringPiece(kSourceAddressTokenTag,
- NewSourceAddressToken(
- config,
- info.client_ip,
- rand,
- info.now,
- &cached_network_params));
+ out->SetStringPiece(
+ kSourceAddressTokenTag,
+ NewSourceAddressToken(config, info.source_address_tokens, info.client_ip,
+ rand, info.now, &cached_network_params));
if (replay_protection_) {
out->SetStringPiece(kServerNonceTag, NewServerNonce(rand, info.now));
}
@@ -1412,6 +1417,7 @@ void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
string QuicCryptoServerConfig::NewSourceAddressToken(
const Config& config,
+ const SourceAddressTokens& previous_tokens,
const IPEndPoint& ip,
QuicRandom* rand,
QuicWallTime now,
@@ -1420,21 +1426,80 @@ string QuicCryptoServerConfig::NewSourceAddressToken(
if (ip.GetSockAddrFamily() == AF_INET) {
ip_address = ConvertIPv4NumberToIPv6Number(ip_address);
}
- SourceAddressToken source_address_token;
- source_address_token.set_ip(IPAddressToPackedString(ip_address));
- source_address_token.set_timestamp(now.ToUNIXSeconds());
+ SourceAddressTokens source_address_tokens;
+ SourceAddressToken* source_address_token = source_address_tokens.add_tokens();
+ source_address_token->set_ip(IPAddressToPackedString(ip_address));
+ source_address_token->set_timestamp(now.ToUNIXSeconds());
if (cached_network_params != nullptr) {
- source_address_token.set_cached_network_parameters(*cached_network_params);
+ *(source_address_token->mutable_cached_network_parameters()) =
+ *cached_network_params;
+ }
+
+ if (!FLAGS_quic_use_multiple_address_in_source_tokens) {
+ return config.source_address_token_boxer->Box(
+ rand, source_address_token->SerializeAsString());
+ }
+
+ // Append previous tokens.
+ for (size_t i = 0; i < previous_tokens.tokens_size(); i++) {
+ const SourceAddressToken& token = previous_tokens.tokens(i);
+ if (source_address_tokens.tokens_size() > kMaxTokenAddresses) {
+ break;
+ }
+
+ if (token.ip() == source_address_token->ip()) {
+ // It's for the same IP address.
+ continue;
+ }
+
+ if (ValidateSourceAddressTokenTimestamp(token, now) != HANDSHAKE_OK) {
+ continue;
+ }
+
+ *(source_address_tokens.add_tokens()) = token;
}
return config.source_address_token_boxer->Box(
- rand, source_address_token.SerializeAsString());
+ rand, source_address_tokens.SerializeAsString());
}
bool QuicCryptoServerConfig::HasProofSource() const {
return proof_source_ != nullptr;
}
+HandshakeFailureReason QuicCryptoServerConfig::ParseSourceAddressToken(
+ const Config& config,
+ StringPiece token,
+ SourceAddressTokens* tokens) const {
+ string storage;
+ StringPiece plaintext;
+ if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) {
+ return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE;
+ }
+
+ if (!FLAGS_quic_use_multiple_address_in_source_tokens) {
+ SourceAddressToken token;
+ if (!token.ParseFromArray(plaintext.data(), plaintext.size())) {
+ return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE;
+ }
+ *(tokens->add_tokens()) = token;
+ return HANDSHAKE_OK;
+ }
+
+ if (!tokens->ParseFromArray(plaintext.data(), plaintext.size())) {
+ // Some clients might still be using the old source token format so
+ // attempt to parse that format.
+ // TODO(rch): remove this code once the new format is ubiquitous.
+ SourceAddressToken token;
+ if (!token.ParseFromArray(plaintext.data(), plaintext.size())) {
+ return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE;
+ }
+ *tokens->add_tokens() = token;
+ }
+
+ return HANDSHAKE_OK;
+}
+
HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressToken(
const Config& config,
StringPiece token,
@@ -1483,6 +1548,63 @@ HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressToken(
return HANDSHAKE_OK;
}
+HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressTokens(
+ const SourceAddressTokens& source_address_tokens,
+ const IPEndPoint& ip,
+ QuicWallTime now,
+ CachedNetworkParameters* cached_network_params) const {
+ HandshakeFailureReason reason =
+ SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
+ for (size_t i = 0; i < source_address_tokens.tokens_size(); i++) {
+ const SourceAddressToken& token = source_address_tokens.tokens(i);
+ reason = ValidateSingleSourceAddressToken(token, ip, now);
+ if (reason == HANDSHAKE_OK) {
+ if (token.has_cached_network_parameters()) {
+ *cached_network_params = token.cached_network_parameters();
+ }
+ break;
+ }
+ }
+ return reason;
+}
+
+HandshakeFailureReason QuicCryptoServerConfig::ValidateSingleSourceAddressToken(
+ const SourceAddressToken& source_address_token,
+ const IPEndPoint& ip,
+ QuicWallTime now) const {
+ IPAddressNumber ip_address = ip.address();
+ if (ip.GetSockAddrFamily() == AF_INET) {
+ ip_address = ConvertIPv4NumberToIPv6Number(ip_address);
+ }
+ if (source_address_token.ip() != IPAddressToPackedString(ip_address)) {
+ // It's for a different IP address.
+ return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
+ }
+
+ return ValidateSourceAddressTokenTimestamp(source_address_token, now);
+}
+
+HandshakeFailureReason
+QuicCryptoServerConfig::ValidateSourceAddressTokenTimestamp(
+ const SourceAddressToken& source_address_token,
+ QuicWallTime now) const {
+ const QuicWallTime timestamp(
+ QuicWallTime::FromUNIXSeconds(source_address_token.timestamp()));
+ const QuicTime::Delta delta(now.AbsoluteDifference(timestamp));
+
+ if (now.IsBefore(timestamp) &&
+ delta.ToSeconds() > source_address_token_future_secs_) {
+ return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE;
+ }
+
+ if (now.IsAfter(timestamp) &&
+ delta.ToSeconds() > source_address_token_lifetime_secs_) {
+ return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE;
+ }
+
+ return HANDSHAKE_OK;
+}
+
// kServerNoncePlaintextSize is the number of bytes in an unencrypted server
// nonce.
static const size_t kServerNoncePlaintextSize =
diff --git a/net/quic/crypto/quic_crypto_server_config.h b/net/quic/crypto/quic_crypto_server_config.h
index bce4a3f..da8713a 100644
--- a/net/quic/crypto/quic_crypto_server_config.h
+++ b/net/quic/crypto/quic_crypto_server_config.h
@@ -20,6 +20,7 @@
#include "net/quic/crypto/crypto_handshake_message.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/crypto_secret_boxer.h"
+#include "net/quic/crypto/source_address_token.h"
#include "net/quic/quic_time.h"
namespace net {
@@ -54,6 +55,7 @@ struct ClientHelloInfo {
base::StringPiece client_nonce;
base::StringPiece server_nonce;
base::StringPiece user_agent_id;
+ SourceAddressTokens source_address_tokens;
// Errors from EvaluateClientHello.
std::vector<uint32> reject_reasons;
@@ -257,6 +259,7 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
//
// |cached_network_params| is optional, and can be nullptr.
bool BuildServerConfigUpdateMessage(
+ const SourceAddressTokens& previous_source_address_tokens,
const IPEndPoint& server_ip,
const IPEndPoint& client_ip,
const QuicClock* clock,
@@ -442,16 +445,28 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// IP address. |cached_network_params| is optional, and can be nullptr.
std::string NewSourceAddressToken(
const Config& config,
+ const SourceAddressTokens& previous_tokens,
const IPEndPoint& ip,
QuicRandom* rand,
QuicWallTime now,
const CachedNetworkParameters* cached_network_params) const;
- // ValidateSourceAddressToken returns HANDSHAKE_OK if the source address token
- // in |token| is a valid and timely token for the IP address |ip| given that
- // the current time is |now|. Otherwise it returns the reason for failure.
- // |cached_network_params| is populated if |token| contains a
- // CachedNetworkParameters proto.
+ // ParseSourceAddressToken parses the source address tokens contained in
+ // the encrypted |token|, and populates |tokens| with the parsed tokens.
+ // Returns HANDSHAKE_OK if |token| could be parsed, or the reason for the
+ // failure.
+ HandshakeFailureReason ParseSourceAddressToken(
+ const Config& config,
+ base::StringPiece token,
+ SourceAddressTokens* tokens) const;
+
+ // ValidateSourceAddressToken returns HANDSHAKE_OK if the source address
+ // tokens in |tokens| contain a valid and timely token for the IP address
+ // |ip| given that the current time is |now|. Otherwise it returns the
+ // reason for failure. |cached_network_params| is populated if the valid
+ // token contains a CachedNetworkParameters proto.
+ // TODO(rch): remove this method when we remove:
+ // FLAGS_quic_use_multiple_address_in_source_tokens.
HandshakeFailureReason ValidateSourceAddressToken(
const Config& config,
base::StringPiece token,
@@ -459,6 +474,33 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
QuicWallTime now,
CachedNetworkParameters* cached_network_params) const;
+ // ValidateSourceAddressTokens returns HANDSHAKE_OK if the source address
+ // tokens in |tokens| contain a valid and timely token for the IP address
+ // |ip| given that the current time is |now|. Otherwise it returns the
+ // reason for failure. |cached_network_params| is populated if the valid
+ // token contains a CachedNetworkParameters proto.
+ HandshakeFailureReason ValidateSourceAddressTokens(
+ const SourceAddressTokens& tokens,
+ const IPEndPoint& ip,
+ QuicWallTime now,
+ CachedNetworkParameters* cached_network_params) const;
+
+ // ValidateSingleSourceAddressToken returns HANDSHAKE_OK if the source
+ // address token in |token| is a timely token for the IP address |ip|
+ // given that the current time is |now|. Otherwise it returns the reason
+ // for failure.
+ HandshakeFailureReason ValidateSingleSourceAddressToken(
+ const SourceAddressToken& token,
+ const IPEndPoint& ip,
+ QuicWallTime now) const;
+
+ // Returns HANDSHAKE_OK if the source address token in |token| is a timely
+ // token given that the current time is |now|. Otherwise it returns the
+ // reason for failure.
+ HandshakeFailureReason ValidateSourceAddressTokenTimestamp(
+ const SourceAddressToken& token,
+ QuicWallTime now) const;
+
// NewServerNonce generates and encrypts a random nonce.
std::string NewServerNonce(QuicRandom* rand, QuicWallTime now) const;
diff --git a/net/quic/crypto/quic_crypto_server_config_test.cc b/net/quic/crypto/quic_crypto_server_config_test.cc
index 4453b76..6948165 100644
--- a/net/quic/crypto/quic_crypto_server_config_test.cc
+++ b/net/quic/crypto/quic_crypto_server_config_test.cc
@@ -13,6 +13,7 @@
#include "net/quic/crypto/crypto_server_config_protobuf.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/crypto/strike_register_client.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_time.h"
#include "net/quic/test_tools/mock_clock.h"
#include "net/quic/test_tools/quic_test_utils.h"
@@ -50,22 +51,31 @@ class QuicCryptoServerConfigPeer {
&(server_config_->default_source_address_token_boxer_);
}
- string NewSourceAddressToken(
- string config_id,
- const IPEndPoint& ip,
- QuicRandom* rand,
- QuicWallTime now) {
+ string NewSourceAddressToken(string config_id,
+ const IPEndPoint& ip,
+ QuicRandom* rand,
+ QuicWallTime now) {
return NewSourceAddressToken(config_id, ip, rand, now, NULL);
}
- string NewSourceAddressToken(
- string config_id,
- const IPEndPoint& ip,
- QuicRandom* rand,
- QuicWallTime now,
- CachedNetworkParameters* cached_network_params) {
+ string NewSourceAddressToken(string config_id,
+ const IPEndPoint& ip,
+ QuicRandom* rand,
+ QuicWallTime now,
+ const SourceAddressTokens& previous_tokens) {
return server_config_->NewSourceAddressToken(
- *GetConfig(config_id), ip, rand, now, cached_network_params);
+ *GetConfig(config_id), previous_tokens, ip, rand, now, NULL);
+ }
+
+ string NewSourceAddressToken(string config_id,
+ const IPEndPoint& ip,
+ QuicRandom* rand,
+ QuicWallTime now,
+ CachedNetworkParameters* cached_network_params) {
+ SourceAddressTokens previous_tokens;
+ return server_config_->NewSourceAddressToken(*GetConfig(config_id),
+ previous_tokens, ip, rand, now,
+ cached_network_params);
}
HandshakeFailureReason ValidateSourceAddressToken(string config_id,
@@ -85,6 +95,30 @@ class QuicCryptoServerConfigPeer {
*GetConfig(config_id), srct, ip, now, cached_network_params);
}
+ HandshakeFailureReason ValidateSourceAddressTokens(string config_id,
+ StringPiece srct,
+ const IPEndPoint& ip,
+ QuicWallTime now) {
+ return ValidateSourceAddressTokens(config_id, srct, ip, now, NULL);
+ }
+
+ HandshakeFailureReason ValidateSourceAddressTokens(
+ string config_id,
+ StringPiece srct,
+ const IPEndPoint& ip,
+ QuicWallTime now,
+ CachedNetworkParameters* cached_network_params) {
+ SourceAddressTokens tokens;
+ HandshakeFailureReason reason = server_config_->ParseSourceAddressToken(
+ *GetConfig(config_id), srct, &tokens);
+ if (reason != HANDSHAKE_OK) {
+ return reason;
+ }
+
+ return server_config_->ValidateSourceAddressTokens(tokens, ip, now,
+ cached_network_params);
+ }
+
string NewServerNonce(QuicRandom* rand, QuicWallTime now) const {
return server_config_->NewServerNonce(rand, now);
}
@@ -257,110 +291,294 @@ TEST(QuicCryptoServerConfigTest, GetOrbitIsCalledWithoutTheStrikeRegisterLock) {
EXPECT_TRUE(strike_register->is_known_orbit_called());
}
-TEST(QuicCryptoServerConfigTest, SourceAddressTokens) {
+class SourceAddressTokenTest : public ::testing::Test {
+ public:
+ SourceAddressTokenTest()
+ : ip4_(IPEndPoint(Loopback4(), 1)),
+ ip4_dual_(ConvertIPv4NumberToIPv6Number(ip4_.address()), 1),
+ ip6_(IPEndPoint(Loopback6(), 2)),
+ original_time_(QuicWallTime::Zero()),
+ rand_(QuicRandom::GetInstance()),
+ server_(QuicCryptoServerConfig::TESTING, rand_),
+ peer_(&server_) {
+ // Advance the clock to some non-zero time.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000000));
+ original_time_ = clock_.WallNow();
+
+ primary_config_.reset(server_.AddDefaultConfig(
+ rand_, &clock_, QuicCryptoServerConfig::ConfigOptions()));
+
+ // Add a config that overrides the default boxer.
+ QuicCryptoServerConfig::ConfigOptions options;
+ options.id = kOverride;
+ override_config_protobuf_.reset(
+ QuicCryptoServerConfig::GenerateConfig(rand_, &clock_, options));
+ override_config_protobuf_->set_source_address_token_secret_override(
+ "a secret key");
+ // Lower priority than the default config.
+ override_config_protobuf_->set_priority(1);
+ override_config_.reset(
+ server_.AddConfig(override_config_protobuf_.get(), original_time_));
+ }
+
const string kPrimary = "<primary>";
const string kOverride = "Config with custom source address token key";
- MockClock clock;
- clock.AdvanceTime(QuicTime::Delta::FromSeconds(1000000));
+ IPEndPoint ip4_;
+ IPEndPoint ip4_dual_;
+ IPEndPoint ip6_;
- QuicWallTime now = clock.WallNow();
- const QuicWallTime original_time = now;
+ MockClock clock_;
+ QuicWallTime original_time_;
+ QuicRandom* rand_ = QuicRandom::GetInstance();
+ QuicCryptoServerConfig server_;
+ QuicCryptoServerConfigPeer peer_;
+ // Stores the primary config.
+ scoped_ptr<CryptoHandshakeMessage> primary_config_;
+ scoped_ptr<QuicServerConfigProtobuf> override_config_protobuf_;
+ scoped_ptr<CryptoHandshakeMessage> override_config_;
+};
- QuicRandom* rand = QuicRandom::GetInstance();
- QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand);
- QuicCryptoServerConfigPeer peer(&server);
+TEST_F(SourceAddressTokenTest, SourceAddressToken) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens,
+ false);
- scoped_ptr<CryptoHandshakeMessage>(
- server.AddDefaultConfig(rand, &clock,
- QuicCryptoServerConfig::ConfigOptions()));
+ QuicWallTime now = clock_.WallNow();
- // Add a config that overrides the default boxer.
- QuicCryptoServerConfig::ConfigOptions options;
- options.id = kOverride;
- scoped_ptr<QuicServerConfigProtobuf> protobuf(
- QuicCryptoServerConfig::GenerateConfig(rand, &clock, options));
- protobuf->set_source_address_token_secret_override("a secret key");
- // Lower priority than the default config.
- protobuf->set_priority(1);
- scoped_ptr<CryptoHandshakeMessage>(
- server.AddConfig(protobuf.get(), now));
+ EXPECT_TRUE(peer_.ConfigHasDefaultSourceAddressTokenBoxer(kPrimary));
+ EXPECT_FALSE(peer_.ConfigHasDefaultSourceAddressTokenBoxer(kOverride));
+
+ // Primary config generates configs that validate successfully.
+ const string token4 = peer_.NewSourceAddressToken(kPrimary, ip4_, rand_, now);
+ const string token4d =
+ peer_.NewSourceAddressToken(kPrimary, ip4_dual_, rand_, now);
+ const string token6 = peer_.NewSourceAddressToken(kPrimary, ip6_, rand_, now);
+ EXPECT_EQ(HANDSHAKE_OK,
+ peer_.ValidateSourceAddressToken(kPrimary, token4, ip4_, now));
+ ASSERT_EQ(HANDSHAKE_OK,
+ peer_.ValidateSourceAddressToken(kPrimary, token4, ip4_dual_, now));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
+ peer_.ValidateSourceAddressToken(kPrimary, token4, ip6_, now));
+ ASSERT_EQ(HANDSHAKE_OK,
+ peer_.ValidateSourceAddressToken(kPrimary, token4d, ip4_, now));
+ ASSERT_EQ(HANDSHAKE_OK, peer_.ValidateSourceAddressToken(kPrimary, token4d,
+ ip4_dual_, now));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
+ peer_.ValidateSourceAddressToken(kPrimary, token4d, ip6_, now));
+ ASSERT_EQ(HANDSHAKE_OK,
+ peer_.ValidateSourceAddressToken(kPrimary, token6, ip6_, now));
+
+ // Override config generates configs that validate successfully.
+ const string override_token4 =
+ peer_.NewSourceAddressToken(kOverride, ip4_, rand_, now);
+ const string override_token6 =
+ peer_.NewSourceAddressToken(kOverride, ip6_, rand_, now);
+ ASSERT_EQ(HANDSHAKE_OK, peer_.ValidateSourceAddressToken(
+ kOverride, override_token4, ip4_, now));
+ ASSERT_EQ(
+ SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
+ peer_.ValidateSourceAddressToken(kOverride, override_token4, ip6_, now));
+ ASSERT_EQ(HANDSHAKE_OK, peer_.ValidateSourceAddressToken(
+ kOverride, override_token6, ip6_, now));
+
+ // Tokens generated by the primary config do not validate
+ // successfully against the override config, and vice versa.
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
+ peer_.ValidateSourceAddressToken(kOverride, token4, ip4_, now));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
+ peer_.ValidateSourceAddressToken(kOverride, token6, ip6_, now));
+ ASSERT_EQ(
+ SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
+ peer_.ValidateSourceAddressToken(kPrimary, override_token4, ip4_, now));
+ ASSERT_EQ(
+ SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
+ peer_.ValidateSourceAddressToken(kPrimary, override_token6, ip6_, now));
+}
+
+TEST_F(SourceAddressTokenTest, SourceAddressTokenExpiration) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens,
+ false);
+
+ QuicWallTime now = clock_.WallNow();
+
+ const string token = peer_.NewSourceAddressToken(kPrimary, ip4_, rand_, now);
+
+ // Validation fails after tokens expire.
+ now = original_time_.Add(QuicTime::Delta::FromSeconds(86400 * 7));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE,
+ peer_.ValidateSourceAddressToken(kPrimary, token, ip4_, now));
+
+ now = original_time_.Subtract(QuicTime::Delta::FromSeconds(3600 * 2));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE,
+ peer_.ValidateSourceAddressToken(kPrimary, token, ip4_, now));
+}
+
+TEST_F(SourceAddressTokenTest, SourceAddressTokenWithNetworkParams) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens,
+ false);
+
+ QuicWallTime now = clock_.WallNow();
+
+ // Make sure that if the source address token contains CachedNetworkParameters
+ // that this gets written to ValidateSourceAddressToken output argument.
+ CachedNetworkParameters cached_network_params_input;
+ cached_network_params_input.set_bandwidth_estimate_bytes_per_second(1234);
+ const string token4_with_cached_network_params = peer_.NewSourceAddressToken(
+ kPrimary, ip4_, rand_, now, &cached_network_params_input);
- EXPECT_TRUE(peer.ConfigHasDefaultSourceAddressTokenBoxer(kPrimary));
- EXPECT_FALSE(peer.ConfigHasDefaultSourceAddressTokenBoxer(kOverride));
+ CachedNetworkParameters cached_network_params_output;
+#if 0
+ // TODO(rtenneti): For server, enable the following check after serialization
+ // of optional CachedNetworkParameters is implemented.
+ EXPECT_NE(cached_network_params_output.DebugString(),
+ cached_network_params_input.DebugString());
+#endif
+ peer_.ValidateSourceAddressToken(kPrimary, token4_with_cached_network_params,
+ ip4_, now, &cached_network_params_output);
+#if 0
+ // TODO(rtenneti): For server, enable the following check after serialization
+ // of optional CachedNetworkParameters is implemented.
+ EXPECT_EQ(cached_network_params_output.DebugString(),
+ cached_network_params_input.DebugString());
+#endif
+}
+
+// Test basic behavior of source address tokens including being specific
+// to a single IP address and server config.
+//
+// TODO(rtenneti): For server, enable the following test after serialization of
+// SourceAddressTokens is implemented.
+TEST_F(SourceAddressTokenTest, DISABLED_NewSourceAddressToken) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens,
+ true);
- IPEndPoint ip4 = IPEndPoint(Loopback4(), 1);
- IPEndPoint ip4d = IPEndPoint(ConvertIPv4NumberToIPv6Number(ip4.address()), 1);
- IPEndPoint ip6 = IPEndPoint(Loopback6(), 2);
+ QuicWallTime now = clock_.WallNow();
// Primary config generates configs that validate successfully.
- const string token4 = peer.NewSourceAddressToken(kPrimary, ip4, rand, now);
- const string token4d = peer.NewSourceAddressToken(kPrimary, ip4d, rand, now);
- const string token6 = peer.NewSourceAddressToken(kPrimary, ip6, rand, now);
- EXPECT_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
- kPrimary, token4, ip4, now));
- DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
- kPrimary, token4, ip4d, now));
- DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
- peer.ValidateSourceAddressToken(kPrimary, token4, ip6, now));
- DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
- kPrimary, token4d, ip4, now));
- DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
- kPrimary, token4d, ip4d, now));
- DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
- peer.ValidateSourceAddressToken(kPrimary, token4d, ip6, now));
- DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
- kPrimary, token6, ip6, now));
+ const string token4 = peer_.NewSourceAddressToken(kPrimary, ip4_, rand_, now);
+ const string token4d =
+ peer_.NewSourceAddressToken(kPrimary, ip4_dual_, rand_, now);
+ const string token6 = peer_.NewSourceAddressToken(kPrimary, ip6_, rand_, now);
+ EXPECT_EQ(HANDSHAKE_OK,
+ peer_.ValidateSourceAddressTokens(kPrimary, token4, ip4_, now));
+ ASSERT_EQ(HANDSHAKE_OK, peer_.ValidateSourceAddressTokens(kPrimary, token4,
+ ip4_dual_, now));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
+ peer_.ValidateSourceAddressTokens(kPrimary, token4, ip6_, now));
+ ASSERT_EQ(HANDSHAKE_OK,
+ peer_.ValidateSourceAddressTokens(kPrimary, token4d, ip4_, now));
+ ASSERT_EQ(HANDSHAKE_OK, peer_.ValidateSourceAddressTokens(kPrimary, token4d,
+ ip4_dual_, now));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
+ peer_.ValidateSourceAddressTokens(kPrimary, token4d, ip6_, now));
+ ASSERT_EQ(HANDSHAKE_OK,
+ peer_.ValidateSourceAddressTokens(kPrimary, token6, ip6_, now));
// Override config generates configs that validate successfully.
- const string override_token4 = peer.NewSourceAddressToken(
- kOverride, ip4, rand, now);
- const string override_token6 = peer.NewSourceAddressToken(
- kOverride, ip6, rand, now);
- DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
- kOverride, override_token4, ip4, now));
- DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
- peer.ValidateSourceAddressToken(kOverride, override_token4, ip6,
- now));
- DCHECK_EQ(HANDSHAKE_OK, peer.ValidateSourceAddressToken(
- kOverride, override_token6, ip6, now));
+ const string override_token4 =
+ peer_.NewSourceAddressToken(kOverride, ip4_, rand_, now);
+ const string override_token6 =
+ peer_.NewSourceAddressToken(kOverride, ip6_, rand_, now);
+ ASSERT_EQ(HANDSHAKE_OK, peer_.ValidateSourceAddressTokens(
+ kOverride, override_token4, ip4_, now));
+ ASSERT_EQ(
+ SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
+ peer_.ValidateSourceAddressTokens(kOverride, override_token4, ip6_, now));
+ ASSERT_EQ(HANDSHAKE_OK, peer_.ValidateSourceAddressTokens(
+ kOverride, override_token6, ip6_, now));
// Tokens generated by the primary config do not validate
// successfully against the override config, and vice versa.
- DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
- peer.ValidateSourceAddressToken(kOverride, token4, ip4, now));
- DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
- peer.ValidateSourceAddressToken(kOverride, token6, ip6, now));
- DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
- peer.ValidateSourceAddressToken(kPrimary, override_token4, ip4,
- now));
- DCHECK_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
- peer.ValidateSourceAddressToken(kPrimary, override_token6, ip6,
- now));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
+ peer_.ValidateSourceAddressTokens(kOverride, token4, ip4_, now));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
+ peer_.ValidateSourceAddressTokens(kOverride, token6, ip6_, now));
+ ASSERT_EQ(
+ SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
+ peer_.ValidateSourceAddressTokens(kPrimary, override_token4, ip4_, now));
+ ASSERT_EQ(
+ SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
+ peer_.ValidateSourceAddressTokens(kPrimary, override_token6, ip6_, now));
+}
+
+// TODO(rtenneti): For server, enable the following test after serialization of
+// SourceAddressTokens is implemented.
+TEST_F(SourceAddressTokenTest, DISABLED_NewSourceAddressTokenExpiration) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens,
+ true);
+
+ QuicWallTime now = clock_.WallNow();
+
+ const string token = peer_.NewSourceAddressToken(kPrimary, ip4_, rand_, now);
// Validation fails after tokens expire.
- now = original_time.Add(QuicTime::Delta::FromSeconds(86400 * 7));
- DCHECK_EQ(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE,
- peer.ValidateSourceAddressToken(kPrimary, token4, ip4, now));
+ now = original_time_.Add(QuicTime::Delta::FromSeconds(86400 * 7));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE,
+ peer_.ValidateSourceAddressTokens(kPrimary, token, ip4_, now));
+
+ now = original_time_.Subtract(QuicTime::Delta::FromSeconds(3600 * 2));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE,
+ peer_.ValidateSourceAddressTokens(kPrimary, token, ip4_, now));
+}
- now = original_time.Subtract(QuicTime::Delta::FromSeconds(3600 * 2));
- DCHECK_EQ(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE,
- peer.ValidateSourceAddressToken(kPrimary, token4, ip4, now));
+TEST_F(SourceAddressTokenTest, NewSourceAddressTokenWithNetworkParams) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens,
+ true);
+
+ QuicWallTime now = clock_.WallNow();
// Make sure that if the source address token contains CachedNetworkParameters
// that this gets written to ValidateSourceAddressToken output argument.
CachedNetworkParameters cached_network_params_input;
cached_network_params_input.set_bandwidth_estimate_bytes_per_second(1234);
- const string token4_with_cached_network_params = peer.NewSourceAddressToken(
- kPrimary, ip4, rand, now, &cached_network_params_input);
+ const string token4_with_cached_network_params = peer_.NewSourceAddressToken(
+ kPrimary, ip4_, rand_, now, &cached_network_params_input);
CachedNetworkParameters cached_network_params_output;
- EXPECT_NE(cached_network_params_output, cached_network_params_input);
- peer.ValidateSourceAddressToken(kPrimary, token4_with_cached_network_params,
- ip4, now, &cached_network_params_output);
+#if 0
// TODO(rtenneti): For server, enable the following check after serialization
// of optional CachedNetworkParameters is implemented.
- // EXPECT_EQ(cached_network_params_output, cached_network_params_input);
+ EXPECT_NE(cached_network_params_output.DebugString(),
+ cached_network_params_input.DebugString());
+#endif
+ peer_.ValidateSourceAddressTokens(kPrimary, token4_with_cached_network_params,
+ ip4_, now, &cached_network_params_output);
+#if 0
+ // TODO(rtenneti): For server, enable the following check after serialization
+ // of optional CachedNetworkParameters is implemented.
+ EXPECT_EQ(cached_network_params_output.DebugString(),
+ cached_network_params_input.DebugString());
+#endif
+}
+
+// Test the ability for a source address token to be valid for multiple
+// addresses.
+//
+// TODO(rtenneti): For server, enable the following test after serialization of
+// SourceAddressTokens is implemented.
+TEST_F(SourceAddressTokenTest, DISABLED_SourceAddressTokenMultipleAddresses) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_use_multiple_address_in_source_tokens,
+ true);
+
+ QuicWallTime now = clock_.WallNow();
+
+ // Now create a token which is usable for both addresses.
+ SourceAddressToken previous_token;
+ IPAddressNumber ip_address = ip6_.address();
+ if (ip6_.GetSockAddrFamily() == AF_INET) {
+ ip_address = ConvertIPv4NumberToIPv6Number(ip_address);
+ }
+ previous_token.set_ip(IPAddressToPackedString(ip_address));
+ previous_token.set_timestamp(now.ToUNIXSeconds());
+ SourceAddressTokens previous_tokens;
+ (*previous_tokens.add_tokens()) = previous_token;
+ const string token4or6 =
+ peer_.NewSourceAddressToken(kPrimary, ip4_, rand_, now, previous_tokens);
+
+ EXPECT_EQ(HANDSHAKE_OK,
+ peer_.ValidateSourceAddressTokens(kPrimary, token4or6, ip4_, now));
+ ASSERT_EQ(HANDSHAKE_OK,
+ peer_.ValidateSourceAddressTokens(kPrimary, token4or6, ip6_, now));
}
TEST(QuicCryptoServerConfigTest, ValidateServerNonce) {
diff --git a/net/quic/crypto/source_address_token.cc b/net/quic/crypto/source_address_token.cc
index 5c1877a..dcb7267 100644
--- a/net/quic/crypto/source_address_token.cc
+++ b/net/quic/crypto/source_address_token.cc
@@ -58,4 +58,28 @@ bool SourceAddressToken::ParseFromArray(const char* plaintext,
return true;
}
+SourceAddressTokens::SourceAddressTokens() {
+}
+
+SourceAddressTokens::~SourceAddressTokens() {
+ STLDeleteElements(&tokens_);
+}
+
+string SourceAddressTokens::SerializeAsString() const {
+ string out;
+
+ for (size_t i = 0; i < tokens_size(); i++) {
+ const SourceAddressToken& source_address_token = tokens(i);
+ out.append(source_address_token.SerializeAsString());
+ }
+ return out;
+}
+
+bool SourceAddressTokens::ParseFromArray(const char* plaintext,
+ size_t plaintext_length) {
+ // TODO(rtenneti): Implement parsing of SourceAddressTokens when they are
+ // used.
+ return true;
+}
+
} // namespace net
diff --git a/net/quic/crypto/source_address_token.h b/net/quic/crypto/source_address_token.h
index 32f11c5..71ba54e 100644
--- a/net/quic/crypto/source_address_token.h
+++ b/net/quic/crypto/source_address_token.h
@@ -6,9 +6,11 @@
#define NET_QUIC_CRYPTO_SOURCE_ADDRESS_TOKEN_H_
#include <string>
+#include <vector>
#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "net/base/net_export.h"
#include "net/quic/crypto/cached_network_parameters.h"
@@ -46,6 +48,9 @@ class NET_EXPORT_PRIVATE SourceAddressToken {
const CachedNetworkParameters& cached_network_parameters() const {
return cached_network_parameters_;
}
+ CachedNetworkParameters* mutable_cached_network_parameters() {
+ return &cached_network_parameters_;
+ }
void set_cached_network_parameters(
const CachedNetworkParameters& cached_network_parameters) {
cached_network_parameters_ = cached_network_parameters;
@@ -69,8 +74,32 @@ class NET_EXPORT_PRIVATE SourceAddressToken {
// TODO(rtenneti): Delete |has_cached_network_parameters_| after we convert
// SourceAddressToken to protobuf.
bool has_cached_network_parameters_;
+};
+
+class NET_EXPORT_PRIVATE SourceAddressTokens {
+ public:
+ SourceAddressTokens();
+ ~SourceAddressTokens();
+
+ std::string SerializeAsString() const;
+
+ bool ParseFromArray(const char* plaintext, size_t plaintext_length);
+
+ size_t tokens_size() const { return tokens_.size(); }
+
+ const SourceAddressToken& tokens(size_t i) const {
+ DCHECK_GT(tokens_.size(), i);
+ return *tokens_[i];
+ }
+
+ SourceAddressToken* add_tokens() {
+ tokens_.push_back(new SourceAddressToken);
+ return tokens_.back();
+ }
+
+ void clear_tokens() { STLDeleteElements(&tokens_); }
- DISALLOW_COPY_AND_ASSIGN(SourceAddressToken);
+ std::vector<SourceAddressToken*> tokens_;
};
} // namespace net
diff --git a/net/quic/quic_ack_notifier.cc b/net/quic/quic_ack_notifier.cc
index 3bd65e5..2a9b585 100644
--- a/net/quic/quic_ack_notifier.cc
+++ b/net/quic/quic_ack_notifier.cc
@@ -68,8 +68,7 @@ void QuicAckNotifier::UpdateSequenceNumber(
DCHECK(!ContainsKey(sequence_numbers_, new_sequence_number));
PacketInfo packet_info;
- hash_map<QuicPacketSequenceNumber, PacketInfo>::iterator it =
- sequence_numbers_.find(old_sequence_number);
+ auto it = sequence_numbers_.find(old_sequence_number);
if (it != sequence_numbers_.end()) {
packet_info = it->second;
sequence_numbers_.erase(it);
diff --git a/net/quic/quic_ack_notifier_manager.cc b/net/quic/quic_ack_notifier_manager.cc
index 1d9ac9a..ad6193f 100644
--- a/net/quic/quic_ack_notifier_manager.cc
+++ b/net/quic/quic_ack_notifier_manager.cc
@@ -22,11 +22,10 @@ AckNotifierManager::~AckNotifierManager() {
STLDeleteElements(&ack_notifiers_);
}
-void AckNotifierManager::OnPacketAcked(
- QuicPacketSequenceNumber sequence_number,
- QuicTime::Delta delta_largest_observed) {
+void AckNotifierManager::OnPacketAcked(QuicPacketSequenceNumber sequence_number,
+ QuicTime::Delta delta_largest_observed) {
// Inform all the registered AckNotifiers of the new ACK.
- AckNotifierMap::iterator map_it = ack_notifier_map_.find(sequence_number);
+ auto map_it = ack_notifier_map_.find(sequence_number);
if (map_it == ack_notifier_map_.end()) {
// No AckNotifier is interested in this sequence number.
return;
@@ -34,9 +33,8 @@ void AckNotifierManager::OnPacketAcked(
// One or more AckNotifiers are registered as interested in this sequence
// number. Iterate through them and call OnAck on each.
- for (AckNotifierSet::iterator set_it = map_it->second.begin();
- set_it != map_it->second.end(); ++set_it) {
- QuicAckNotifier* ack_notifier = *set_it;
+ AckNotifierSet& ack_notifier_set = map_it->second;
+ for (QuicAckNotifier* ack_notifier : ack_notifier_set) {
ack_notifier->OnAck(sequence_number, delta_largest_observed);
// If this has resulted in an empty AckNotifer, erase it.
@@ -54,53 +52,51 @@ void AckNotifierManager::OnPacketAcked(
void AckNotifierManager::UpdateSequenceNumber(
QuicPacketSequenceNumber old_sequence_number,
QuicPacketSequenceNumber new_sequence_number) {
- AckNotifierMap::iterator map_it = ack_notifier_map_.find(old_sequence_number);
- if (map_it != ack_notifier_map_.end()) {
- // We will add an entry to the map for the new sequence number, and move
- // the
- // list of AckNotifiers over.
- AckNotifierSet new_set;
- for (AckNotifierSet::iterator notifier_it = map_it->second.begin();
- notifier_it != map_it->second.end(); ++notifier_it) {
- (*notifier_it)
- ->UpdateSequenceNumber(old_sequence_number, new_sequence_number);
- new_set.insert(*notifier_it);
- }
- ack_notifier_map_[new_sequence_number] = new_set;
- ack_notifier_map_.erase(map_it);
+ auto map_it = ack_notifier_map_.find(old_sequence_number);
+ if (map_it == ack_notifier_map_.end()) {
+ // No AckNotifiers are interested in the old sequence number.
+ return;
}
+
+ // Update the existing QuicAckNotifiers to the new sequence number.
+ AckNotifierSet& ack_notifier_set = map_it->second;
+ for (QuicAckNotifier* ack_notifier : ack_notifier_set) {
+ ack_notifier->UpdateSequenceNumber(old_sequence_number,
+ new_sequence_number);
+ }
+
+ // The old sequence number is no longer of interest, copy the updated
+ // AckNotifiers to the new sequence number before deleting the old.
+ ack_notifier_map_[new_sequence_number] = ack_notifier_set;
+ ack_notifier_map_.erase(map_it);
}
void AckNotifierManager::OnSerializedPacket(
const SerializedPacket& serialized_packet) {
- // Run through all the frames and if any of them are stream frames and have
- // an AckNotifier registered, then inform the AckNotifier that it should be
- // interested in this packet's sequence number.
-
- RetransmittableFrames* frames = serialized_packet.retransmittable_frames;
-
// AckNotifiers can only be attached to retransmittable frames.
- if (!frames) {
+ RetransmittableFrames* frames = serialized_packet.retransmittable_frames;
+ if (frames == nullptr) {
return;
}
- for (QuicFrames::const_iterator it = frames->frames().begin();
- it != frames->frames().end(); ++it) {
- if (it->type == STREAM_FRAME && it->stream_frame->notifier != nullptr) {
- QuicAckNotifier* notifier = it->stream_frame->notifier;
+ // For each frame in |serialized_packet|, inform any attached AckNotifiers of
+ // the packet's sequence number.
+ for (const QuicFrame& quic_frame : frames->frames()) {
+ if (quic_frame.type != STREAM_FRAME ||
+ quic_frame.stream_frame->notifier == nullptr) {
+ continue;
+ }
- // The AckNotifier needs to know it is tracking this packet's sequence
- // number.
- notifier->AddSequenceNumber(serialized_packet.sequence_number,
- serialized_packet.packet->length());
+ QuicAckNotifier* notifier = quic_frame.stream_frame->notifier;
+ notifier->AddSequenceNumber(serialized_packet.sequence_number,
+ serialized_packet.packet->length());
- // Update the mapping in the other direction, from sequence
- // number to AckNotifier.
- ack_notifier_map_[serialized_packet.sequence_number].insert(notifier);
+ // Update the mapping in the other direction, from sequence number to
+ // AckNotifier.
+ ack_notifier_map_[serialized_packet.sequence_number].insert(notifier);
- // Take ownership of the AckNotifier.
- ack_notifiers_.insert(notifier);
- }
+ // Take ownership of the AckNotifier.
+ ack_notifiers_.insert(notifier);
}
}
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 74d1758..5fdc4b9 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -467,10 +467,8 @@ void QuicConnection::OnDecryptedPacket(EncryptionLevel level) {
last_packet_decrypted_ = true;
// If this packet was foward-secure encrypted and the forward-secure encrypter
// is not being used, start using it.
- if (FLAGS_enable_quic_delay_forward_security &&
- encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
- has_forward_secure_encrypter_ &&
- level == ENCRYPTION_FORWARD_SECURE) {
+ if (encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
+ has_forward_secure_encrypter_ && level == ENCRYPTION_FORWARD_SECURE) {
SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
}
}
@@ -942,9 +940,6 @@ void QuicConnection::ClearLastFrames() {
}
void QuicConnection::MaybeCloseIfTooManyOutstandingPackets() {
- if (!FLAGS_quic_too_many_outstanding_packets) {
- return;
- }
// This occurs if we don't discard old packets we've sent fast enough.
// It's possible largest observed is less than least unacked.
if (sent_packet_manager_.largest_observed() >
@@ -1584,8 +1579,7 @@ void QuicConnection::OnSerializedPacket(
// If a forward-secure encrypter is available but is not being used and this
// packet's sequence number is after the first packet which requires
// forward security, start using the forward-secure encrypter.
- if (FLAGS_enable_quic_delay_forward_security &&
- encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
+ if (encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
has_forward_secure_encrypter_ &&
serialized_packet.sequence_number >=
first_required_forward_secure_packet_) {
@@ -1696,8 +1690,7 @@ void QuicConnection::OnRetransmissionTimeout() {
void QuicConnection::SetEncrypter(EncryptionLevel level,
QuicEncrypter* encrypter) {
framer_.SetEncrypter(level, encrypter);
- if (FLAGS_enable_quic_delay_forward_security &&
- level == ENCRYPTION_FORWARD_SECURE) {
+ if (level == ENCRYPTION_FORWARD_SECURE) {
has_forward_secure_encrypter_ = true;
first_required_forward_secure_packet_ =
sequence_number_of_last_sent_packet_ +
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 6381c16..fe11766 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -1346,11 +1346,8 @@ TEST_P(QuicConnectionTest, TooManySentPackets) {
// Ack packet 1, which leaves more than the limit outstanding.
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- if (FLAGS_quic_too_many_outstanding_packets) {
- EXPECT_CALL(visitor_,
- OnConnectionClosed(QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS,
- false));
- }
+ EXPECT_CALL(visitor_, OnConnectionClosed(
+ QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS, false));
// We're receive buffer limited, so the connection won't try to write more.
EXPECT_CALL(visitor_, OnCanWrite()).Times(0);
@@ -1364,12 +1361,8 @@ TEST_P(QuicConnectionTest, TooManySentPackets) {
TEST_P(QuicConnectionTest, TooManyReceivedPackets) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- if (FLAGS_quic_too_many_outstanding_packets) {
- EXPECT_CALL(visitor_,
- OnConnectionClosed(QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS,
- false));
- }
+ EXPECT_CALL(visitor_, OnConnectionClosed(
+ QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS, false));
// Miss every other packet for 1000 packets.
for (QuicPacketSequenceNumber i = 1; i < 1000; ++i) {
@@ -2543,8 +2536,6 @@ TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
}
TEST_P(QuicConnectionTest, DelayForwardSecureEncryptionUntilClientIsReady) {
- ValueRestore<bool> old_flag(&FLAGS_enable_quic_delay_forward_security, true);
-
// A TaggingEncrypter puts kTagSize copies of the given byte (0x02 here) at
// the end of the packet. We can test this to check which encrypter was used.
use_tagging_decrypter();
@@ -2568,8 +2559,6 @@ TEST_P(QuicConnectionTest, DelayForwardSecureEncryptionUntilClientIsReady) {
}
TEST_P(QuicConnectionTest, DelayForwardSecureEncryptionUntilManyPacketSent) {
- ValueRestore<bool> old_flag(&FLAGS_enable_quic_delay_forward_security, true);
-
// Set a congestion window of 10 packets.
QuicPacketCount congestion_window = 10;
EXPECT_CALL(*send_algorithm_, GetCongestionWindow()).WillRepeatedly(
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index 50a6da4..63070cd 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -11,7 +11,6 @@
#include "net/quic/crypto/crypto_utils.h"
#include "net/quic/crypto/quic_crypto_server_config.h"
#include "net/quic/quic_config.h"
-#include "net/quic/quic_flags.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_session.h"
@@ -142,10 +141,6 @@ void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
session()->connection()->SetEncrypter(
ENCRYPTION_FORWARD_SECURE,
crypto_negotiated_params_.forward_secure_crypters.encrypter.release());
- if (!FLAGS_enable_quic_delay_forward_security) {
- session()->connection()->SetDefaultEncryptionLevel(
- ENCRYPTION_FORWARD_SECURE);
- }
session()->connection()->SetAlternativeDecrypter(
crypto_negotiated_params_.forward_secure_crypters.decrypter.release(),
ENCRYPTION_FORWARD_SECURE, false /* don't latch */);
@@ -164,6 +159,7 @@ void QuicCryptoServerStream::SendServerConfigUpdate(
CryptoHandshakeMessage server_config_update_message;
if (!crypto_config_.BuildServerConfigUpdateMessage(
+ previous_source_address_tokens_,
session()->connection()->self_address(),
session()->connection()->peer_address(),
session()->connection()->clock(),
@@ -232,6 +228,7 @@ QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
previous_cached_network_params_.reset(
new CachedNetworkParameters(result.cached_network_params));
}
+ previous_source_address_tokens_ = result.info.source_address_tokens;
return crypto_config_.ProcessClientHello(
result, session()->connection()->connection_id(),
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h
index f88affe..ece2da2 100644
--- a/net/quic/quic_crypto_server_stream.h
+++ b/net/quic/quic_crypto_server_stream.h
@@ -19,6 +19,7 @@ class CryptoHandshakeMessage;
class QuicCryptoServerConfig;
class QuicCryptoServerStream;
class QuicSession;
+class SourceAddressTokens;
namespace test {
class CryptoTestUtils;
@@ -141,6 +142,9 @@ class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream {
// estimate to send.
scoped_ptr<CachedNetworkParameters> previous_cached_network_params_;
+ // Contains any source address tokens which were present in the CHLO.
+ SourceAddressTokens previous_source_address_tokens_;
+
DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerStream);
};
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index d06234a..b395eac 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -39,14 +39,6 @@ bool FLAGS_quic_allow_bbr = false;
// If true, truncate QUIC connection IDs if the client requests it.
bool FLAGS_allow_truncated_connection_ids_for_quic = false;
-// If true, close the connection when there are too many outstanding QUIC
-// packets in the sent or received packet managers.
-bool FLAGS_quic_too_many_outstanding_packets = false;
-
-// If true, QUIC connections will delay moving to forward security until the
-// client starts sending foward secure encrypted packets.
-bool FLAGS_enable_quic_delay_forward_security = true;
-
// Do not flip this flag. jokulik plans more testing and additional monitoring
// before the flag can go the auto-flip process.
//
@@ -68,3 +60,11 @@ bool FLAGS_quic_allow_silent_close = true;
// If true, use std::cbrt instead of custom cube root.
bool FLAGS_quic_use_std_cbrt = true;
+
+// If true, the QUIC packet generator will not attempt to queue multiple ACK
+// frames.
+bool FLAGS_quic_disallow_multiple_pending_ack_frames = true;
+
+// If true, then the source address tokens generated for QUIC connects will
+// store multiple addresses.
+bool FLAGS_quic_use_multiple_address_in_source_tokens = false;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index 6580083..6927ce0 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -17,12 +17,13 @@ NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_bbr_congestion_control;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_bbr;
NET_EXPORT_PRIVATE extern bool FLAGS_allow_truncated_connection_ids_for_quic;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_too_many_outstanding_packets;
-NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_delay_forward_security;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_record_send_time_before_write;
NET_EXPORT_PRIVATE
extern bool FLAGS_quic_enable_bandwidth_resumption_experiment;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_pacing;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_silent_close;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_std_cbrt;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_disallow_multiple_pending_ack_frames;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_multiple_address_in_source_tokens;
#endif // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_headers_stream.cc b/net/quic/quic_headers_stream.cc
index 9d26e4a..e8c8b58 100644
--- a/net/quic/quic_headers_stream.cc
+++ b/net/quic/quic_headers_stream.cc
@@ -4,6 +4,7 @@
#include "net/quic/quic_headers_stream.h"
+#include "base/strings/stringprintf.h"
#include "net/quic/quic_session.h"
using base::StringPiece;
@@ -81,7 +82,9 @@ class QuicHeadersStream::SpdyFramerVisitor
}
void OnError(SpdyFramer* framer) override {
- CloseConnection("SPDY framing error.");
+ CloseConnection(base::StringPrintf(
+ "SPDY framing error: %s",
+ SpdyFramer::ErrorCodeToString(framer->error_code())));
}
void OnDataFrameHeader(SpdyStreamId stream_id,
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc
index 8649a3e..446b73f 100644
--- a/net/quic/quic_headers_stream_test.cc
+++ b/net/quic/quic_headers_stream_test.cc
@@ -245,6 +245,15 @@ TEST_P(QuicHeadersStreamTest, ProcessRawData) {
}
}
+TEST_P(QuicHeadersStreamTest, ProcessBadData) {
+ const char kBadData[] = "blah blah blah";
+ EXPECT_CALL(*connection_,
+ SendConnectionCloseWithDetails(
+ QUIC_INVALID_HEADERS_STREAM_DATA,
+ "SPDY framing error: SPDY_INVALID_DATA_FRAME_FLAGS"));
+ headers_stream_->ProcessRawData(kBadData, strlen(kBadData));
+}
+
TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) {
SpdyDataIR data(2, "");
scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index 21ab10c..2262883 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "net/quic/quic_fec_group.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_utils.h"
using base::StringPiece;
@@ -93,6 +94,23 @@ void QuicPacketGenerator::OnCongestionWindowChange(
void QuicPacketGenerator::SetShouldSendAck(bool also_send_feedback,
bool also_send_stop_waiting) {
+ if (FLAGS_quic_disallow_multiple_pending_ack_frames) {
+ if (pending_ack_frame_ != nullptr) {
+ // Ack already queued, nothing to do.
+ return;
+ }
+
+ if (also_send_feedback && pending_feedback_frame_ != nullptr) {
+ LOG(DFATAL) << "Should only ever be one pending feedback frame.";
+ return;
+ }
+
+ if (also_send_stop_waiting && pending_stop_waiting_frame_ != nullptr) {
+ LOG(DFATAL) << "Should only ever be one pending stop waiting frame.";
+ return;
+ }
+ }
+
should_send_ack_ = true;
should_send_feedback_ = also_send_feedback;
should_send_stop_waiting_ = also_send_stop_waiting;
@@ -347,6 +365,13 @@ void QuicPacketGenerator::SerializeAndSendPacket() {
DCHECK(serialized_packet.packet);
delegate_->OnSerializedPacket(serialized_packet);
MaybeSendFecPacketAndCloseGroup(false);
+
+ // The packet has now been serialized, safe to delete pending frames.
+ if (FLAGS_quic_disallow_multiple_pending_ack_frames) {
+ pending_ack_frame_.reset();
+ pending_feedback_frame_.reset();
+ pending_stop_waiting_frame_.reset();
+ }
}
void QuicPacketGenerator::StopSendingVersion() {
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index ac99144..7eea015 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -10,6 +10,7 @@
#include "net/quic/crypto/null_encrypter.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_packet_creator_peer.h"
#include "net/quic/test_tools/quic_packet_generator_peer.h"
@@ -315,6 +316,30 @@ TEST_F(QuicPacketGeneratorTest,
CheckPacketContains(contents, packet_);
}
+TEST_F(QuicPacketGeneratorTest, ShouldSendAck_MultipleCalls) {
+ ValueRestore<bool> old_flag(&FLAGS_quic_disallow_multiple_pending_ack_frames,
+ true);
+
+ // Make sure that calling SetShouldSendAck multiple times does not result in a
+ // crash. Previously this would result in multiple QuicFrames queued in the
+ // packet generator, with all but the last with internal pointers to freed
+ // memory.
+ delegate_.SetCanWriteAnything();
+
+ // Only one AckFrame should be created.
+ EXPECT_CALL(delegate_, CreateAckFrame())
+ .Times(1)
+ .WillOnce(Return(CreateAckFrame()));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .Times(1)
+ .WillOnce(SaveArg<0>(&packet_));
+
+ generator_.StartBatchOperations();
+ generator_.SetShouldSendAck(false, false);
+ generator_.SetShouldSendAck(false, false);
+ generator_.FinishBatchOperations();
+}
+
TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritable) {
delegate_.SetCanNotWrite();
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index f054673..5feb467 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -165,6 +165,13 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
bool QuicSentPacketManager::ResumeConnectionState(
const CachedNetworkParameters& cached_network_params) {
+ if (cached_network_params.has_min_rtt_ms()) {
+ uint32 initial_rtt_us =
+ kNumMicrosPerMilli * cached_network_params.min_rtt_ms();
+ rtt_stats_.set_initial_rtt_us(
+ max(kMinInitialRoundTripTimeUs,
+ min(kMaxInitialRoundTripTimeUs, initial_rtt_us)));
+ }
return send_algorithm_->ResumeConnectionState(cached_network_params);
}
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index 1a907ff..044bead 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -1465,6 +1465,19 @@ TEST_F(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) {
EXPECT_EQ(initial_rtt_us, manager_.GetRttStats()->initial_rtt_us());
}
+TEST_F(QuicSentPacketManagerTest, ResumeConnectionState) {
+ // The sent packet manager should use the RTT from CachedNetworkParameters if
+ // it is provided.
+ const int kRttMs = 1234;
+ CachedNetworkParameters cached_network_params;
+ cached_network_params.set_min_rtt_ms(kRttMs);
+
+ EXPECT_CALL(*send_algorithm_, ResumeConnectionState(_));
+ manager_.ResumeConnectionState(cached_network_params);
+ EXPECT_EQ(kRttMs * kNumMicrosPerMilli,
+ static_cast<uint64>(manager_.GetRttStats()->initial_rtt_us()));
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index e404929..15dfe79 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -327,9 +327,9 @@ TEST_P(QuicSessionTest, DecompressionError) {
0x00, 0x00,
'a', 'b', 'c', 'd' // invalid compressed data
};
- EXPECT_CALL(*connection_,
- SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
- "SPDY framing error."));
+ EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(
+ QUIC_INVALID_HEADERS_STREAM_DATA,
+ "SPDY framing error: DECOMPRESS_FAILURE"));
stream->ProcessRawData(reinterpret_cast<const char*>(data),
arraysize(data));
}