summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrtenneti <rtenneti@chromium.org>2014-11-03 20:17:00 -0800
committerCommit bot <commit-bot@chromium.org>2014-11-04 04:17:20 +0000
commit33da8ab021168895957e45ad4d1af9e991a2c665 (patch)
treec212fcc3dab23e9df9d0e0e14156ac6a31da366d
parent3e7c2a6ee80e05fc6b8090bee850c40b8a2a3810 (diff)
downloadchromium_src-33da8ab021168895957e45ad4d1af9e991a2c665.zip
chromium_src-33da8ab021168895957e45ad4d1af9e991a2c665.tar.gz
chromium_src-33da8ab021168895957e45ad4d1af9e991a2c665.tar.bz2
Land Recent QUIC Changes.
Tiny refactor of QuicSentPacketManager::NetworkChangeVisitor's OnCongestionWindowChange() method to take no arguments, and require the caller to fetch the updated congestion window. Slightly simplifies the code. In preparation for the larger GetCongestionWindowInPackets() cleanup. Merge internal change: 78883300 https://codereview.chromium.org/694383002/ Change the number of emulated connections in QUIC's congestion control as the number of open streams changes when the NCON connection option is supplied. Merge internal change: 78876869 https://codereview.chromium.org/682293004/ Merge changes to keep chromium source tree same as internal source tree. Merge internal change: 78853598 https://codereview.chromium.org/693253002/ QUIC: Only send a new SCUP if enough packets have been sent since the last SCUP. Merge internal change: 78841268 https://codereview.chromium.org/699433002/ Fixes reduction for n-connection emulation in TCP Reno. Merge internal change: 78812645 https://codereview.chromium.org/680253005/ Delay a QUIC server's use of the FORWARD_SECURE encrypter until the client has had a chance to start using it. Protected by FLAGS_enable_quic_delay_forward_security. When the forward secure encrypter is available, don't use it until one of two things happens: 1) the peers starts sending forward secure encrypted packets 2) 2 round trips worth of packets have been sent, in case something (MitM?) is preventing the peer from using forward secure encryption. Merge internal change: 78801773 Set FLAGS_enable_quic_delay_forward_security to true in chromium. https://codereview.chromium.org/698703003/ Change QUIC's Reno congestion controller to use a higher beta. Fixed tests to be independent of beta. Merge internal change: 78728349 https://codereview.chromium.org/698713002/ R=rch@chromium.org Review URL: https://codereview.chromium.org/694393002 Cr-Commit-Position: refs/heads/master@{#302571}
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.cc14
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.h3
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender_test.cc121
-rw-r--r--net/quic/crypto/common_cert_set.cc12
-rw-r--r--net/quic/crypto/crypto_protocol.h1
-rw-r--r--net/quic/quic_connection.cc39
-rw-r--r--net/quic/quic_connection.h21
-rw-r--r--net/quic/quic_connection_test.cc61
-rw-r--r--net/quic/quic_crypto_server_stream.cc10
-rw-r--r--net/quic/quic_flags.cc4
-rw-r--r--net/quic/quic_flags.h1
-rw-r--r--net/quic/quic_packet_generator.cc1
-rw-r--r--net/quic/quic_protocol.h3
-rw-r--r--net/quic/quic_sent_packet_manager.cc21
-rw-r--r--net/quic/quic_sent_packet_manager.h5
-rw-r--r--net/quic/quic_sent_packet_manager_test.cc98
-rw-r--r--net/quic/quic_server_session.cc17
-rw-r--r--net/quic/quic_server_session.h13
-rw-r--r--net/quic/quic_session.cc8
-rw-r--r--net/quic/test_tools/quic_connection_peer.cc6
-rw-r--r--net/quic/test_tools/quic_connection_peer.h3
-rw-r--r--net/quic/test_tools/quic_test_utils.h2
-rw-r--r--net/tools/quic/end_to_end_test.cc1
-rw-r--r--net/tools/quic/quic_client_session.h10
-rw-r--r--net/tools/quic/quic_server_session.cc17
-rw-r--r--net/tools/quic/quic_server_session.h5
-rw-r--r--net/tools/quic/quic_server_session_test.cc9
27 files changed, 333 insertions, 173 deletions
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 9ea96ae..44e4b3e 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -24,6 +24,8 @@ const QuicPacketCount kMinimumCongestionWindow = 2;
const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS;
const int64 kInitialCongestionWindow = 10;
const int kMaxBurstLength = 3;
+const float kRenoBeta = 0.7f; // Reno backoff factor.
+const uint32 kDefaultNumConnections = 2; // N-connection emulation.
} // namespace
TcpCubicSender::TcpCubicSender(
@@ -37,7 +39,7 @@ TcpCubicSender::TcpCubicSender(
rtt_stats_(rtt_stats),
stats_(stats),
reno_(reno),
- num_connections_(2),
+ num_connections_(kDefaultNumConnections),
congestion_window_count_(0),
largest_sent_sequence_number_(0),
largest_acked_sequence_number_(0),
@@ -75,6 +77,14 @@ void TcpCubicSender::SetNumEmulatedConnections(int num_connections) {
cubic_.SetNumConnections(num_connections_);
}
+float TcpCubicSender::RenoBeta() const {
+ // kNConnectionBeta is the backoff factor after loss for our N-connection
+ // emulation, which emulates the effective backoff of an ensemble of N
+ // TCP-Reno connections on a single loss event. The effective multiplier is
+ // computed as:
+ return (num_connections_ - 1 + kRenoBeta) / num_connections_;
+}
+
void TcpCubicSender::OnCongestionEvent(
bool rtt_updated,
QuicByteCount bytes_in_flight,
@@ -133,7 +143,7 @@ void TcpCubicSender::OnPacketLost(QuicPacketSequenceNumber sequence_number,
prr_.OnPacketLost(bytes_in_flight);
if (reno_) {
- congestion_window_ = congestion_window_ >> 1;
+ congestion_window_ = congestion_window_ * RenoBeta();
} else {
congestion_window_ =
cubic_.CongestionWindowAfterPacketLoss(congestion_window_);
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index ae05ee2..7491565 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -70,6 +70,9 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
private:
friend class test::TcpCubicSenderPeer;
+ // Compute the TCP Reno beta based on the current number of connections.
+ float RenoBeta() const;
+
// TODO(ianswett): Remove these and migrate to OnCongestionEvent.
void OnPacketAcked(QuicPacketSequenceNumber acked_sequence_number,
QuicByteCount acked_bytes,
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index 9193941..4fe8dbf 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -23,6 +23,7 @@ namespace test {
const int64 kInitialCongestionWindow = 10;
const uint32 kDefaultWindowTCP = kInitialCongestionWindow * kDefaultTCPMSS;
+const float kRenoBeta = 0.7f; // Reno backoff factor.
// TODO(ianswett): Remove 10000 once b/10075719 is fixed.
const QuicPacketCount kDefaultMaxCongestionWindowTCP = 10000;
@@ -48,6 +49,10 @@ class TcpCubicSenderPeer : public TcpCubicSender {
return hybrid_slow_start_;
}
+ float GetRenoBeta() const {
+ return RenoBeta();
+ }
+
RttStats rtt_stats_;
QuicConnectionStats stats_;
};
@@ -264,32 +269,26 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) {
// Lose a packet to exit slow start.
LoseNPackets(1);
+ size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS;
- // We should now have fallen out of slow start.
- // We expect window to be cut in half by Reno.
- expected_send_window /= 2;
+ // We should now have fallen out of slow start with a reduced window.
+ expected_send_window *= kRenoBeta;
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- // Testing Reno phase.
- // We need to ack half of the pending packet before we can send again.
+ // Recovery phase. We need to ack every packet in the recovery window before
+ // we exit recovery.
size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
- AckNPackets(number_of_packets_in_window);
+ DVLOG(1) << "number_packets: " << number_of_packets_in_window;
+ AckNPackets(packets_in_recovery_window);
+ SendAvailableSendWindow();
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- // We need to ack every packet in the window before we exit recovery.
- for (size_t i = 0; i < number_of_packets_in_window; ++i) {
- AckNPackets(1);
- SendAvailableSendWindow();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- }
-
- // We need to ack another window before we increase CWND by 1.
- for (size_t i = 0; i < number_of_packets_in_window - 2; ++i) {
- AckNPackets(1);
- SendAvailableSendWindow();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- }
+ // We need to ack an entire window before we increase CWND by 1.
+ AckNPackets(number_of_packets_in_window - 2);
+ SendAvailableSendWindow();
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ // Next ack should increase cwnd by 1.
AckNPackets(1);
expected_send_window += kDefaultTCPMSS;
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
@@ -330,27 +329,27 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLossPRR) {
LoseNPackets(1);
- // We should now have fallen out of slow start.
- // We expect window to be cut in half by Reno.
- expected_send_window /= 2;
+ // We should now have fallen out of slow start with a reduced window.
+ size_t send_window_before_loss = expected_send_window;
+ expected_send_window *= kRenoBeta;
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
// Testing TCP proportional rate reduction.
- // We should send one packet for every two received acks over the remaining
- // 18 outstanding packets.
- size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
- // The number of packets before we exit recovery is the original CWND minus
- // the packet that has been lost and the one which triggered the loss.
- size_t remaining_packets_in_recovery = number_of_packets_in_window * 2 - 1;
- for (size_t i = 0; i < remaining_packets_in_recovery - 1; i += 2) {
- AckNPackets(2);
- EXPECT_TRUE(sender_->TimeUntilSend(
- clock_.Now(), bytes_in_flight_, HAS_RETRANSMITTABLE_DATA).IsZero());
- EXPECT_EQ(1, SendAvailableSendWindow());
+ // We should send packets paced over the received acks for the remaining
+ // outstanding packets. The number of packets before we exit recovery is the
+ // original CWND minus the packet that has been lost and the one which
+ // triggered the loss.
+ size_t remaining_packets_in_recovery =
+ send_window_before_loss / kDefaultTCPMSS - 2;
+
+ for (size_t i = 0; i < remaining_packets_in_recovery; ++i) {
+ AckNPackets(1);
+ SendAvailableSendWindow();
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
}
// We need to ack another window before we increase CWND by 1.
+ size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
for (size_t i = 0; i < number_of_packets_in_window; ++i) {
AckNPackets(1);
EXPECT_EQ(1, SendAvailableSendWindow());
@@ -367,8 +366,8 @@ TEST_F(TcpCubicSenderTest, SlowStartBurstPacketLossPRR) {
// Test based on the second example in RFC6937, though we also implement
// forward acknowledgements, so the first two incoming acks will trigger
// PRR immediately.
- // Ack 10 packets in 5 acks to raise the CWND to 20, as in the example.
- const int kNumberOfAcks = 5;
+ // Ack 20 packets in 10 acks to raise the CWND to 30.
+ const int kNumberOfAcks = 10;
for (int i = 0; i < kNumberOfAcks; ++i) {
// Send our full send window.
SendAvailableSendWindow();
@@ -379,17 +378,20 @@ TEST_F(TcpCubicSenderTest, SlowStartBurstPacketLossPRR) {
(kDefaultTCPMSS * 2 * kNumberOfAcks);
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- // Ack a packet with a 15 packet gap, losing 13 of them due to FACK.
- LoseNPackets(13);
+ // Lose one more than the congestion window reduction, so that after loss,
+ // bytes_in_flight is lesser than the congestion window.
+ size_t send_window_after_loss = kRenoBeta * expected_send_window;
+ size_t num_packets_to_lose =
+ (expected_send_window - send_window_after_loss) / kDefaultTCPMSS + 1;
+ LoseNPackets(num_packets_to_lose);
// Immediately after the loss, ensure at least one packet can be sent.
// Losses without subsequent acks can occur with timer based loss detection.
EXPECT_TRUE(sender_->TimeUntilSend(
clock_.Now(), bytes_in_flight_, HAS_RETRANSMITTABLE_DATA).IsZero());
AckNPackets(1);
- // We should now have fallen out of slow start.
- // We expect window to be cut in half by Reno.
- expected_send_window /= 2;
+ // We should now have fallen out of slow start with a reduced window.
+ expected_send_window *= kRenoBeta;
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
// Only 2 packets should be allowed to be sent, per PRR-SSRB
@@ -409,15 +411,6 @@ TEST_F(TcpCubicSenderTest, SlowStartBurstPacketLossPRR) {
// Send 2 packets to simulate PRR-SSRB.
EXPECT_EQ(2, SendAvailableSendWindow());
- AckNPackets(1);
- EXPECT_EQ(2, SendAvailableSendWindow());
-
- AckNPackets(1);
- EXPECT_EQ(2, SendAvailableSendWindow());
-
- // The window should not have changed.
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
// Exit recovery and return to sending at the new rate.
for (int i = 0; i < kNumberOfAcks; ++i) {
AckNPackets(1);
@@ -609,9 +602,8 @@ TEST_F(TcpCubicSenderTest, 2ConnectionCongestionAvoidanceAtEndOfRecovery) {
LoseNPackets(1);
- // We should now have fallen out of slow start, and window should be cut in
- // half by Reno. New cwnd should be 10.
- expected_send_window /= 2;
+ // We should now have fallen out of slow start with a reduced window.
+ expected_send_window = expected_send_window * sender_->GetRenoBeta();
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
// No congestion window growth should occur in recovery phase, i.e., until the
@@ -626,22 +618,25 @@ TEST_F(TcpCubicSenderTest, 2ConnectionCongestionAvoidanceAtEndOfRecovery) {
EXPECT_FALSE(sender_->InRecovery());
// Out of recovery now. Congestion window should not grow for half an RTT.
+ size_t packets_in_send_window = expected_send_window / kDefaultTCPMSS;
SendAvailableSendWindow();
- AckNPackets(2);
+ AckNPackets(packets_in_send_window / 2 - 2);
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- // Next ack will be the 5th and should increase congestion window by 1MSS.
+ // Next ack should increase congestion window by 1MSS.
+ SendAvailableSendWindow();
AckNPackets(2);
expected_send_window += kDefaultTCPMSS;
+ packets_in_send_window += 1;
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- for (int i = 0; i < 2; ++i) {
- SendAvailableSendWindow();
- AckNPackets(2);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- }
+ // Congestion window should remain steady again for half an RTT.
+ SendAvailableSendWindow();
+ AckNPackets(packets_in_send_window / 2 - 1);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
// Next ack should cause congestion window to grow by 1MSS.
+ SendAvailableSendWindow();
AckNPackets(2);
expected_send_window += kDefaultTCPMSS;
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
@@ -663,9 +658,8 @@ TEST_F(TcpCubicSenderTest, 1ConnectionCongestionAvoidanceAtEndOfRecovery) {
LoseNPackets(1);
- // We should now have fallen out of slow start, and window should be cut in
- // half by Reno. New cwnd should be 10.
- expected_send_window /= 2;
+ // We should now have fallen out of slow start with a reduced window.
+ expected_send_window *= kRenoBeta;
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
// No congestion window growth should occur in recovery phase, i.e., until the
@@ -680,7 +674,7 @@ TEST_F(TcpCubicSenderTest, 1ConnectionCongestionAvoidanceAtEndOfRecovery) {
EXPECT_FALSE(sender_->InRecovery());
// Out of recovery now. Congestion window should not grow during RTT.
- for (int i = 0; i < 4; ++i) {
+ for (uint64 i = 0; i < expected_send_window / kDefaultTCPMSS - 2; i += 2) {
// Send our full send window.
SendAvailableSendWindow();
AckNPackets(2);
@@ -688,6 +682,7 @@ TEST_F(TcpCubicSenderTest, 1ConnectionCongestionAvoidanceAtEndOfRecovery) {
}
// Next ack should cause congestion window to grow by 1MSS.
+ SendAvailableSendWindow();
AckNPackets(2);
expected_send_window += kDefaultTCPMSS;
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
diff --git a/net/quic/crypto/common_cert_set.cc b/net/quic/crypto/common_cert_set.cc
index b60ac07..09379f3 100644
--- a/net/quic/crypto/common_cert_set.cc
+++ b/net/quic/crypto/common_cert_set.cc
@@ -80,12 +80,12 @@ int Compare(StringPiece a, const unsigned char* b, size_t b_len) {
class CommonCertSetsQUIC : public CommonCertSets {
public:
// CommonCertSets interface.
- virtual StringPiece GetCommonHashes() const override {
+ StringPiece GetCommonHashes() const override {
return StringPiece(reinterpret_cast<const char*>(kSetHashes),
sizeof(uint64) * arraysize(kSetHashes));
}
- virtual StringPiece GetCert(uint64 hash, uint32 index) const override {
+ StringPiece GetCert(uint64 hash, uint32 index) const override {
for (size_t i = 0; i < arraysize(kSets); i++) {
if (kSets[i].hash == hash) {
if (index < kSets[i].num_certs) {
@@ -100,10 +100,10 @@ class CommonCertSetsQUIC : public CommonCertSets {
return StringPiece();
}
- virtual bool MatchCert(StringPiece cert,
- StringPiece common_set_hashes,
- uint64* out_hash,
- uint32* out_index) const override {
+ bool MatchCert(StringPiece cert,
+ StringPiece common_set_hashes,
+ uint64* out_hash,
+ uint32* out_index) const override {
if (common_set_hashes.size() % sizeof(uint64) != 0) {
return false;
}
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 2509f6f..d010776 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -57,6 +57,7 @@ const QuicTag kIW10 = TAG('I', 'W', '1', '0'); // Force ICWND to 10
const QuicTag kPACE = TAG('P', 'A', 'C', 'E'); // Paced TCP cubic
const QuicTag k1CON = TAG('1', 'C', 'O', 'N'); // Emulate a single connection
const QuicTag kNTLP = TAG('N', 'T', 'L', 'P'); // No tail loss probe
+const QuicTag kNCON = TAG('N', 'C', 'O', 'N'); // N Connection Congestion Ctrl
// Loss detection algorithm types
const QuicTag kNACK = TAG('N', 'A', 'C', 'K'); // TCP style nack counting
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 934c801..21ea41a 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -196,6 +196,8 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id,
writer_(writer_factory.Create(this)),
owns_writer_(owns_writer),
encryption_level_(ENCRYPTION_NONE),
+ has_forward_secure_encrypter_(false),
+ first_required_forward_secure_packet_(0),
clock_(helper->GetClock()),
random_generator_(helper->GetRandomGenerator()),
connection_id_(connection_id),
@@ -285,6 +287,10 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) {
max_undecryptable_packets_ = config.max_undecryptable_packets();
}
+void QuicConnection::SetNumOpenStreams(size_t num_streams) {
+ sent_packet_manager_.SetNumOpenStreams(num_streams);
+}
+
bool QuicConnection::SelectMutualVersion(
const QuicVersionVector& available_versions) {
// Try to find the highest mutual version by iterating over supported
@@ -457,6 +463,14 @@ bool QuicConnection::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
void QuicConnection::OnDecryptedPacket(EncryptionLevel level) {
last_decrypted_packet_level_ = 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) {
+ SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ }
}
bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
@@ -1553,6 +1567,16 @@ void QuicConnection::OnWriteError(int error_code) {
void QuicConnection::OnSerializedPacket(
const SerializedPacket& serialized_packet) {
+ // 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 &&
+ has_forward_secure_encrypter_ &&
+ serialized_packet.sequence_number >=
+ first_required_forward_secure_packet_) {
+ SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ }
if (serialized_packet.retransmittable_frames) {
serialized_packet.retransmittable_frames->
set_encryption_level(encryption_level_);
@@ -1560,8 +1584,9 @@ void QuicConnection::OnSerializedPacket(
SendOrQueuePacket(QueuedPacket(serialized_packet, encryption_level_));
}
-void QuicConnection::OnCongestionWindowChange(QuicByteCount congestion_window) {
- packet_generator_.OnCongestionWindowChange(congestion_window);
+void QuicConnection::OnCongestionWindowChange() {
+ packet_generator_.OnCongestionWindowChange(
+ sent_packet_manager_.GetCongestionWindow());
visitor_->OnCongestionWindowChange(clock_->ApproximateNow());
}
@@ -1653,6 +1678,16 @@ 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) {
+ has_forward_secure_encrypter_ = true;
+ first_required_forward_secure_packet_ =
+ sequence_number_of_last_sent_packet_ +
+ // 3 times the current congestion window (in slow start) should cover
+ // about two full round trips worth of packets, which should be
+ // sufficient.
+ 3 * sent_packet_manager_.GetCongestionWindow() / max_packet_length();
+ }
}
const QuicEncrypter* QuicConnection::encrypter(EncryptionLevel level) const {
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index cd3d3d4..7a9e55d 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -257,6 +257,9 @@ class NET_EXPORT_PRIVATE QuicConnection
// Sets connection parameters from the supplied |config|.
void SetFromConfig(const QuicConfig& config);
+ // Sets the number of active streams on the connection for congestion control.
+ void SetNumOpenStreams(size_t num_streams);
+
// Send the data in |data| to the peer in as few packets as possible.
// Returns a pair with the number of bytes consumed from data, and a boolean
// indicating if the fin bit was consumed. This does not indicate the data
@@ -372,7 +375,7 @@ class NET_EXPORT_PRIVATE QuicConnection
void OnSerializedPacket(const SerializedPacket& packet) override;
// QuicSentPacketManager::NetworkChangeVisitor
- void OnCongestionWindowChange(QuicByteCount congestion_window) override;
+ void OnCongestionWindowChange() override;
// Called by the crypto stream when the handshake completes. In the server's
// case this is when the SHLO has been ACKed. Clients call this on receipt of
@@ -426,6 +429,7 @@ class NET_EXPORT_PRIVATE QuicConnection
// Sets (or resets) the idle state connection timeout. Also, checks and times
// out the connection if network timer has expired for |timeout|.
void SetIdleNetworkTimeout(QuicTime::Delta timeout);
+
// Sets (or resets) the total time delta the connection can be alive for.
// Also, checks and times out the connection if timer has expired for
// |timeout|. Used to limit the time a connection can be alive before crypto
@@ -526,6 +530,10 @@ class NET_EXPORT_PRIVATE QuicConnection
bool already_in_batch_mode_;
};
+ QuicPacketSequenceNumber sequence_number_of_last_sent_packet() const {
+ return sequence_number_of_last_sent_packet_;
+ }
+
protected:
// Packets which have not been written to the wire.
// Owns the QuicPacket* packet.
@@ -566,10 +574,6 @@ class NET_EXPORT_PRIVATE QuicConnection
bool peer_port_changed() const { return peer_port_changed_; }
- QuicPacketSequenceNumber sequence_number_of_last_sent_packet() const {
- return sequence_number_of_last_sent_packet_;
- }
-
private:
friend class test::QuicConnectionPeer;
friend class test::PacketSavingConnection;
@@ -678,7 +682,14 @@ class NET_EXPORT_PRIVATE QuicConnection
QuicConnectionHelperInterface* helper_; // Not owned.
QuicPacketWriter* writer_; // Owned or not depending on |owns_writer_|.
bool owns_writer_;
+ // Encryption level for new packets. Should only be changed via
+ // SetDefaultEncryptionLevel().
EncryptionLevel encryption_level_;
+ bool has_forward_secure_encrypter_;
+ // The sequence number of the first packet which will be encrypted with the
+ // foward-secure encrypter, even if the peer has not started sending
+ // forward-secure packets.
+ QuicPacketSequenceNumber first_required_forward_secure_packet_;
const QuicClock* clock_;
QuicRandom* random_generator_;
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 4dbbe13..b230fd5 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -2447,6 +2447,63 @@ TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
connection_.RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
}
+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();
+ connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ SendAckPacketToPeer();
+ EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+
+ // Set a forward-secure encrypter but do not make it the default, and verify
+ // that it is not yet used.
+ connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ new TaggingEncrypter(0x03));
+ SendAckPacketToPeer();
+ EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+
+ // Now simulate receipt of a forward-secure packet and verify that the
+ // forward-secure encrypter is now used.
+ connection_.OnDecryptedPacket(ENCRYPTION_FORWARD_SECURE);
+ SendAckPacketToPeer();
+ EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet());
+}
+
+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(
+ Return(congestion_window * kDefaultMaxPacketSize));
+
+ // 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();
+ connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ SendAckPacketToPeer();
+ EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+
+ // Set a forward-secure encrypter but do not make it the default, and
+ // verify that it is not yet used.
+ connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ new TaggingEncrypter(0x03));
+ SendAckPacketToPeer();
+ EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+
+ // Now send a packet "Far enough" after the encrypter was set and verify that
+ // the forward-secure encrypter is now used.
+ for (uint64 i = 0; i < 3 * congestion_window - 1; ++i) {
+ EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+ SendAckPacketToPeer();
+ }
+ EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet());
+}
+
TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) {
// SetFromConfig is always called after construction from InitializeSession.
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
@@ -4012,7 +4069,9 @@ TEST_P(QuicConnectionTest, NetworkChangeVisitorCallbacksChangeFecState) {
EXPECT_TRUE(visitor);
// Increase FEC group size by increasing congestion window to a large number.
- visitor->OnCongestionWindowChange(1000 * kDefaultTCPMSS);
+ EXPECT_CALL(*send_algorithm_, GetCongestionWindow()).WillRepeatedly(
+ Return(1000 * kDefaultTCPMSS));
+ visitor->OnCongestionWindowChange();
EXPECT_LT(max_packets_per_fec_group, creator->max_packets_per_fec_group());
}
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index 73ae154..dac2087 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -11,6 +11,7 @@
#include "net/quic/crypto/quic_crypto_server_config.h"
#include "net/quic/crypto/source_address_token.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"
@@ -119,8 +120,7 @@ void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
session()->connection()->SetEncrypter(
ENCRYPTION_INITIAL,
crypto_negotiated_params_.initial_crypters.encrypter.release());
- session()->connection()->SetDefaultEncryptionLevel(
- ENCRYPTION_INITIAL);
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
// Set the decrypter immediately so that we no longer accept unencrypted
// packets.
session()->connection()->SetDecrypter(
@@ -140,8 +140,10 @@ void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
session()->connection()->SetEncrypter(
ENCRYPTION_FORWARD_SECURE,
crypto_negotiated_params_.forward_secure_crypters.encrypter.release());
- session()->connection()->SetDefaultEncryptionLevel(
- ENCRYPTION_FORWARD_SECURE);
+ 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 */);
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index ae57199..682e06e 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -58,3 +58,7 @@ 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;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index b557c35..271b02e 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -21,5 +21,6 @@ NET_EXPORT_PRIVATE extern bool FLAGS_quic_drop_junk_packets;
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;
#endif // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index 454d77e..deb6a9e 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -84,7 +84,6 @@ QuicPacketGenerator::~QuicPacketGenerator() {
}
}
-// NetworkChangeVisitor method.
void QuicPacketGenerator::OnCongestionWindowChange(
QuicByteCount congestion_window) {
packet_creator_.set_max_packets_per_fec_group(
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 6383677..64d0c23 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -133,6 +133,9 @@ const int kMinIntervalBetweenServerConfigUpdatesRTTs = 10;
// Minimum time between Server Config Updates (SCUP) sent to client.
const int kMinIntervalBetweenServerConfigUpdatesMs = 1000;
+// Minimum number of packets between Server Config Updates (SCUP).
+const int kMinPacketsBetweenServerConfigUpdates = 100;
+
// The number of open streams that a server will accept is set to be slightly
// larger than the negotiated limit. Immediately closing the connection if the
// client opens slightly too many streams is not ideal: the client may have sent
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 553e7e2..6370d9f 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -78,6 +78,7 @@ QuicSentPacketManager::QuicSentPacketManager(
congestion_control_type,
stats)),
loss_algorithm_(LossDetectionInterface::Create(loss_type)),
+ n_connection_simulation_(false),
receive_buffer_bytes_(kDefaultSocketReceiveBuffer),
least_packet_awaited_by_peer_(1),
first_rto_transmission_(0),
@@ -125,6 +126,9 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
if (HasClientSentConnectionOption(config, k1CON)) {
send_algorithm_->SetNumEmulatedConnections(1);
}
+ if (HasClientSentConnectionOption(config, kNCON)) {
+ n_connection_simulation_ = true;
+ }
if (HasClientSentConnectionOption(config, kNTLP)) {
max_tail_loss_probes_ = 0;
}
@@ -140,7 +144,15 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
send_algorithm_->SetFromConfig(config, is_server_);
if (network_change_visitor_ != nullptr) {
- network_change_visitor_->OnCongestionWindowChange(GetCongestionWindow());
+ network_change_visitor_->OnCongestionWindowChange();
+ }
+}
+
+void QuicSentPacketManager::SetNumOpenStreams(size_t num_streams) {
+ if (n_connection_simulation_) {
+ // Ensure the number of connections is between 1 and 5.
+ send_algorithm_->SetNumEmulatedConnections(
+ min<size_t>(5, max<size_t>(1, num_streams)));
}
}
@@ -225,7 +237,7 @@ void QuicSentPacketManager::MaybeInvokeCongestionEvent(
packets_acked_.clear();
packets_lost_.clear();
if (network_change_visitor_ != nullptr) {
- network_change_visitor_->OnCongestionWindowChange(GetCongestionWindow());
+ network_change_visitor_->OnCongestionWindowChange();
}
}
@@ -650,7 +662,7 @@ void QuicSentPacketManager::RetransmitAllPackets() {
}
if (network_change_visitor_ != nullptr) {
- network_change_visitor_->OnCongestionWindowChange(GetCongestionWindow());
+ network_change_visitor_->OnCongestionWindowChange();
}
}
@@ -818,8 +830,7 @@ const QuicTime::Delta QuicSentPacketManager::GetTailLossProbeDelay() const {
QuicTime::Delta srtt = rtt_stats_.SmoothedRtt();
if (!unacked_packets_.HasMultipleInFlightPackets()) {
return QuicTime::Delta::Max(
- srtt.Multiply(2),
- srtt.Multiply(1.5).Add(
+ srtt.Multiply(2), srtt.Multiply(1.5).Add(
QuicTime::Delta::FromMilliseconds(kMinRetransmissionTimeMs / 2)));
}
return QuicTime::Delta::FromMilliseconds(
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index 837bfb5..cccacab 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -67,7 +67,7 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
virtual ~NetworkChangeVisitor() {}
// Called when congestion window may have changed.
- virtual void OnCongestionWindowChange(QuicByteCount congestion_window) = 0;
+ virtual void OnCongestionWindowChange() = 0;
// TODO(jri): Add OnRttStatsChange() to this class as well.
};
@@ -98,6 +98,8 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
virtual void SetFromConfig(const QuicConfig& config);
+ void SetNumOpenStreams(size_t num_streams);
+
void SetHandshakeConfirmed() { handshake_confirmed_ = true; }
// Processes the incoming ack.
@@ -345,6 +347,7 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
RttStats rtt_stats_;
scoped_ptr<SendAlgorithmInterface> send_algorithm_;
scoped_ptr<LossDetectionInterface> loss_algorithm_;
+ bool n_connection_simulation_;
// Receiver side buffer in bytes.
QuicByteCount receive_buffer_bytes_;
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index 5eabf86..bf8c99c 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -15,6 +15,7 @@
using std::vector;
using testing::AnyNumber;
using testing::ElementsAre;
+using testing::IsEmpty;
using testing::Pair;
using testing::Pointwise;
using testing::Return;
@@ -99,18 +100,14 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
void ExpectAck(QuicPacketSequenceNumber largest_observed) {
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(
- true, _, ElementsAre(Pair(largest_observed, _)), _));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(100 * kDefaultTCPMSS));
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
+ true, _, ElementsAre(Pair(largest_observed, _)), IsEmpty()));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
}
void ExpectUpdatedRtt(QuicPacketSequenceNumber largest_observed) {
EXPECT_CALL(*send_algorithm_,
- OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(100 * kDefaultTCPMSS));
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
+ OnCongestionEvent(true, _, IsEmpty(), IsEmpty()));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
}
void ExpectAckAndLoss(bool rtt_updated,
@@ -119,9 +116,7 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(
rtt_updated, _, ElementsAre(Pair(largest_observed, _)),
ElementsAre(Pair(lost_packet, _))));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(100 * kDefaultTCPMSS));
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
}
// |packets_acked| and |packets_lost| should be in sequence number order.
@@ -142,9 +137,7 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
OnCongestionEvent(rtt_updated, _,
Pointwise(KeyEq(), ack_vector),
Pointwise(KeyEq(), lost_vector)));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillRepeatedly(Return(100 * kDefaultTCPMSS));
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_)).
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange()).
Times(AnyNumber());
}
@@ -395,9 +388,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckPreviousBeforeSend) {
// Fire the RTO, which will mark 2 for retransmission (but will not send it).
EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(2 * kDefaultTCPMSS));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
manager_.OnRetransmissionTimeout();
EXPECT_TRUE(manager_.HasPendingRetransmissions());
@@ -839,9 +830,7 @@ TEST_F(QuicSentPacketManagerTest, TailLossProbeThenRTO) {
// The final RTO abandons all of them.
EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(2 * kDefaultTCPMSS));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
manager_.OnRetransmissionTimeout();
EXPECT_TRUE(manager_.HasPendingRetransmissions());
EXPECT_EQ(2u, stats_.tlp_count);
@@ -1077,9 +1066,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmissionTimeout) {
}
EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(2 * kDefaultTCPMSS));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_FALSE(manager_.MaybeRetransmitTailLossProbe());
manager_.OnRetransmissionTimeout();
}
@@ -1171,9 +1158,7 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeRTO) {
EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
// Retransmit the packet by invoking the retransmission timeout.
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(2 * kDefaultTCPMSS));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
clock_.AdvanceTime(expected_rto_delay);
manager_.OnRetransmissionTimeout();
@@ -1219,9 +1204,7 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionDelayMin) {
EXPECT_EQ(delay,
QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_));
delay = delay.Add(delay);
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(2 * kDefaultTCPMSS));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
manager_.OnRetransmissionTimeout();
RetransmitNextPacket(i + 2);
@@ -1247,9 +1230,7 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionDelay) {
EXPECT_EQ(delay,
QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_));
delay = delay.Add(delay);
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(2 * kDefaultTCPMSS));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
manager_.OnRetransmissionTimeout();
RetransmitNextPacket(i + 2);
@@ -1297,9 +1278,7 @@ TEST_F(QuicSentPacketManagerTest, NegotiateTimeLossDetectionFromOptions) {
options.push_back(kTIME);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(100 * kDefaultTCPMSS));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
manager_.SetFromConfig(config);
EXPECT_EQ(kTime,
@@ -1314,7 +1293,7 @@ TEST_F(QuicSentPacketManagerTest, NegotiateCongestionControlFromOptions) {
options.push_back(kRENO);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
manager_.SetFromConfig(config);
EXPECT_EQ(kReno, QuicSentPacketManagerPeer::GetSendAlgorithm(
manager_)->GetCongestionControlType());
@@ -1324,7 +1303,7 @@ TEST_F(QuicSentPacketManagerTest, NegotiateCongestionControlFromOptions) {
options.clear();
options.push_back(kTBBR);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
manager_.SetFromConfig(config);
EXPECT_EQ(kBBR, QuicSentPacketManagerPeer::GetSendAlgorithm(
manager_)->GetCongestionControlType());
@@ -1337,33 +1316,44 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNumConnectionsFromOptions) {
options.push_back(k1CON);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(1));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(100 * kDefaultTCPMSS));
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
manager_.SetFromConfig(config);
QuicSentPacketManagerPeer::SetIsServer(&manager_, false);
QuicConfig client_config;
client_config.SetConnectionOptionsToSend(options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(1));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(100 * kDefaultTCPMSS));
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
manager_.SetFromConfig(client_config);
}
+TEST_F(QuicSentPacketManagerTest, NegotiateNConnectionFromOptions) {
+ // By default, changing the number of open streams does nothing.
+ manager_.SetNumOpenStreams(5);
+
+ QuicConfig config;
+ QuicTagVector options;
+
+ options.push_back(kNCON);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ manager_.SetFromConfig(config);
+
+ EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(5));
+ manager_.SetNumOpenStreams(5);
+}
+
TEST_F(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtServer) {
QuicConfig config;
QuicTagVector options;
options.push_back(kNTLP);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(100 * kDefaultTCPMSS));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
manager_.SetFromConfig(config);
EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_));
@@ -1376,9 +1366,7 @@ TEST_F(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtClient) {
options.push_back(kNTLP);
QuicSentPacketManagerPeer::SetIsServer(&manager_, false);
client_config.SetConnectionOptionsToSend(options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(100 * kDefaultTCPMSS));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
manager_.SetFromConfig(client_config);
EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_));
@@ -1391,9 +1379,7 @@ TEST_F(QuicSentPacketManagerTest, NegotiatePacingFromOptions) {
QuicTagVector options;
options.push_back(kPACE);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(100 * kDefaultTCPMSS));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
manager_.SetFromConfig(config);
@@ -1408,9 +1394,7 @@ TEST_F(QuicSentPacketManagerTest, NegotiateReceiveWindowFromOptions) {
QuicConfig client_config;
QuicConfigPeer::SetReceivedSocketReceiveBuffer(&client_config, 1024);
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(100 * kDefaultTCPMSS));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
manager_.SetFromConfig(client_config);
EXPECT_EQ(kMinSocketReceiveBuffer,
@@ -1441,9 +1425,7 @@ TEST_F(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) {
QuicConfig config;
config.SetInitialRoundTripTimeUsToSend(initial_rtt_us);
EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange(_));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(100 * kDefaultTCPMSS));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
manager_.SetFromConfig(config);
EXPECT_EQ(initial_rtt_us,
diff --git a/net/quic/quic_server_session.cc b/net/quic/quic_server_session.cc
index 9d45162..efb0bcf 100644
--- a/net/quic/quic_server_session.cc
+++ b/net/quic/quic_server_session.cc
@@ -19,7 +19,8 @@ QuicServerSession::QuicServerSession(const QuicConfig& config,
: QuicSession(connection, config),
visitor_(visitor),
bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
- last_server_config_update_time_(QuicTime::Zero()) {}
+ last_scup_time_(QuicTime::Zero()),
+ last_scup_sequence_number_(0) {}
QuicServerSession::~QuicServerSession() {}
@@ -68,14 +69,18 @@ void QuicServerSession::OnCongestionWindowChange(QuicTime now) {
}
// If not enough time has passed since the last time we sent an update to the
- // client, then return early.
+ // client, or not enough packets have been sent, then return early.
const QuicSentPacketManager& sent_packet_manager =
connection()->sent_packet_manager();
int64 srtt_ms =
sent_packet_manager.GetRttStats()->SmoothedRtt().ToMilliseconds();
- int64 now_ms = now.Subtract(last_server_config_update_time_).ToMilliseconds();
+ int64 now_ms = now.Subtract(last_scup_time_).ToMilliseconds();
+ int64 packets_since_last_scup =
+ connection()->sequence_number_of_last_sent_packet() -
+ last_scup_sequence_number_;
if (now_ms < (kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms) ||
- now_ms < kMinIntervalBetweenServerConfigUpdatesMs) {
+ now_ms < kMinIntervalBetweenServerConfigUpdatesMs ||
+ packets_since_last_scup < kMinPacketsBetweenServerConfigUpdates) {
return;
}
@@ -134,7 +139,9 @@ void QuicServerSession::OnCongestionWindowChange(QuicTime now) {
}
crypto_stream_->SendServerConfigUpdate(&cached_network_params);
- last_server_config_update_time_ = now;
+ last_scup_time_ = now;
+ last_scup_sequence_number_ =
+ connection()->sequence_number_of_last_sent_packet();
}
bool QuicServerSession::ShouldCreateIncomingDataStream(QuicStreamId id) {
diff --git a/net/quic/quic_server_session.h b/net/quic/quic_server_session.h
index 2f0bdea..43107a0 100644
--- a/net/quic/quic_server_session.h
+++ b/net/quic/quic_server_session.h
@@ -20,16 +20,16 @@
namespace net {
+namespace test {
+class QuicServerSessionPeer;
+} // namespace test
+
class QuicBlockedWriterInterface;
class QuicConfig;
class QuicConnection;
class QuicCryptoServerConfig;
class ReliableQuicStream;
-namespace test {
-class QuicServerSessionPeer;
-} // namespace test
-
// An interface from the session to the entity owning the session.
// This lets the session notify its owner (the Dispatcher) when the connection
// is closed or blocked.
@@ -99,7 +99,10 @@ class QuicServerSession : public QuicSession {
string serving_region_;
// Time at which we send the last SCUP to the client.
- QuicTime last_server_config_update_time_;
+ QuicTime last_scup_time_;
+
+ // Number of packets sent to the peer, at the time we last sent a SCUP.
+ int64 last_scup_sequence_number_;
DISALLOW_COPY_AND_ASSIGN(QuicServerSession);
};
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 3c00e8b..4e1fc7b 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -48,8 +48,8 @@ class VisitorShim : public QuicConnectionVisitorInterface {
session_->PostProcessAfterData();
}
- void OnWindowUpdateFrames(
- const vector<QuicWindowUpdateFrame>& frames) override {
+ void OnWindowUpdateFrames(const vector<QuicWindowUpdateFrame>& frames)
+ override {
session_->OnWindowUpdateFrames(frames);
session_->PostProcessAfterData();
}
@@ -428,6 +428,8 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id,
stream_map_.erase(it);
stream->OnClose();
+ // Decrease the number of streams being emulated when a new one is opened.
+ connection_->SetNumOpenStreams(stream_map_.size());
}
void QuicSession::UpdateFlowControlOnFinalReceivedByteOffset(
@@ -595,6 +597,8 @@ void QuicSession::ActivateStream(QuicDataStream* stream) {
<< ". activating " << stream->id();
DCHECK_EQ(stream_map_.count(stream->id()), 0u);
stream_map_[stream->id()] = stream;
+ // Increase the number of streams being emulated when a new one is opened.
+ connection_->SetNumOpenStreams(stream_map_.size());
}
QuicStreamId QuicSession::GetNextStreamId() {
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc
index d2c6399..8a8df46 100644
--- a/net/quic/test_tools/quic_connection_peer.cc
+++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -248,5 +248,11 @@ QuicPacketHeader* QuicConnectionPeer::GetLastHeader(
return &connection->last_header_;
}
+// static
+void QuicConnectionPeer::SetSequenceNumberOfLastSentPacket(
+ QuicConnection* connection, QuicPacketSequenceNumber number) {
+ connection->sequence_number_of_last_sent_packet_ = number;
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h
index 5216d43..d452d43 100644
--- a/net/quic/test_tools/quic_connection_peer.h
+++ b/net/quic/test_tools/quic_connection_peer.h
@@ -121,6 +121,9 @@ class QuicConnectionPeer {
static QuicPacketHeader* GetLastHeader(QuicConnection* connection);
+ static void SetSequenceNumberOfLastSentPacket(
+ QuicConnection* connection, QuicPacketSequenceNumber number);
+
private:
DISALLOW_COPY_AND_ASSIGN(QuicConnectionPeer);
};
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 867e8de..ea5e5ef 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -538,7 +538,7 @@ class MockNetworkChangeVisitor :
MockNetworkChangeVisitor();
virtual ~MockNetworkChangeVisitor();
- MOCK_METHOD1(OnCongestionWindowChange, void(QuicByteCount));
+ MOCK_METHOD0(OnCongestionWindowChange, void());
private:
DISALLOW_COPY_AND_ASSIGN(MockNetworkChangeVisitor);
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 8974a11..e3b9ef8 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -178,6 +178,7 @@ class ClientDelegate : public PacketDroppingTestWriter::Delegate {
EpollEvent event(EPOLLOUT, false);
client_->OnEvent(client_->fd(), &event);
}
+
private:
QuicClient* client_;
};
diff --git a/net/tools/quic/quic_client_session.h b/net/tools/quic/quic_client_session.h
index 15dd1c8..3c92efa 100644
--- a/net/tools/quic/quic_client_session.h
+++ b/net/tools/quic/quic_client_session.h
@@ -28,11 +28,6 @@ class QuicClientSession : public QuicClientSessionBase {
QuicClientSession(const QuicConfig& config, QuicConnection* connection);
~QuicClientSession() override;
- // QuicClientSessionBase methods:
- void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override;
- void OnProofVerifyDetailsAvailable(
- const ProofVerifyDetails& verify_details) override;
-
void InitializeSession(const QuicServerId& server_id,
QuicCryptoClientConfig* config);
@@ -40,6 +35,11 @@ class QuicClientSession : public QuicClientSessionBase {
QuicSpdyClientStream* CreateOutgoingDataStream() override;
QuicCryptoClientStream* GetCryptoStream() override;
+ // QuicClientSessionBase methods:
+ void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override;
+ void OnProofVerifyDetailsAvailable(
+ const ProofVerifyDetails& verify_details) override;
+
// Performs a crypto handshake with the server. Returns true if the crypto
// handshake is started successfully.
bool CryptoConnect();
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 982a42d..64e664d 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -20,7 +20,8 @@ QuicServerSession::QuicServerSession(const QuicConfig& config,
: QuicSession(connection, config),
visitor_(visitor),
bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
- last_server_config_update_time_(QuicTime::Zero()) {}
+ last_scup_time_(QuicTime::Zero()),
+ last_scup_sequence_number_(0) {}
QuicServerSession::~QuicServerSession() {}
@@ -69,14 +70,18 @@ void QuicServerSession::OnCongestionWindowChange(QuicTime now) {
}
// If not enough time has passed since the last time we sent an update to the
- // client, then return early.
+ // client, or not enough packets have been sent, then return early.
const QuicSentPacketManager& sent_packet_manager =
connection()->sent_packet_manager();
int64 srtt_ms =
sent_packet_manager.GetRttStats()->SmoothedRtt().ToMilliseconds();
- int64 now_ms = now.Subtract(last_server_config_update_time_).ToMilliseconds();
+ int64 now_ms = now.Subtract(last_scup_time_).ToMilliseconds();
+ int64 packets_since_last_scup =
+ connection()->sequence_number_of_last_sent_packet() -
+ last_scup_sequence_number_;
if (now_ms < (kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms) ||
- now_ms < kMinIntervalBetweenServerConfigUpdatesMs) {
+ now_ms < kMinIntervalBetweenServerConfigUpdatesMs ||
+ packets_since_last_scup < kMinPacketsBetweenServerConfigUpdates) {
return;
}
@@ -135,7 +140,9 @@ void QuicServerSession::OnCongestionWindowChange(QuicTime now) {
}
crypto_stream_->SendServerConfigUpdate(&cached_network_params);
- last_server_config_update_time_ = now;
+ last_scup_time_ = now;
+ last_scup_sequence_number_ =
+ connection()->sequence_number_of_last_sent_packet();
}
bool QuicServerSession::ShouldCreateIncomingDataStream(QuicStreamId id) {
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h
index acec14b..603ad35 100644
--- a/net/tools/quic/quic_server_session.h
+++ b/net/tools/quic/quic_server_session.h
@@ -100,7 +100,10 @@ class QuicServerSession : public QuicSession {
string serving_region_;
// Time at which we send the last SCUP to the client.
- QuicTime last_server_config_update_time_;
+ QuicTime last_scup_time_;
+
+ // Number of packets sent to the peer, at the time we last sent a SCUP.
+ int64 last_scup_sequence_number_;
DISALLOW_COPY_AND_ASSIGN(QuicServerSession);
};
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc
index 64d0be4..9f36241 100644
--- a/net/tools/quic/quic_server_session_test.cc
+++ b/net/tools/quic/quic_server_session_test.cc
@@ -339,11 +339,18 @@ TEST_P(QuicServerSessionTest, BandwidthEstimates) {
bandwidth_estimate_kbytes_per_second * 1.6;
session_->OnCongestionWindowChange(now);
- // Bandwidth estimate has now changed sufficiently and enough time has passed.
+ // Bandwidth estimate has now changed sufficiently and enough time has passed,
+ // but not enough packets have been sent.
int64 srtt_ms =
sent_packet_manager->GetRttStats()->SmoothedRtt().ToMilliseconds();
now = now.Add(QuicTime::Delta::FromMilliseconds(
kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms));
+ session_->OnCongestionWindowChange(now);
+
+ // Bandwidth estimate has now changed sufficiently, enough time has passed,
+ // and enough packets have been sent.
+ QuicConnectionPeer::SetSequenceNumberOfLastSentPacket(
+ session_->connection(), kMinPacketsBetweenServerConfigUpdates);
// Verify that the proto has exactly the values we expect.
CachedNetworkParameters expected_network_params;