diff options
author | rtenneti <rtenneti@chromium.org> | 2014-11-03 20:17:00 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-04 04:17:20 +0000 |
commit | 33da8ab021168895957e45ad4d1af9e991a2c665 (patch) | |
tree | c212fcc3dab23e9df9d0e0e14156ac6a31da366d | |
parent | 3e7c2a6ee80e05fc6b8090bee850c40b8a2a3810 (diff) | |
download | chromium_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}
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; |