Land Recent QUIC Changes.
Trying to merge as many of flow control changes as possible before the
branch (we have all changed until Fri 06/13 21:20 UTC).
Test tools for udp proxying. This involves a few refactors of test
tools but nothing which affects the internal server.
minor refactors to allow quic udp proxy testing.
Merge internal change: 69157651
https://codereview.chromium.org/331963002/
Added FEC policy per stream, which is translated to an FEC protection
value on writes further on down.
Merge internal change: 69153464
https://codereview.chromium.org/338623002/
Pull out stream/session updates from OnConfigNegotiated. Preparation for
updating stream/session with different received windows.
QUIC refector: Pull out stream/session updates from OnConfigNegotiated
Merge internal change: 69106467
https://codereview.chromium.org/337723003/
Rather than passing initial_flow_control_window all the way down the
call stack, put it inside QuicConfig as intended: each member of
QuicConfig has a "value to send" field, so populate this at the top
level.
rtenneti: when porting to Chromium, you should add
config.SetInitialFlowControlWindowToSend(kInitialReceiveWindowSize)
in QuicStreamFactory::CreateSession, just above line 837: *session =
new QuicClientSession(...)
Store initial flow control window for QUIC in QuicConfig. No behavior
change intended.
Added the following unit tests to EndToEndTest.cc
+ DoNotSetResumeWriteAlarmIfConnectionFlowControlBlocked
+ NegotiateMaxOpenStreams
Merge internal change: 69079363
https://codereview.chromium.org/333803007/
First version of a QUIC SendAlgorithmSimulator which is designed to
simulate BBR and TCP flows and changes.
Merge internal change: 69035927
https://codereview.chromium.org/330163003/
[email protected], [email protected]
Review URL: https://codereview.chromium.org/330333006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@277959 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/net.gypi b/net/net.gypi
index 748acc3..6571fb9a 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -1404,6 +1404,8 @@
'quic/congestion_control/leaky_bucket_test.cc',
'quic/congestion_control/pacing_sender_test.cc',
'quic/congestion_control/rtt_stats_test.cc',
+ 'quic/congestion_control/send_algorithm_simulator.cc',
+ 'quic/congestion_control/send_algorithm_simulator.h',
'quic/congestion_control/tcp_cubic_sender_test.cc',
'quic/congestion_control/tcp_loss_algorithm_test.cc',
'quic/congestion_control/tcp_receiver_test.cc',
diff --git a/net/quic/congestion_control/send_algorithm_simulator.cc b/net/quic/congestion_control/send_algorithm_simulator.cc
new file mode 100644
index 0000000..d539013
--- /dev/null
+++ b/net/quic/congestion_control/send_algorithm_simulator.cc
@@ -0,0 +1,273 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/send_algorithm_simulator.h"
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "net/quic/crypto/quic_random.h"
+
+using std::list;
+using std::max;
+using std::min;
+
+namespace net {
+
+namespace {
+
+const QuicByteCount kPacketSize = 1200;
+
+} // namespace
+
+SendAlgorithmSimulator::SendAlgorithmSimulator(
+ SendAlgorithmInterface* send_algorithm,
+ MockClock* clock,
+ RttStats* rtt_stats,
+ QuicBandwidth bandwidth,
+ QuicTime::Delta rtt)
+ : send_algorithm_(send_algorithm),
+ clock_(clock),
+ rtt_stats_(rtt_stats),
+ next_sent_(1),
+ last_acked_(0),
+ next_acked_(1),
+ lose_next_ack_(false),
+ bytes_in_flight_(0),
+ forward_loss_rate_(0),
+ reverse_loss_rate_(0),
+ loss_correlation_(0),
+ bandwidth_(bandwidth),
+ rtt_(rtt),
+ buffer_size_(1000000),
+ max_cwnd_(0),
+ min_cwnd_(100000),
+ max_cwnd_drop_(0),
+ last_cwnd_(0) {
+ uint32 seed = base::RandInt(0, std::numeric_limits<int32>::max());
+ DVLOG(1) << "Seeding SendAlgorithmSimulator with " << seed;
+ simple_random_.set_seed(seed);
+}
+
+SendAlgorithmSimulator::~SendAlgorithmSimulator() {}
+
+// Sends the specified number of bytes as quickly as possible and returns the
+// average bandwidth in bytes per second. The time elapsed is based on
+// waiting for all acks to arrive.
+QuicBandwidth SendAlgorithmSimulator::SendBytes(size_t num_bytes) {
+ const QuicTime start_time = clock_->Now();
+ size_t bytes_acked = 0;
+ while (bytes_acked < num_bytes) {
+ DVLOG(1) << "bytes_acked:" << bytes_acked << " bytes_in_flight_:"
+ << bytes_in_flight_ << " CWND(bytes):"
+ << send_algorithm_->GetCongestionWindow();
+ // Determine the times of next send and of the next ack arrival.
+ QuicTime::Delta send_delta = send_algorithm_->TimeUntilSend(
+ clock_->Now(), bytes_in_flight_, HAS_RETRANSMITTABLE_DATA);
+ // If we've already sent enough bytes, wait for them to be acked.
+ if (bytes_acked + bytes_in_flight_ >= num_bytes) {
+ send_delta = QuicTime::Delta::Infinite();
+ }
+ QuicTime::Delta ack_delta = NextAckDelta();
+ // If both times are infinite, fire a TLP.
+ if (ack_delta.IsInfinite() && send_delta.IsInfinite()) {
+ DVLOG(1) << "Both times are infinite, simulating a TLP.";
+ // TODO(ianswett): Use a more sophisticated TLP timer.
+ clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
+ SendDataNow();
+ } else if (ack_delta < send_delta) {
+ DVLOG(1) << "Handling ack, advancing time:"
+ << ack_delta.ToMicroseconds() << "us";
+ // Ack data all the data up to ack time and lose any missing sequence
+ // numbers.
+ clock_->AdvanceTime(ack_delta);
+ bytes_acked += HandlePendingAck();
+ } else {
+ DVLOG(1) << "Sending, advancing time:"
+ << send_delta.ToMicroseconds() << "us";
+ clock_->AdvanceTime(send_delta);
+ SendDataNow();
+ }
+ RecordStats();
+ }
+ return QuicBandwidth::FromBytesAndTimeDelta(
+ num_bytes, clock_->Now().Subtract(start_time));
+}
+
+// NextAck takes into account packet loss in both forward and reverse
+// direction, as well as correlated losses. And it assumes the receiver acks
+// every other packet when there is no loss.
+QuicTime::Delta SendAlgorithmSimulator::NextAckDelta() {
+ if (sent_packets_.empty() || AllPacketsLost()) {
+ DVLOG(1) << "No outstanding packets to cause acks. sent_packets_.size():"
+ << sent_packets_.size();
+ return QuicTime::Delta::Infinite();
+ }
+
+ // If necessary, determine next_acked_.
+ // This is only done once to ensure multiple calls return the same time.
+ FindNextAcked();
+
+ // If only one packet is acked, simulate a delayed ack.
+ if (next_acked_ - last_acked_ == 1) {
+ return sent_packets_.front().ack_time.Add(
+ QuicTime::Delta::FromMilliseconds(100)).Subtract(clock_->Now());
+ }
+ for (list<SentPacket>::const_iterator it = sent_packets_.begin();
+ it != sent_packets_.end(); ++it) {
+ if (next_acked_ == it->sequence_number) {
+ return it->ack_time.Subtract(clock_->Now());
+ }
+ }
+ LOG(DFATAL) << "Error, next_acked_: " << next_acked_
+ << " should have been found in sent_packets_";
+ return QuicTime::Delta::Infinite();
+}
+
+bool SendAlgorithmSimulator::AllPacketsLost() {
+ for (list<SentPacket>::const_iterator it = sent_packets_.begin();
+ it != sent_packets_.end(); ++it) {
+ if (it->ack_time.IsInitialized()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void SendAlgorithmSimulator::FindNextAcked() {
+ // TODO(ianswett): Add a simpler mode which acks every packet.
+ bool packets_lost = false;
+ if (next_acked_ == last_acked_) {
+ // Determine if the next ack is lost only once, to ensure determinism.
+ lose_next_ack_ =
+ reverse_loss_rate_ * kuint64max > simple_random_.RandUint64();
+ }
+ bool two_acks_remaining = lose_next_ack_;
+ next_acked_ = last_acked_;
+ // Remove any packets that are simulated as lost.
+ for (list<SentPacket>::const_iterator it = sent_packets_.begin();
+ it != sent_packets_.end(); ++it) {
+ // Lost packets don't trigger an ack.
+ if (it->ack_time == QuicTime::Zero()) {
+ packets_lost = true;
+ continue;
+ }
+ // Buffer dropped packets are skipped automatically, but still end up
+ // being lost and cause acks to be sent immediately.
+ if (next_acked_ < it->sequence_number - 1) {
+ packets_lost = true;
+ }
+ next_acked_ = it->sequence_number;
+ if (packets_lost || (next_acked_ - last_acked_) % 2 == 0) {
+ if (two_acks_remaining) {
+ two_acks_remaining = false;
+ } else {
+ break;
+ }
+ }
+ }
+ DVLOG(1) << "FindNextAcked found next_acked_:" << next_acked_
+ << " last_acked:" << last_acked_;
+}
+
+int SendAlgorithmSimulator::HandlePendingAck() {
+ DCHECK_LT(last_acked_, next_acked_);
+ SendAlgorithmInterface::CongestionMap acked_packets;
+ SendAlgorithmInterface::CongestionMap lost_packets;
+ // Some entries may be missing from the sent_packets_ array, if they were
+ // dropped due to buffer overruns.
+ SentPacket largest_observed = sent_packets_.front();
+ while (last_acked_ < next_acked_) {
+ ++last_acked_;
+ TransmissionInfo info = TransmissionInfo();
+ info.bytes_sent = kPacketSize;
+ info.in_flight = true;
+ // If it's missing from the array, it's a loss.
+ if (sent_packets_.front().sequence_number > last_acked_) {
+ DVLOG(1) << "Lost packet:" << last_acked_
+ << " dropped by buffer overflow.";
+ lost_packets[last_acked_] = info;
+ continue;
+ }
+ if (sent_packets_.front().ack_time.IsInitialized()) {
+ acked_packets[last_acked_] = info;
+ } else {
+ lost_packets[last_acked_] = info;
+ }
+ // Remove all packets from the front to next_acked_.
+ largest_observed = sent_packets_.front();
+ sent_packets_.pop_front();
+ }
+
+ DCHECK(largest_observed.ack_time.IsInitialized());
+ rtt_stats_->UpdateRtt(
+ largest_observed.ack_time.Subtract(largest_observed.send_time),
+ QuicTime::Delta::Zero(),
+ clock_->Now());
+ send_algorithm_->OnCongestionEvent(
+ true, bytes_in_flight_, acked_packets, lost_packets);
+ DCHECK_LE(kPacketSize * (acked_packets.size() + lost_packets.size()),
+ bytes_in_flight_);
+ bytes_in_flight_ -=
+ kPacketSize * (acked_packets.size() + lost_packets.size());
+ return acked_packets.size() * kPacketSize;
+}
+
+void SendAlgorithmSimulator::SendDataNow() {
+ DVLOG(1) << "Sending packet:" << next_sent_ << " bytes_in_flight:"
+ << bytes_in_flight_;
+ send_algorithm_->OnPacketSent(
+ clock_->Now(), bytes_in_flight_,
+ next_sent_, kPacketSize, HAS_RETRANSMITTABLE_DATA);
+ // Lose the packet immediately if the buffer is full.
+ if (sent_packets_.size() * kPacketSize < buffer_size_) {
+ // TODO(ianswett): This buffer simulation is an approximation.
+ // An ack time of zero means loss.
+ bool packet_lost =
+ forward_loss_rate_ * kuint64max > simple_random_.RandUint64();
+ // Handle correlated loss.
+ if (!sent_packets_.empty() &&
+ !sent_packets_.back().ack_time.IsInitialized() &&
+ loss_correlation_ * kuint64max > simple_random_.RandUint64()) {
+ packet_lost = true;
+ }
+
+ QuicTime ack_time = clock_->Now().Add(rtt_);
+ // If the number of bytes in flight are less than the bdp, there's
+ // no buffering delay. Bytes lost from the buffer are not counted.
+ QuicByteCount bdp = bandwidth_.ToBytesPerPeriod(rtt_);
+ if (sent_packets_.size() * kPacketSize > bdp) {
+ QuicByteCount qsize = sent_packets_.size() * kPacketSize - bdp;
+ ack_time = ack_time.Add(bandwidth_.TransferTime(qsize));
+ }
+ // If the packet is lost, give it an ack time of Zero.
+ sent_packets_.push_back(SentPacket(
+ next_sent_, clock_->Now(), packet_lost ? QuicTime::Zero() : ack_time));
+ }
+ ++next_sent_;
+ bytes_in_flight_ += kPacketSize;
+}
+
+void SendAlgorithmSimulator::RecordStats() {
+ QuicByteCount cwnd = send_algorithm_->GetCongestionWindow();
+ max_cwnd_ = max(max_cwnd_, cwnd);
+ min_cwnd_ = min(min_cwnd_, cwnd);
+ if (last_cwnd_ > cwnd) {
+ max_cwnd_drop_ = max(max_cwnd_drop_, last_cwnd_ - cwnd);
+ }
+ last_cwnd_ = cwnd;
+}
+
+// Advance the time by |delta| without sending anything.
+void SendAlgorithmSimulator::AdvanceTime(QuicTime::Delta delta) {
+ clock_->AdvanceTime(delta);
+}
+
+// Elapsed time from the start of the connection.
+QuicTime SendAlgorithmSimulator::ElapsedTime() {
+ return clock_->Now();
+}
+
+} // namespace net
diff --git a/net/quic/congestion_control/send_algorithm_simulator.h b/net/quic/congestion_control/send_algorithm_simulator.h
new file mode 100644
index 0000000..e9b80fa
--- /dev/null
+++ b/net/quic/congestion_control/send_algorithm_simulator.h
@@ -0,0 +1,133 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A test only class to enable simulations of send algorithms.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_SIMULATOR_H_
+#define NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_SIMULATOR_H_
+
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "net/quic/congestion_control/send_algorithm_interface.h"
+#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_time.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
+namespace net {
+
+class SendAlgorithmSimulator {
+ public:
+ struct SentPacket {
+ SentPacket(QuicPacketSequenceNumber sequence_number,
+ QuicTime send_time,
+ QuicTime ack_time) :
+ sequence_number(sequence_number),
+ send_time(send_time),
+ ack_time(ack_time) {}
+ QuicPacketSequenceNumber sequence_number;
+ QuicTime send_time;
+ QuicTime ack_time;
+ };
+
+ // |rtt_stats| should be the same RttStats used by the |send_algorithm|.
+ SendAlgorithmSimulator(SendAlgorithmInterface* send_algorithm,
+ MockClock* clock_,
+ RttStats* rtt_stats,
+ QuicBandwidth bandwidth,
+ QuicTime::Delta rtt);
+ ~SendAlgorithmSimulator();
+
+ void set_forward_loss_rate(float loss_rate) {
+ DCHECK_LT(loss_rate, 1.0f);
+ forward_loss_rate_ = loss_rate;
+ }
+
+ void set_reverse_loss_rate(float loss_rate) {
+ DCHECK_LT(loss_rate, 1.0f);
+ reverse_loss_rate_ = loss_rate;
+ }
+
+ void set_loss_correlation(float loss_correlation) {
+ DCHECK_LT(loss_correlation, 1.0f);
+ loss_correlation_ = loss_correlation;
+ }
+
+ void set_buffer_size(size_t buffer_size_bytes) {
+ buffer_size_ = buffer_size_bytes;
+ }
+
+ // Sends the specified number of bytes as quickly as possible and returns the
+ // average bandwidth in bytes per second. The time elapsed is based on
+ // waiting for all acks to arrive.
+ QuicBandwidth SendBytes(size_t num_bytes);
+
+ const RttStats* rtt_stats() const { return rtt_stats_; }
+
+ QuicByteCount max_cwnd() const { return max_cwnd_; }
+ QuicByteCount min_cwnd() const { return min_cwnd_; }
+ QuicByteCount max_cwnd_drop() const { return max_cwnd_drop_; }
+ QuicByteCount last_cwnd() const { return last_cwnd_; }
+
+ private:
+ // NextAckTime takes into account packet loss in both forward and reverse
+ // direction, as well as delayed ack behavior.
+ QuicTime::Delta NextAckDelta();
+
+ // Whether all packets in sent_packets_ are lost.
+ bool AllPacketsLost();
+
+ // Sets the next acked.
+ void FindNextAcked();
+
+ // Process all the acks that should have arrived by the current time, and
+ // lose any packets that are missing. Returns the number of bytes acked.
+ int HandlePendingAck();
+
+ void SendDataNow();
+ void RecordStats();
+
+ // Advance the time by |delta| without sending anything.
+ void AdvanceTime(QuicTime::Delta delta);
+
+ // Elapsed time from the start of the connection.
+ QuicTime ElapsedTime();
+
+ SendAlgorithmInterface* send_algorithm_;
+ MockClock* clock_;
+ RttStats* rtt_stats_;
+ // Next packet sequence number to send.
+ QuicPacketSequenceNumber next_sent_;
+ // Last packet sequence number acked.
+ QuicPacketSequenceNumber last_acked_;
+ // Packet sequence number to ack up to.
+ QuicPacketSequenceNumber next_acked_;
+ // Whether the next ack should be lost.
+ bool lose_next_ack_;
+ QuicByteCount bytes_in_flight_;
+ // The times acks are expected, assuming acks are not lost and every packet
+ // is acked.
+ std::list<SentPacket> sent_packets_;
+
+ test::SimpleRandom simple_random_;
+ float forward_loss_rate_; // Loss rate on the forward path.
+ float reverse_loss_rate_; // Loss rate on the reverse path.
+ float loss_correlation_; // Likelihood the subsequent packet is lost.
+ QuicBandwidth bandwidth_;
+ QuicTime::Delta rtt_;
+ size_t buffer_size_; // In bytes.
+
+ // Stats collected for understanding the congestion control.
+ QuicByteCount max_cwnd_;
+ QuicByteCount min_cwnd_;
+ QuicByteCount max_cwnd_drop_;
+ QuicByteCount last_cwnd_;
+
+ DISALLOW_COPY_AND_ASSIGN(SendAlgorithmSimulator);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_SIMULATOR_H_
diff --git a/net/quic/crypto/channel_id.h b/net/quic/crypto/channel_id.h
index cfa618f..7d29932 100644
--- a/net/quic/crypto/channel_id.h
+++ b/net/quic/crypto/channel_id.h
@@ -18,7 +18,7 @@
// ChannelID key.
class NET_EXPORT_PRIVATE ChannelIDKey {
public:
- virtual ~ChannelIDKey() { }
+ virtual ~ChannelIDKey() {}
// Sign signs |signed_data| using the ChannelID private key and puts the
// signature into |out_signature|. It returns true on success.
diff --git a/net/quic/crypto/crypto_server_test.cc b/net/quic/crypto/crypto_server_test.cc
index f3738ff..f1892d3 100644
--- a/net/quic/crypto/crypto_server_test.cc
+++ b/net/quic/crypto/crypto_server_test.cc
@@ -182,9 +182,8 @@
string error_details;
QuicErrorCode error = config_.ProcessClientHello(
result, 1 /* ConnectionId */, client_address_,
- supported_versions_.front(), supported_versions_,
- kInitialFlowControlWindowForTest, &clock_, rand_, ¶ms_, &out_,
- &error_details);
+ supported_versions_.front(), supported_versions_, &clock_, rand_,
+ ¶ms_, &out_, &error_details);
if (should_succeed) {
ASSERT_EQ(error, QUIC_NO_ERROR)
@@ -523,35 +522,5 @@
EXPECT_EQ(kREJ, out_.tag());
}
-TEST_F(CryptoServerTest, InitialFlowControlWindow) {
- // Test that the SHLO contains a value for initial flow control window.
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex_.c_str(),
- "#004b5453", srct_hex_.c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "VER\0", client_version_.data(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- NULL);
- ShouldSucceed(msg);
- // The message should be rejected because the strike-register is still
- // quiescent.
- ASSERT_EQ(kREJ, out_.tag());
- config_.set_replay_protection(false);
-
- // The message should be accepted now.
- ShouldSucceed(msg);
- ASSERT_EQ(kSHLO, out_.tag());
- CheckServerHello(out_);
-
- // Ensure that the kIFCW tag is populated correctly.
- QuicTag ifcw;
- EXPECT_EQ(QUIC_NO_ERROR, out_.GetUint32(kIFCW, &ifcw));
- EXPECT_EQ(kInitialFlowControlWindowForTest, ifcw);
-}
-
} // namespace test
} // namespace net
diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc
index ae572483..8dc6a554 100644
--- a/net/quic/crypto/quic_crypto_client_config.cc
+++ b/net/quic/crypto/quic_crypto_client_config.cc
@@ -346,7 +346,6 @@
const QuicServerId& server_id,
QuicConnectionId connection_id,
const QuicVersion preferred_version,
- uint32 initial_flow_control_window_bytes,
const CachedState* cached,
QuicWallTime now,
QuicRandom* rand,
@@ -359,9 +358,6 @@
FillInchoateClientHello(server_id, preferred_version, cached,
out_params, out);
- // Set initial receive window for flow control.
- out->SetValue(kIFCW, initial_flow_control_window_bytes);
-
const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
if (!scfg) {
// This should never happen as our caller should have checked
diff --git a/net/quic/crypto/quic_crypto_client_config.h b/net/quic/crypto/quic_crypto_client_config.h
index 14fa0d4..8aa4527 100644
--- a/net/quic/crypto/quic_crypto_client_config.h
+++ b/net/quic/crypto/quic_crypto_client_config.h
@@ -161,9 +161,6 @@
// the server's hostname in order to perform a handshake. This can be checked
// with the |IsComplete| member of |CachedState|.
//
- // |initial_flow_control_window_bytes| is the size of the initial flow
- // control window this client will use for new streams.
- //
// |now| and |rand| are used to generate the nonce and |out_params| is
// filled with the results of the handshake that the server is expected to
// accept. |preferred_version| is the version of the QUIC protocol that this
@@ -176,7 +173,6 @@
QuicErrorCode FillClientHello(const QuicServerId& server_id,
QuicConnectionId connection_id,
const QuicVersion preferred_version,
- uint32 initial_flow_control_window_bytes,
const CachedState* cached,
QuicWallTime now,
QuicRandom* rand,
diff --git a/net/quic/crypto/quic_crypto_client_config_test.cc b/net/quic/crypto/quic_crypto_client_config_test.cc
index 75cf2397..fdce91c 100644
--- a/net/quic/crypto/quic_crypto_client_config_test.cc
+++ b/net/quic/crypto/quic_crypto_client_config_test.cc
@@ -110,7 +110,6 @@
QuicCryptoClientConfig config;
QuicCryptoNegotiatedParameters params;
QuicConnectionId kConnectionId = 1234;
- uint32 kInitialFlowControlWindow = 5678;
string error_details;
MockRandom rand;
CryptoHandshakeMessage chlo;
@@ -118,7 +117,6 @@
config.FillClientHello(server_id,
kConnectionId,
QuicVersionMax(),
- kInitialFlowControlWindow,
&state,
QuicWallTime::Zero(),
&rand,
@@ -131,10 +129,6 @@
QuicTag cver;
EXPECT_EQ(QUIC_NO_ERROR, chlo.GetUint32(kVER, &cver));
EXPECT_EQ(QuicVersionToQuicTag(QuicVersionMax()), cver);
-
- QuicTag ifcw;
- EXPECT_EQ(QUIC_NO_ERROR, chlo.GetUint32(kIFCW, &ifcw));
- EXPECT_EQ(kInitialFlowControlWindow, ifcw);
}
TEST(QuicCryptoClientConfigTest, ProcessServerDowngradeAttack) {
diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc
index 65db0f54..c8114ff 100644
--- a/net/quic/crypto/quic_crypto_server_config.cc
+++ b/net/quic/crypto/quic_crypto_server_config.cc
@@ -490,7 +490,6 @@
IPEndPoint client_address,
QuicVersion version,
const QuicVersionVector& supported_versions,
- uint32 initial_flow_control_window_bytes,
const QuicClock* clock,
QuicRandom* rand,
QuicCryptoNegotiatedParameters *params,
@@ -739,9 +738,6 @@
out->SetStringPiece(kCADR, address_coder.Encode());
out->SetStringPiece(kPUBS, forward_secure_public_value);
- // Set initial receive window for flow control.
- out->SetValue(kIFCW, initial_flow_control_window_bytes);
-
return QUIC_NO_ERROR;
}
diff --git a/net/quic/crypto/quic_crypto_server_config.h b/net/quic/crypto/quic_crypto_server_config.h
index 216dbbf6..566e60d5 100644
--- a/net/quic/crypto/quic_crypto_server_config.h
+++ b/net/quic/crypto/quic_crypto_server_config.h
@@ -204,7 +204,6 @@
IPEndPoint client_address,
QuicVersion version,
const QuicVersionVector& supported_versions,
- uint32 initial_flow_control_window_bytes,
const QuicClock* clock,
QuicRandom* rand,
QuicCryptoNegotiatedParameters* params,
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index 2acaf86..ba95c7a 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -140,12 +140,10 @@
scoped_ptr<QuicServerInfo> server_info,
const QuicServerId& server_id,
const QuicConfig& config,
- uint32 max_flow_control_receive_window_bytes,
QuicCryptoClientConfig* crypto_config,
base::TaskRunner* task_runner,
NetLog* net_log)
: QuicClientSessionBase(connection,
- max_flow_control_receive_window_bytes,
config),
require_confirmation_(false),
stream_factory_(stream_factory),
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index c64e908..7fbe3db 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -98,11 +98,9 @@
scoped_ptr<QuicServerInfo> server_info,
const QuicServerId& server_id,
const QuicConfig& config,
- uint32 max_flow_control_receive_window_bytes,
QuicCryptoClientConfig* crypto_config,
base::TaskRunner* task_runner,
NetLog* net_log);
-
virtual ~QuicClientSession();
void AddObserver(Observer* observer);
diff --git a/net/quic/quic_client_session_base.cc b/net/quic/quic_client_session_base.cc
index f735fac..4343011 100644
--- a/net/quic/quic_client_session_base.cc
+++ b/net/quic/quic_client_session_base.cc
@@ -8,11 +8,8 @@
QuicClientSessionBase::QuicClientSessionBase(
QuicConnection* connection,
- uint32 max_flow_control_receive_window_bytes,
const QuicConfig& config)
- : QuicSession(connection,
- max_flow_control_receive_window_bytes,
- config) {}
+ : QuicSession(connection, config) {}
QuicClientSessionBase::~QuicClientSessionBase() {}
diff --git a/net/quic/quic_client_session_base.h b/net/quic/quic_client_session_base.h
index 007d3ba..eab5d08 100644
--- a/net/quic/quic_client_session_base.h
+++ b/net/quic/quic_client_session_base.h
@@ -14,7 +14,6 @@
class NET_EXPORT_PRIVATE QuicClientSessionBase : public QuicSession {
public:
QuicClientSessionBase(QuicConnection* connection,
- uint32 max_flow_control_receive_window_bytes,
const QuicConfig& config);
virtual ~QuicClientSessionBase();
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index 8706d7c..264fbfa 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -33,8 +33,7 @@
class TestPacketWriter : public QuicDefaultPacketWriter {
public:
- TestPacketWriter(QuicVersion version) : version_(version) {
- }
+ TestPacketWriter(QuicVersion version) : version_(version) {}
// QuicPacketWriter
virtual WriteResult WritePacket(
@@ -72,8 +71,7 @@
make_scoped_ptr((QuicServerInfo*)NULL),
QuicServerId(kServerHostname, kServerPort, false,
PRIVACY_MODE_DISABLED),
- DefaultQuicConfig(), kInitialFlowControlWindowForTest,
- &crypto_config_,
+ DefaultQuicConfig(), &crypto_config_,
base::MessageLoop::current()->message_loop_proxy().get(),
&net_log_) {
session_.config()->SetDefaults();
diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc
index 215c362..f7b82501 100644
--- a/net/quic/quic_config.cc
+++ b/net/quic/quic_config.cc
@@ -537,11 +537,21 @@
}
void QuicConfig::SetInitialFlowControlWindowToSend(uint32 window_bytes) {
+ if (window_bytes < kDefaultFlowControlSendWindow) {
+ LOG(DFATAL) << "Initial flow control receive window (" << window_bytes
+ << ") cannot be set lower than default ("
+ << kDefaultFlowControlSendWindow << ").";
+ window_bytes = kDefaultFlowControlSendWindow;
+ }
initial_flow_control_window_bytes_.SetSendValue(window_bytes);
}
+uint32 QuicConfig::GetInitialFlowControlWindowToSend() const {
+ return initial_flow_control_window_bytes_.GetSendValue();
+}
+
bool QuicConfig::HasReceivedInitialFlowControlWindowBytes() const {
- return initial_flow_control_window_bytes_.HasReceivedValue();;
+ return initial_flow_control_window_bytes_.HasReceivedValue();
}
uint32 QuicConfig::ReceivedInitialFlowControlWindowBytes() const {
@@ -573,6 +583,8 @@
kDefaultMaxStreamsPerConnection);
max_time_before_crypto_handshake_ = QuicTime::Delta::FromSeconds(
kDefaultMaxTimeForCryptoHandshakeSecs);
+
+ SetInitialFlowControlWindowToSend(kDefaultFlowControlSendWindow);
}
void QuicConfig::EnablePacing(bool enable_pacing) {
diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h
index 4d65097..ba681fc0 100644
--- a/net/quic/quic_config.h
+++ b/net/quic/quic_config.h
@@ -310,6 +310,8 @@
// Sets an initial flow control window size to transmit to the peer.
void SetInitialFlowControlWindowToSend(uint32 window_bytes);
+ uint32 GetInitialFlowControlWindowToSend() const;
+
bool HasReceivedInitialFlowControlWindowBytes() const;
uint32 ReceivedInitialFlowControlWindowBytes() const;
diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc
index 63299e5b0..f77c382 100644
--- a/net/quic/quic_config_test.cc
+++ b/net/quic/quic_config_test.cc
@@ -12,6 +12,7 @@
#include "net/quic/quic_time.h"
#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
#include "testing/gtest/include/gtest/gtest.h"
using std::string;
@@ -32,6 +33,7 @@
TEST_F(QuicConfigTest, ToHandshakeMessage) {
ValueRestore<bool> old_flag(&FLAGS_enable_quic_pacing, false);
config_.SetDefaults();
+ config_.SetInitialFlowControlWindowToSend(kInitialFlowControlWindowForTest);
config_.set_idle_connection_state_lifetime(QuicTime::Delta::FromSeconds(5),
QuicTime::Delta::FromSeconds(2));
config_.set_max_streams_per_connection(4, 2);
@@ -47,6 +49,10 @@
EXPECT_EQ(QUIC_NO_ERROR, error);
EXPECT_EQ(4u, value);
+ error = msg.GetUint32(kIFCW, &value);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_EQ(kInitialFlowControlWindowForTest, value);
+
const QuicTag* out;
size_t out_len;
error = msg.GetTaglist(kCGST, &out, &out_len);
@@ -82,6 +88,8 @@
2 * kDefaultMaxStreamsPerConnection, kDefaultMaxStreamsPerConnection);
client_config.SetInitialRoundTripTimeUsToSend(
10 * base::Time::kMicrosecondsPerMillisecond);
+ client_config.SetInitialFlowControlWindowToSend(
+ 2 * kInitialFlowControlWindowForTest);
QuicTagVector copt;
copt.push_back(kTBBR);
client_config.SetCongestionOptionsToSend(copt);
@@ -104,6 +112,8 @@
EXPECT_TRUE(config_.HasReceivedCongestionOptions());
EXPECT_EQ(1u, config_.ReceivedCongestionOptions().size());
EXPECT_EQ(config_.ReceivedCongestionOptions()[0], kTBBR);
+ EXPECT_EQ(config_.ReceivedInitialFlowControlWindowBytes(),
+ 2 * kInitialFlowControlWindowForTest);
}
TEST_F(QuicConfigTest, ProcessServerHello) {
@@ -120,6 +130,8 @@
server_config.SetInitialCongestionWindowToSend(kDefaultInitialWindow / 2);
server_config.SetInitialRoundTripTimeUsToSend(
10 * base::Time::kMicrosecondsPerMillisecond);
+ server_config.SetInitialFlowControlWindowToSend(
+ 2 * kInitialFlowControlWindowForTest);
CryptoHandshakeMessage msg;
server_config.ToHandshakeMessage(&msg);
string error_details;
@@ -138,6 +150,8 @@
EXPECT_EQ(10 * base::Time::kMicrosecondsPerMillisecond,
config_.ReceivedInitialRoundTripTimeUs());
EXPECT_FALSE(config_.HasReceivedLossDetection());
+ EXPECT_EQ(config_.ReceivedInitialFlowControlWindowBytes(),
+ 2 * kInitialFlowControlWindowForTest);
}
TEST_F(QuicConfigTest, MissingOptionalValuesInCHLO) {
@@ -243,6 +257,18 @@
EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP, error);
}
+TEST_F(QuicConfigTest, InvalidFlowControlWindow) {
+ // QuicConfig should not accept an invalid flow control window to send to the
+ // peer: the receive window must be at least the default of 16 Kb.
+ QuicConfig config;
+ const uint64 kInvalidWindow = kDefaultFlowControlSendWindow - 1;
+ EXPECT_DFATAL(config.SetInitialFlowControlWindowToSend(kInvalidWindow),
+ "Initial flow control receive window");
+
+ EXPECT_EQ(kDefaultFlowControlSendWindow,
+ config.GetInitialFlowControlWindowToSend());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 9cb1f7e..3993637 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -185,7 +185,6 @@
server_id_,
session()->connection()->connection_id(),
session()->connection()->supported_versions().front(),
- session()->max_flow_control_receive_window_bytes(),
cached,
session()->connection()->clock()->WallNow(),
session()->connection()->random_generator(),
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index 62b77953..7bd2c03 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -173,7 +173,6 @@
session()->connection()->peer_address(),
session()->connection()->version(),
session()->connection()->supported_versions(),
- session()->max_flow_control_receive_window_bytes(),
session()->connection()->clock(),
session()->connection()->random_generator(),
&crypto_negotiated_params_, reply, error_details);
diff --git a/net/quic/quic_dispatcher.cc b/net/quic/quic_dispatcher.cc
index d1fe193..2d35df3 100644
--- a/net/quic/quic_dispatcher.cc
+++ b/net/quic/quic_dispatcher.cc
@@ -157,8 +157,7 @@
QuicDispatcher::QuicDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
const QuicVersionVector& supported_versions,
- QuicConnectionHelperInterface* helper,
- uint32 initial_flow_control_window_bytes)
+ QuicConnectionHelperInterface* helper)
: config_(config),
crypto_config_(crypto_config),
helper_(helper),
@@ -169,8 +168,7 @@
supported_versions_no_connection_flow_control_(supported_versions),
current_packet_(NULL),
framer_(supported_versions, /*unused*/ QuicTime::Zero(), true),
- framer_visitor_(new QuicFramerVisitor(this)),
- initial_flow_control_window_bytes_(initial_flow_control_window_bytes) {
+ framer_visitor_(new QuicFramerVisitor(this)) {
framer_.set_visitor(framer_visitor_.get());
}
@@ -371,7 +369,6 @@
QuicServerSession* session = new QuicServerSession(
config_,
CreateQuicConnection(connection_id, server_address, client_address),
- initial_flow_control_window_bytes_,
this);
session->InitializeSession(crypto_config_);
return session;
diff --git a/net/quic/quic_dispatcher.h b/net/quic/quic_dispatcher.h
index 423afe6..fa20bcc2d 100644
--- a/net/quic/quic_dispatcher.h
+++ b/net/quic/quic_dispatcher.h
@@ -57,8 +57,7 @@
QuicDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
const QuicVersionVector& supported_versions,
- QuicConnectionHelperInterface* helper,
- uint32 initial_flow_control_window_bytes);
+ QuicConnectionHelperInterface* helper);
virtual ~QuicDispatcher();
@@ -157,10 +156,6 @@
QuicPacketWriter* writer() { return writer_.get(); }
- uint32 initial_flow_control_window_bytes() const {
- return initial_flow_control_window_bytes_;
- }
-
private:
class QuicFramerVisitor;
friend class net::test::QuicDispatcherPeer;
@@ -227,10 +222,6 @@
QuicFramer framer_;
scoped_ptr<QuicFramerVisitor> framer_visitor_;
- // Initial flow control window size to advertize to peer on newly created
- // connections.
- const uint32 initial_flow_control_window_bytes_;
-
DISALLOW_COPY_AND_ASSIGN(QuicDispatcher);
};
diff --git a/net/quic/quic_end_to_end_unittest.cc b/net/quic/quic_end_to_end_unittest.cc
index 4777d8ae..e7e2769 100644
--- a/net/quic/quic_end_to_end_unittest.cc
+++ b/net/quic/quic_end_to_end_unittest.cc
@@ -23,6 +23,7 @@
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/ssl/ssl_config_service_defaults.h"
#include "net/tools/quic/quic_in_memory_cache.h"
+#include "net/tools/quic/quic_server.h"
#include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h"
#include "net/tools/quic/test_tools/server_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,6 +31,7 @@
using base::StringPiece;
using net::tools::QuicInMemoryCache;
+using net::tools::QuicServer;
using net::tools::test::QuicInMemoryCachePeer;
using net::tools::test::ServerThread;
@@ -133,10 +135,12 @@
CHECK(net::ParseIPLiteralToNumber("127.0.0.1", &ip));
server_address_ = IPEndPoint(ip, 0);
server_config_.SetDefaults();
- server_thread_.reset(new ServerThread(server_address_, server_config_,
- QuicSupportedVersions(),
- strike_register_no_startup_period_,
- kInitialFlowControlWindowForTest));
+ server_config_.SetInitialFlowControlWindowToSend(
+ kInitialFlowControlWindowForTest);
+ server_thread_.reset(new ServerThread(
+ new QuicServer(server_config_, QuicSupportedVersions()),
+ server_address_,
+ strike_register_no_startup_period_));
server_thread_->Initialize();
server_address_ = IPEndPoint(server_address_.address(),
server_thread_->GetPort());
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index e44bd2d..fd077bc2 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -323,9 +323,9 @@
return frame_len;
}
-QuicFramer::AckFrameInfo::AckFrameInfo() : max_delta(0) { }
+QuicFramer::AckFrameInfo::AckFrameInfo() : max_delta(0) {}
-QuicFramer::AckFrameInfo::~AckFrameInfo() { }
+QuicFramer::AckFrameInfo::~AckFrameInfo() {}
QuicPacketEntropyHash QuicFramer::GetPacketEntropyHash(
const QuicPacketHeader& header) const {
diff --git a/net/quic/quic_headers_stream.cc b/net/quic/quic_headers_stream.cc
index aab85715..c158e0850 100644
--- a/net/quic/quic_headers_stream.cc
+++ b/net/quic/quic_headers_stream.cc
@@ -174,6 +174,7 @@
spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
spdy_framer_.set_visitor(spdy_framer_visitor_.get());
spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
+ // TODO(jri): Set headers to be always FEC protected.
DisableFlowControl();
}
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 66261d4..8fafdd51 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -212,8 +212,7 @@
make_scoped_ptr((QuicServerInfo*)NULL),
QuicServerId(kServerHostname, kServerPort,
false, PRIVACY_MODE_DISABLED),
- DefaultQuicConfig(),
- kInitialFlowControlWindowForTest, &crypto_config_,
+ DefaultQuicConfig(), &crypto_config_,
base::MessageLoop::current()->
message_loop_proxy().get(),
NULL));
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index cd73694..9ad7798 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -753,7 +753,7 @@
nack_count(0),
transmission_type(NOT_RETRANSMISSION),
all_transmissions(NULL),
- in_flight(false) { }
+ in_flight(false) {}
TransmissionInfo::TransmissionInfo(
RetransmittableFrames* retransmittable_frames,
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 23bdd3e1..eed756b 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -158,7 +158,13 @@
// Indicates FEC protection level for data being written.
enum FecProtection {
MUST_FEC_PROTECT, // Callee must FEC protect this data.
- MAY_FEC_PROTECT // Callee does not have to but may FEC protect this data.
+ MAY_FEC_PROTECT // Callee does not have to but may FEC protect this data.
+};
+
+// Indicates FEC policy
+enum FecPolicy {
+ FEC_PROTECT_ALWAYS, // All data in the stream should be FEC protected.
+ FEC_PROTECT_OPTIONAL // Data in the stream does not need FEC protection.
};
enum QuicFrameType {
diff --git a/net/quic/quic_received_packet_manager_test.cc b/net/quic/quic_received_packet_manager_test.cc
index 30c84c5f..b579309 100644
--- a/net/quic/quic_received_packet_manager_test.cc
+++ b/net/quic/quic_received_packet_manager_test.cc
@@ -186,7 +186,7 @@
class QuicReceivedPacketManagerTest : public ::testing::Test {
protected:
- QuicReceivedPacketManagerTest() : received_manager_(kTCP, &stats_) { }
+ QuicReceivedPacketManagerTest() : received_manager_(kTCP, &stats_) {}
void RecordPacketReceipt(QuicPacketSequenceNumber sequence_number,
QuicPacketEntropyHash entropy_hash) {
diff --git a/net/quic/quic_server_session.cc b/net/quic/quic_server_session.cc
index 3944acd..1de91a4 100644
--- a/net/quic/quic_server_session.cc
+++ b/net/quic/quic_server_session.cc
@@ -13,9 +13,8 @@
QuicServerSession::QuicServerSession(const QuicConfig& config,
QuicConnection* connection,
- uint32 max_flow_control_window_bytes,
QuicServerSessionVisitor* visitor)
- : QuicSession(connection, max_flow_control_window_bytes, config),
+ : QuicSession(connection, config),
visitor_(visitor) {}
QuicServerSession::~QuicServerSession() {}
diff --git a/net/quic/quic_server_session.h b/net/quic/quic_server_session.h
index b413098..30ac08c8 100644
--- a/net/quic/quic_server_session.h
+++ b/net/quic/quic_server_session.h
@@ -45,7 +45,6 @@
public:
QuicServerSession(const QuicConfig& config,
QuicConnection* connection,
- uint32 max_flow_control_window_bytes,
QuicServerSessionVisitor* visitor);
// Override the base class to notify the owner of the connection close.
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 8a2f8b4..f16434d 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -95,9 +95,7 @@
QuicSession* session_;
};
-QuicSession::QuicSession(QuicConnection* connection,
- uint32 max_flow_control_receive_window_bytes,
- const QuicConfig& config)
+QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config)
: connection_(connection),
visitor_shim_(new VisitorShim(this)),
config_(config),
@@ -107,20 +105,11 @@
error_(QUIC_NO_ERROR),
goaway_received_(false),
goaway_sent_(false),
- has_pending_handshake_(false),
- max_flow_control_receive_window_bytes_(
- max_flow_control_receive_window_bytes) {
- if (max_flow_control_receive_window_bytes_ < kDefaultFlowControlSendWindow) {
- LOG(ERROR) << "Initial receive window ("
- << max_flow_control_receive_window_bytes_
- << ") cannot be set lower than default ("
- << kDefaultFlowControlSendWindow << ").";
- max_flow_control_receive_window_bytes_ = kDefaultFlowControlSendWindow;
- }
+ has_pending_handshake_(false) {
flow_controller_.reset(new QuicFlowController(
connection_.get(), 0, is_server(), kDefaultFlowControlSendWindow,
- max_flow_control_receive_window_bytes_,
- max_flow_control_receive_window_bytes_));
+ config_.GetInitialFlowControlWindowToSend(),
+ config_.GetInitialFlowControlWindowToSend()));
connection_->set_visitor(visitor_shim_.get());
connection_->SetFromConfig(config_);
@@ -477,28 +466,43 @@
config_.HasReceivedInitialFlowControlWindowBytes()) {
// Streams which were created before the SHLO was received (0RTT requests)
// are now informed of the peer's initial flow control window.
- uint32 new_flow_control_send_window =
- config_.ReceivedInitialFlowControlWindowBytes();
- if (new_flow_control_send_window < kDefaultFlowControlSendWindow) {
- LOG(ERROR)
- << "Peer sent us an invalid flow control send window: "
- << new_flow_control_send_window
- << ", below default: " << kDefaultFlowControlSendWindow;
- connection_->SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW);
- return;
- }
- DataStreamMap::iterator it = stream_map_.begin();
- while (it != stream_map_.end()) {
- it->second->flow_controller()->UpdateSendWindowOffset(
- new_flow_control_send_window);
- it++;
- }
-
- // Update connection level window.
- flow_controller_->UpdateSendWindowOffset(new_flow_control_send_window);
+ uint32 new_window = config_.ReceivedInitialFlowControlWindowBytes();
+ OnNewStreamFlowControlWindow(new_window);
+ OnNewSessionFlowControlWindow(new_window);
}
}
+void QuicSession::OnNewStreamFlowControlWindow(uint32 new_window) {
+ if (new_window < kDefaultFlowControlSendWindow) {
+ LOG(ERROR)
+ << "Peer sent us an invalid stream flow control send window: "
+ << new_window << ", below default: " << kDefaultFlowControlSendWindow;
+ if (connection_->connected()) {
+ connection_->SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW);
+ }
+ return;
+ }
+
+ for (DataStreamMap::iterator it = stream_map_.begin();
+ it != stream_map_.end(); ++it) {
+ it->second->flow_controller()->UpdateSendWindowOffset(new_window);
+ }
+}
+
+void QuicSession::OnNewSessionFlowControlWindow(uint32 new_window) {
+ if (new_window < kDefaultFlowControlSendWindow) {
+ LOG(ERROR)
+ << "Peer sent us an invalid session flow control send window: "
+ << new_window << ", below default: " << kDefaultFlowControlSendWindow;
+ if (connection_->connected()) {
+ connection_->SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW);
+ }
+ return;
+ }
+
+ flow_controller_->UpdateSendWindowOffset(new_window);
+}
+
void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
switch (event) {
// TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 4cc3215..1b312800 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -53,9 +53,7 @@
HANDSHAKE_CONFIRMED,
};
- QuicSession(QuicConnection* connection,
- uint32 max_flow_control_receive_window_bytes,
- const QuicConfig& config);
+ QuicSession(QuicConnection* connection, const QuicConfig& config);
virtual ~QuicSession();
@@ -205,10 +203,6 @@
bool is_server() const { return connection_->is_server(); }
- uint32 max_flow_control_receive_window_bytes() {
- return max_flow_control_receive_window_bytes_;
- }
-
QuicFlowController* flow_controller() { return flow_controller_.get(); }
protected:
@@ -273,6 +267,14 @@
void UpdateFlowControlOnFinalReceivedByteOffset(
QuicStreamId id, QuicStreamOffset final_byte_offset);
+ // Called in OnConfigNegotiated when we receive a new stream level flow
+ // control window in a negotiated config. Closes the connection if invalid.
+ void OnNewStreamFlowControlWindow(uint32 new_window);
+
+ // Called in OnConfigNegotiated when we receive a new session level flow
+ // control window in a negotiated config. Closes the connection if invalid.
+ void OnNewSessionFlowControlWindow(uint32 new_window);
+
// Keep track of highest received byte offset of locally closed streams, while
// waiting for a definitive final highest offset from the peer.
std::map<QuicStreamId, QuicStreamOffset>
@@ -320,9 +322,6 @@
// Used for session level flow control.
scoped_ptr<QuicFlowController> flow_controller_;
- // Initial flow control receive window size for new streams.
- uint32 max_flow_control_receive_window_bytes_;
-
DISALLOW_COPY_AND_ASSIGN(QuicSession);
};
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index d5468e7f..b3250a7 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -15,6 +15,7 @@
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_utils.h"
#include "net/quic/reliable_quic_stream.h"
+#include "net/quic/test_tools/quic_config_peer.h"
#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_data_stream_peer.h"
#include "net/quic/test_tools/quic_flow_controller_peer.h"
@@ -116,9 +117,8 @@
class TestSession : public QuicSession {
public:
- TestSession(QuicConnection* connection,
- uint32 max_initial_flow_control_window)
- : QuicSession(connection, max_initial_flow_control_window,
+ explicit TestSession(QuicConnection* connection)
+ : QuicSession(connection,
DefaultQuicConfig()),
crypto_stream_(this),
writev_consumes_all_data_(false) {}
@@ -181,7 +181,9 @@
protected:
QuicSessionTest()
: connection_(new MockConnection(true, SupportedVersions(GetParam()))),
- session_(connection_, kInitialFlowControlWindowForTest) {
+ session_(connection_) {
+ session_.config()->SetInitialFlowControlWindowToSend(
+ kInitialFlowControlWindowForTest);
headers_[":host"] = "www.google.com";
headers_[":path"] = "/index.hml";
headers_[":scheme"] = "http";
@@ -515,11 +517,11 @@
}
TEST_P(QuicSessionTest, OnCanWriteLimitsNumWritesIfFlowControlBlocked) {
- ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control, true);
if (version() < QUIC_VERSION_19) {
return;
}
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control, true);
// Ensure connection level flow control blockage.
QuicFlowControllerPeer::SetSendWindowOffset(session_.flow_controller(), 0);
EXPECT_TRUE(session_.flow_controller()->IsBlocked());
@@ -654,41 +656,21 @@
ValueRestore<bool> old_flag(&FLAGS_enable_quic_stream_flow_control_2, true);
uint32 kInvalidWindow = kDefaultFlowControlSendWindow - 1;
-
- CryptoHandshakeMessage msg;
- string error_details;
- session_.config()->SetInitialFlowControlWindowToSend(kInvalidWindow);
- session_.config()->ToHandshakeMessage(&msg);
- const QuicErrorCode error =
- session_.config()->ProcessPeerHello(msg, CLIENT, &error_details);
- EXPECT_EQ(QUIC_NO_ERROR, error);
+ QuicConfigPeer::SetReceivedInitialFlowControlWindow(session_.config(),
+ kInvalidWindow);
EXPECT_CALL(*connection_,
- SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW));
+ SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW)).Times(2);
session_.OnConfigNegotiated();
}
-
-TEST_P(QuicSessionTest, InvalidFlowControlWindow) {
- // Test that an attempt to create a QuicSession with an invalid (< default)
- // flow control window results in a QuicSession using the default.
- QuicConnection* connection =
- new MockConnection(true, SupportedVersions(GetParam()));
-
- const uint32 kSmallerFlowControlWindow = kDefaultFlowControlSendWindow - 1;
- TestSession session(connection, kSmallerFlowControlWindow);
-
- EXPECT_EQ(kDefaultFlowControlSendWindow,
- session.max_flow_control_receive_window_bytes());
-}
-
TEST_P(QuicSessionTest, ConnectionFlowControlAccountingRstOutOfOrder) {
- FLAGS_enable_quic_stream_flow_control_2 = true;
- FLAGS_enable_quic_connection_flow_control = true;
if (version() < QUIC_VERSION_19) {
return;
}
+ ValueRestore<bool> old_flag2(&FLAGS_enable_quic_stream_flow_control_2, true);
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control, true);
// Test that when we receive an out of order stream RST we correctly adjust
// our connection level flow control receive window.
// On close, the stream should mark as consumed all bytes between the highest
@@ -711,12 +693,12 @@
}
TEST_P(QuicSessionTest, ConnectionFlowControlAccountingFinAndLocalReset) {
- FLAGS_enable_quic_stream_flow_control_2 = true;
- FLAGS_enable_quic_connection_flow_control = true;
if (version() < QUIC_VERSION_19) {
return;
}
+ ValueRestore<bool> old_flag2(&FLAGS_enable_quic_stream_flow_control_2, true);
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control, true);
// Test the situation where we receive a FIN on a stream, and before we fully
// consume all the data from the sequencer buffer we locally RST the stream.
// The bytes between highest consumed byte, and the final byte offset that we
@@ -752,11 +734,12 @@
// Test that when we RST the stream (and tear down stream state), and then
// receive a FIN from the peer, we correctly adjust our connection level flow
// control receive window.
- FLAGS_enable_quic_connection_flow_control = true;
if (version() < QUIC_VERSION_19) {
return;
}
+ ValueRestore<bool> old_flag2(&FLAGS_enable_quic_stream_flow_control_2, true);
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control, true);
// Connection starts with some non-zero highest received byte offset,
// due to other active streams.
const uint64 kInitialConnectionBytesConsumed = 567;
@@ -795,11 +778,12 @@
// Test that when we RST the stream (and tear down stream state), and then
// receive a RST from the peer, we correctly adjust our connection level flow
// control receive window.
- FLAGS_enable_quic_connection_flow_control = true;
if (version() < QUIC_VERSION_19) {
return;
}
+ ValueRestore<bool> old_flag2(&FLAGS_enable_quic_stream_flow_control_2, true);
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control, true);
// Connection starts with some non-zero highest received byte offset,
// due to other active streams.
const uint64 kInitialConnectionBytesConsumed = 567;
@@ -834,8 +818,8 @@
if (version() < QUIC_VERSION_17) {
return;
}
- FLAGS_enable_quic_stream_flow_control_2 = true;
- FLAGS_enable_quic_connection_flow_control = true;
+ ValueRestore<bool> old_flag2(&FLAGS_enable_quic_stream_flow_control_2, true);
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control, true);
const uint64 kLargeOffset = kInitialFlowControlWindowForTest + 1;
EXPECT_CALL(*connection_,
@@ -857,14 +841,12 @@
}
TEST_P(QuicSessionTest, VersionNegotiationDisablesFlowControl) {
- ValueRestore<bool> old_stream_flag(
- &FLAGS_enable_quic_stream_flow_control_2, true);
- ValueRestore<bool> old_connection_flag(
- &FLAGS_enable_quic_connection_flow_control, true);
if (version() < QUIC_VERSION_19) {
return;
}
+ ValueRestore<bool> old_flag2(&FLAGS_enable_quic_stream_flow_control_2, true);
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control, true);
// Test that after successful version negotiation, flow control is disabled
// appropriately at both the connection and stream level.
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 9acedcb..dd17924 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -834,6 +834,7 @@
config.SetInitialCongestionWindowToSend(
server_id.is_https() ? kServerSecureInitialCongestionWindow
: kServerInecureInitialCongestionWindow);
+ config.SetInitialFlowControlWindowToSend(kInitialReceiveWindowSize);
if (http_server_properties_) {
const HttpServerProperties::NetworkStats* stats =
http_server_properties_->GetServerNetworkStats(
@@ -846,7 +847,7 @@
*session = new QuicClientSession(
connection, socket.Pass(), writer.Pass(), this,
quic_crypto_client_stream_factory_, server_info.Pass(), server_id,
- config, kInitialReceiveWindowSize, &crypto_config_,
+ config, &crypto_config_,
base::MessageLoop::current()->message_loop_proxy().get(),
net_log.net_log());
all_sessions_[*session] = server_id; // owning pointer
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index 32ef6d3..a98e22d 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -124,6 +124,7 @@
fin_received_(false),
rst_sent_(false),
rst_received_(false),
+ fec_policy_(FEC_PROTECT_OPTIONAL),
is_server_(session_->is_server()),
flow_controller_(
session_->connection(),
@@ -132,8 +133,8 @@
session_->config()->HasReceivedInitialFlowControlWindowBytes() ?
session_->config()->ReceivedInitialFlowControlWindowBytes() :
kDefaultFlowControlSendWindow,
- session_->max_flow_control_receive_window_bytes(),
- session_->max_flow_control_receive_window_bytes()),
+ session_->config()->GetInitialFlowControlWindowToSend(),
+ session_->config()->GetInitialFlowControlWindowToSend()),
connection_flow_controller_(session_->flow_controller()) {
}
@@ -360,9 +361,8 @@
IOVector data;
data.AppendIovecAtMostBytes(iov, iov_count, write_length);
- // TODO(jri): Use the correct FecProtection based on FecPolicy on stream.
QuicConsumedData consumed_data = session()->WritevData(
- id(), data, stream_bytes_written_, fin, MAY_FEC_PROTECT,
+ id(), data, stream_bytes_written_, fin, GetFecProtection(),
ack_notifier_delegate);
stream_bytes_written_ += consumed_data.bytes_consumed;
@@ -384,6 +384,10 @@
return consumed_data;
}
+FecProtection ReliableQuicStream::GetFecProtection() {
+ return fec_policy_ == FEC_PROTECT_ALWAYS ? MUST_FEC_PROTECT : MAY_FEC_PROTECT;
+}
+
void ReliableQuicStream::CloseReadSide() {
if (read_side_closed_) {
return;
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 0774c93b..be89a284 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -140,6 +140,9 @@
bool fin,
QuicAckNotifier::DelegateInterface* ack_notifier_delegate);
+ // Helper method that returns FecProtection to use for writes to the session.
+ FecProtection GetFecProtection();
+
// Close the read side of the socket. Further frames will not be accepted.
virtual void CloseReadSide();
@@ -150,6 +153,8 @@
bool fin_buffered() const { return fin_buffered_; }
+ void set_fec_policy(FecPolicy fec_policy) { fec_policy_ = fec_policy; }
+
const QuicSession* session() const { return session_; }
QuicSession* session() { return session_; }
@@ -218,6 +223,9 @@
// True if this stream has received a RST stream frame.
bool rst_received_;
+ // FEC policy to be used for this stream.
+ FecPolicy fec_policy_;
+
// True if the session this stream is running under is a server session.
bool is_server_;
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index df8e6301..13f9c7d 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -239,6 +239,78 @@
stream_->OnCanWrite();
}
+TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithFecProtectAlways) {
+ Initialize(kShouldProcessData);
+
+ // Set FEC policy on stream.
+ ReliableQuicStreamPeer::SetFecPolicy(stream_.get(), FEC_PROTECT_ALWAYS);
+
+ EXPECT_FALSE(HasWriteBlockedStreams());
+ size_t length = 1 + QuicPacketCreator::StreamFramePacketOverhead(
+ connection_->version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, 0u, IN_FEC_GROUP);
+ QuicConnectionPeer::GetPacketCreator(connection_)->set_max_packet_length(
+ length);
+
+ // Write first data onto stream, which will cause one session write.
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, MUST_FEC_PROTECT, _)).WillOnce(
+ Return(QuicConsumedData(kDataLen - 1, false)));
+ stream_->WriteOrBufferData(kData1, false, NULL);
+ EXPECT_TRUE(HasWriteBlockedStreams());
+
+ // Queue a bytes_consumed write.
+ stream_->WriteOrBufferData(kData2, false, NULL);
+
+ // Make sure we get the tail of the first write followed by the bytes_consumed
+ InSequence s;
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, MUST_FEC_PROTECT, _)).
+ WillOnce(Return(QuicConsumedData(1, false)));
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, MUST_FEC_PROTECT, _)).
+ WillOnce(Return(QuicConsumedData(kDataLen - 2, false)));
+ stream_->OnCanWrite();
+
+ // And finally the end of the bytes_consumed.
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, MUST_FEC_PROTECT, _)).
+ WillOnce(Return(QuicConsumedData(2, true)));
+ stream_->OnCanWrite();
+}
+
+TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithFecProtectOptional) {
+ Initialize(kShouldProcessData);
+
+ // Set FEC policy on stream.
+ ReliableQuicStreamPeer::SetFecPolicy(stream_.get(), FEC_PROTECT_OPTIONAL);
+
+ EXPECT_FALSE(HasWriteBlockedStreams());
+ size_t length = 1 + QuicPacketCreator::StreamFramePacketOverhead(
+ connection_->version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, 0u, NOT_IN_FEC_GROUP);
+ QuicConnectionPeer::GetPacketCreator(connection_)->set_max_packet_length(
+ length);
+
+ // Write first data onto stream, which will cause one session write.
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, MAY_FEC_PROTECT, _)).WillOnce(
+ Return(QuicConsumedData(kDataLen - 1, false)));
+ stream_->WriteOrBufferData(kData1, false, NULL);
+ EXPECT_TRUE(HasWriteBlockedStreams());
+
+ // Queue a bytes_consumed write.
+ stream_->WriteOrBufferData(kData2, false, NULL);
+
+ // Make sure we get the tail of the first write followed by the bytes_consumed
+ InSequence s;
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, MAY_FEC_PROTECT, _)).
+ WillOnce(Return(QuicConsumedData(1, false)));
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, MAY_FEC_PROTECT, _)).
+ WillOnce(Return(QuicConsumedData(kDataLen - 2, false)));
+ stream_->OnCanWrite();
+
+ // And finally the end of the bytes_consumed.
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, MAY_FEC_PROTECT, _)).
+ WillOnce(Return(QuicConsumedData(2, true)));
+ stream_->OnCanWrite();
+}
+
TEST_F(ReliableQuicStreamTest, ConnectionCloseAfterStreamClose) {
Initialize(kShouldProcessData);
diff --git a/net/quic/test_tools/crypto_test_utils_chromium.cc b/net/quic/test_tools/crypto_test_utils_chromium.cc
index eb4fec03..9deee83 100644
--- a/net/quic/test_tools/crypto_test_utils_chromium.cc
+++ b/net/quic/test_tools/crypto_test_utils_chromium.cc
@@ -29,7 +29,7 @@
ImportCertFromFile(GetTestCertsDirectory(), cert_file);
scoped_root_.Reset(root_cert.get());
}
- virtual ~TestProofVerifierChromium() { }
+ virtual ~TestProofVerifierChromium() {}
private:
ScopedTestRoot scoped_root_;
diff --git a/net/quic/test_tools/mock_quic_dispatcher.cc b/net/quic/test_tools/mock_quic_dispatcher.cc
index 73a14e9..82c9dbf 100644
--- a/net/quic/test_tools/mock_quic_dispatcher.cc
+++ b/net/quic/test_tools/mock_quic_dispatcher.cc
@@ -15,11 +15,7 @@
const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
QuicConnectionHelperInterface* helper)
- : QuicDispatcher(config,
- crypto_config,
- QuicSupportedVersions(),
- helper,
- kInitialFlowControlWindowForTest) {
+ : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), helper) {
}
MockQuicDispatcher::~MockQuicDispatcher() {
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 727c544..e61cc30a 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -4,6 +4,7 @@
#include "net/quic/test_tools/quic_test_utils.h"
+#include "base/sha1.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "net/quic/crypto/crypto_framer.h"
@@ -82,6 +83,14 @@
return framer->BuildDataPacket(header, frames, packet_size);
}
+uint64 SimpleRandom::RandUint64() {
+ unsigned char hash[base::kSHA1Length];
+ base::SHA1HashBytes(reinterpret_cast<unsigned char*>(&seed_), sizeof(seed_),
+ hash);
+ memcpy(&seed_, hash, sizeof(seed_));
+ return seed_;
+}
+
MockFramerVisitor::MockFramerVisitor() {
// By default, we want to accept packets.
ON_CALL(*this, OnProtocolVersionMismatch(_))
@@ -292,8 +301,7 @@
}
MockSession::MockSession(QuicConnection* connection)
- : QuicSession(connection, kInitialFlowControlWindowForTest,
- DefaultQuicConfig()) {
+ : QuicSession(connection, DefaultQuicConfig()) {
ON_CALL(*this, WritevData(_, _, _, _, _, _))
.WillByDefault(testing::Return(QuicConsumedData(0, false)));
}
@@ -302,7 +310,7 @@
}
TestSession::TestSession(QuicConnection* connection, const QuicConfig& config)
- : QuicSession(connection, kInitialFlowControlWindowForTest, config),
+ : QuicSession(connection, config),
crypto_stream_(NULL) {}
TestSession::~TestSession() {}
@@ -317,7 +325,7 @@
TestClientSession::TestClientSession(QuicConnection* connection,
const QuicConfig& config)
- : QuicClientSessionBase(connection, kInitialFlowControlWindowForTest,
+ : QuicClientSessionBase(connection,
config),
crypto_stream_(NULL) {
EXPECT_CALL(*this, OnProofValid(_)).Times(AnyNumber());
@@ -562,22 +570,23 @@
sequence_number_length, 0u, is_in_fec_group);
}
-TestEntropyCalculator::TestEntropyCalculator() { }
+TestEntropyCalculator::TestEntropyCalculator() {}
-TestEntropyCalculator::~TestEntropyCalculator() { }
+TestEntropyCalculator::~TestEntropyCalculator() {}
QuicPacketEntropyHash TestEntropyCalculator::EntropyHash(
QuicPacketSequenceNumber sequence_number) const {
return 1u;
}
-MockEntropyCalculator::MockEntropyCalculator() { }
+MockEntropyCalculator::MockEntropyCalculator() {}
-MockEntropyCalculator::~MockEntropyCalculator() { }
+MockEntropyCalculator::~MockEntropyCalculator() {}
QuicConfig DefaultQuicConfig() {
QuicConfig config;
config.SetDefaults();
+ config.SetInitialFlowControlWindowToSend(kInitialFlowControlWindowForTest);
return config;
}
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 4c6fcf1..6d1de91 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -122,6 +122,25 @@
DISALLOW_COPY_AND_ASSIGN(ValueRestore);
};
+// Simple random number generator used to compute random numbers suitable
+// for pseudo-randomly dropping packets in tests. It works by computing
+// the sha1 hash of the current seed, and using the first 64 bits as
+// the next random number, and the next seed.
+class SimpleRandom {
+ public:
+ SimpleRandom() : seed_(0) {}
+
+ // Returns a random number in the range [0, kuint64max].
+ uint64 RandUint64();
+
+ void set_seed(uint64 seed) { seed_ = seed; }
+
+ private:
+ uint64 seed_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleRandom);
+};
+
class MockFramerVisitor : public QuicFramerVisitorInterface {
public:
MockFramerVisitor();
diff --git a/net/quic/test_tools/reliable_quic_stream_peer.cc b/net/quic/test_tools/reliable_quic_stream_peer.cc
index 6d1f1129..914609e 100644
--- a/net/quic/test_tools/reliable_quic_stream_peer.cc
+++ b/net/quic/test_tools/reliable_quic_stream_peer.cc
@@ -39,8 +39,6 @@
return stream->rst_sent_;
}
-
-
// static
uint32 ReliableQuicStreamPeer::SizeOfQueuedData(ReliableQuicStream* stream) {
uint32 total = 0;
@@ -53,5 +51,11 @@
return total;
}
+// static
+void ReliableQuicStreamPeer::SetFecPolicy(ReliableQuicStream* stream,
+ FecPolicy fec_policy) {
+ stream->set_fec_policy(fec_policy);
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/reliable_quic_stream_peer.h b/net/quic/test_tools/reliable_quic_stream_peer.h
index c23bf50..1f5467d 100644
--- a/net/quic/test_tools/reliable_quic_stream_peer.h
+++ b/net/quic/test_tools/reliable_quic_stream_peer.h
@@ -26,6 +26,8 @@
static uint32 SizeOfQueuedData(ReliableQuicStream* stream);
+ static void SetFecPolicy(ReliableQuicStream* stream, FecPolicy fec_policy);
+
private:
DISALLOW_COPY_AND_ASSIGN(ReliableQuicStreamPeer);
};
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 5676fc1..46df4fe5 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -24,6 +24,7 @@
#include "net/quic/quic_sent_packet_manager.h"
#include "net/quic/quic_server_id.h"
#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_flow_controller_peer.h"
#include "net/quic/test_tools/quic_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/reliable_quic_stream_peer.h"
@@ -50,8 +51,10 @@
using net::EpollServer;
using net::test::GenerateBody;
using net::test::QuicConnectionPeer;
+using net::test::QuicFlowControllerPeer;
using net::test::QuicSessionPeer;
using net::test::ReliableQuicStreamPeer;
+using net::test::ValueRestore;
using net::test::kClientDataStreamId1;
using net::tools::test::PacketDroppingTestWriter;
using net::tools::test::QuicDispatcherPeer;
@@ -178,10 +181,10 @@
server_config_.SetDefaults();
// Use different flow control windows for client/server.
- client_initial_flow_control_receive_window_ =
- 2 * kInitialFlowControlWindowForTest;
- server_initial_flow_control_receive_window_ =
- 3 * kInitialFlowControlWindowForTest;
+ client_config_.SetInitialFlowControlWindowToSend(
+ 2 * kInitialFlowControlWindowForTest);
+ server_config_.SetInitialFlowControlWindowToSend(
+ 3 * kInitialFlowControlWindowForTest);
QuicInMemoryCachePeer::ResetForTests();
AddToCache("GET", "https://www.google.com/foo",
@@ -202,8 +205,7 @@
server_hostname_,
false, // not secure
client_config_,
- client_supported_versions_,
- client_initial_flow_control_receive_window_);
+ client_supported_versions_);
client->UseWriter(writer);
client->Connect();
return client;
@@ -212,13 +214,13 @@
void set_client_initial_flow_control_receive_window(uint32 window) {
CHECK(client_.get() == NULL);
DVLOG(1) << "Setting client initial flow control window: " << window;
- client_initial_flow_control_receive_window_ = window;
+ client_config_.SetInitialFlowControlWindowToSend(window);
}
void set_server_initial_flow_control_receive_window(uint32 window) {
CHECK(server_thread_.get() == NULL);
DVLOG(1) << "Setting server initial flow control window: " << window;
- server_initial_flow_control_receive_window_ = window;
+ server_config_.SetInitialFlowControlWindowToSend(window);
}
bool Initialize() {
@@ -248,11 +250,10 @@
void StartServer() {
server_thread_.reset(
- new ServerThread(server_address_,
- server_config_,
- server_supported_versions_,
- strike_register_no_startup_period_,
- server_initial_flow_control_receive_window_));
+ new ServerThread(
+ new QuicServer(server_config_, server_supported_versions_),
+ server_address_,
+ strike_register_no_startup_period_));
server_thread_->Initialize();
server_address_ = IPEndPoint(server_address_.address(),
server_thread_->GetPort());
@@ -351,8 +352,6 @@
QuicVersionVector server_supported_versions_;
QuicVersion negotiated_version_;
bool strike_register_no_startup_period_;
- uint32 client_initial_flow_control_receive_window_;
- uint32 server_initial_flow_control_receive_window_;
};
// Run all end to end tests with all supported versions.
@@ -637,9 +636,6 @@
}
TEST_P(EndToEndTest, LargePostFEC) {
- // TODO(jri): Set FecPolicy to always protect on client_->stream_.
- // This test currently does not do any FEC protection.
-
// Connect without packet loss to avoid issues with losing handshake packets,
// and then up the packet loss rate (b/10126687).
ASSERT_TRUE(Initialize());
@@ -651,7 +647,9 @@
// Enable FEC protection.
QuicPacketCreator* creator = QuicConnectionPeer::GetPacketCreator(
client_->client()->session()->connection());
- creator->set_max_packets_per_fec_group(6);
+ creator->set_max_packets_per_fec_group(3);
+ // Set FecPolicy to always protect data on all streams.
+ client_->SetFecPolicy(FEC_PROTECT_ALWAYS);
string body;
GenerateBody(&body, 10240);
@@ -689,6 +687,49 @@
VerifyCleanConnection(false);
}
+TEST_P(EndToEndTest, DoNotSetResumeWriteAlarmIfConnectionFlowControlBlocked) {
+ // Regression test for b/14677858.
+ // Test that the resume write alarm is not set in QuicConnection::OnCanWrite
+ // if currently connection level flow control blocked. If set, this results in
+ // an infinite loop in the EpollServer, as the alarm fires and is immediately
+ // rescheduled.
+ ASSERT_TRUE(Initialize());
+ if (negotiated_version_ < QUIC_VERSION_19) {
+ return;
+ }
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
+ // Ensure both stream and connection level are flow control blocked by setting
+ // the send window offset to 0.
+ const uint64 kFlowControlWindow =
+ server_config_.GetInitialFlowControlWindowToSend();
+ QuicSpdyClientStream* stream = client_->GetOrCreateStream();
+ QuicSession* session = client_->client()->session();
+ QuicFlowControllerPeer::SetSendWindowOffset(stream->flow_controller(), 0);
+ QuicFlowControllerPeer::SetSendWindowOffset(session->flow_controller(), 0);
+ EXPECT_TRUE(stream->flow_controller()->IsBlocked());
+ EXPECT_TRUE(session->flow_controller()->IsBlocked());
+
+ // Make sure that the stream has data pending so that it will be marked as
+ // write blocked when it receives a stream level WINDOW_UPDATE.
+ stream->SendBody("hello", false);
+
+ // The stream now attempts to write, fails because it is still connection
+ // level flow control blocked, and is added to the write blocked list.
+ QuicWindowUpdateFrame window_update(stream->id(), 2 * kFlowControlWindow);
+ stream->OnWindowUpdateFrame(window_update);
+
+ // Prior to fixing b/14677858 this call would result in an infinite loop in
+ // Chromium. As a proxy for detecting this, we now check whether the
+ // resume_writes_alarm is set after OnCanWrite. It should not be, as the
+ // connection is still flow control blocked.
+ session->connection()->OnCanWrite();
+
+ QuicAlarm* resume_writes_alarm =
+ QuicConnectionPeer::GetResumeWritesAlarm(session->connection());
+ EXPECT_FALSE(resume_writes_alarm->IsSet());
+}
+
TEST_P(EndToEndTest, InvalidStream) {
ASSERT_TRUE(Initialize());
client_->client()->WaitForCryptoHandshakeConfirmed();
@@ -747,6 +788,30 @@
}
}
+TEST_P(EndToEndTest, NegotiateMaxOpenStreams) {
+ // Negotiate 1 max open stream.
+ client_config_.set_max_streams_per_connection(1, 1);
+ ASSERT_TRUE(Initialize());
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
+ // Make the client misbehave after negotiation.
+ QuicSessionPeer::SetMaxOpenStreams(client_->client()->session(), 10);
+
+ HTTPMessage request(HttpConstants::HTTP_1_1,
+ HttpConstants::POST, "/foo");
+ request.AddHeader("content-length", "3");
+ request.set_has_complete_message(false);
+
+ // Open two simultaneous streams.
+ client_->SendMessage(request);
+ client_->SendMessage(request);
+ client_->WaitForResponse();
+
+ EXPECT_FALSE(client_->connected());
+ EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
+ EXPECT_EQ(QUIC_TOO_MANY_OPEN_STREAMS, client_->connection_error());
+}
+
TEST_P(EndToEndTest, LimitMaxOpenStreams) {
// Server limits the number of max streams to 2.
server_config_.set_max_streams_per_connection(2, 2);
@@ -823,6 +888,7 @@
client_->client()->WaitForCryptoHandshakeConfirmed();
server_thread_->WaitForCryptoHandshakeConfirmed();
+ // Pause the server so we can access the server's internals without races.
server_thread_->Pause();
QuicDispatcher* dispatcher =
QuicServerPeer::GetDispatcher(server_thread_->server());
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index f2802a2..1bee994 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -35,8 +35,7 @@
QuicClient::QuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
- bool print_response,
- uint32 initial_flow_control_window)
+ bool print_response)
: server_address_(server_address),
server_id_(server_id),
local_port_(0),
@@ -46,16 +45,15 @@
packets_dropped_(0),
overflow_supported_(false),
supported_versions_(supported_versions),
- print_response_(print_response),
- initial_flow_control_window_(initial_flow_control_window) {
+ print_response_(print_response) {
config_.SetDefaults();
}
QuicClient::QuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
- const QuicConfig& config,
const QuicVersionVector& supported_versions,
- uint32 initial_flow_control_window)
+ bool print_response,
+ const QuicConfig& config)
: server_address_(server_address),
server_id_(server_id),
config_(config),
@@ -66,8 +64,7 @@
packets_dropped_(0),
overflow_supported_(false),
supported_versions_(supported_versions),
- print_response_(false),
- initial_flow_control_window_(initial_flow_control_window) {
+ print_response_(print_response) {
}
QuicClient::~QuicClient() {
@@ -190,7 +187,6 @@
config_,
new QuicConnection(GenerateConnectionId(), server_address_, helper_.get(),
writer_.get(), false, supported_versions_),
- initial_flow_control_window_,
&crypto_config_));
return session_->CryptoConnect();
}
@@ -223,7 +219,7 @@
stream->set_visitor(this);
}
- while (WaitForEvents()) { }
+ while (WaitForEvents()) {}
}
QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h
index 33dfeaa..da934ff7 100644
--- a/net/tools/quic/quic_client.h
+++ b/net/tools/quic/quic_client.h
@@ -50,13 +50,12 @@
QuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
- bool print_response,
- uint32 initial_flow_control_window);
+ bool print_response);
QuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
- const QuicConfig& config,
const QuicVersionVector& supported_versions,
- uint32 initial_flow_control_window);
+ bool print_response,
+ const QuicConfig& config);
virtual ~QuicClient();
@@ -245,9 +244,6 @@
// when the stream is closed (in OnClose).
bool print_response_;
- // Size of initial flow control receive window to advertise to server.
- uint32 initial_flow_control_window_;
-
DISALLOW_COPY_AND_ASSIGN(QuicClient);
};
diff --git a/net/tools/quic/quic_client_bin.cc b/net/tools/quic/quic_client_bin.cc
index ebbc51e..fefdfc9 100644
--- a/net/tools/quic/quic_client_bin.cc
+++ b/net/tools/quic/quic_client_bin.cc
@@ -79,12 +79,16 @@
net::IPAddressNumber addr;
CHECK(net::ParseIPLiteralToNumber(FLAGS_address, &addr));
+
+ net::QuicConfig config;
+ config.SetInitialFlowControlWindowToSend(FLAGS_initial_flow_control_window);
+
// TODO(rjshade): Set version on command line.
net::tools::QuicClient client(
net::IPEndPoint(addr, FLAGS_port),
net::QuicServerId(FLAGS_hostname, FLAGS_port, FLAGS_secure,
net::PRIVACY_MODE_DISABLED),
- net::QuicSupportedVersions(), true, FLAGS_initial_flow_control_window);
+ net::QuicSupportedVersions(), true, config);
client.Initialize();
diff --git a/net/tools/quic/quic_client_session.cc b/net/tools/quic/quic_client_session.cc
index c8e28db..aca5418a 100644
--- a/net/tools/quic/quic_client_session.cc
+++ b/net/tools/quic/quic_client_session.cc
@@ -18,11 +18,8 @@
const QuicServerId& server_id,
const QuicConfig& config,
QuicConnection* connection,
- uint32 max_flow_control_receive_window_bytes,
QuicCryptoClientConfig* crypto_config)
- : QuicClientSessionBase(connection,
- max_flow_control_receive_window_bytes,
- config),
+ : QuicClientSessionBase(connection, config),
crypto_stream_(server_id, this, NULL, crypto_config) {
}
diff --git a/net/tools/quic/quic_client_session.h b/net/tools/quic/quic_client_session.h
index d04b420..3aad445 100644
--- a/net/tools/quic/quic_client_session.h
+++ b/net/tools/quic/quic_client_session.h
@@ -28,7 +28,6 @@
QuicClientSession(const QuicServerId& server_id,
const QuicConfig& config,
QuicConnection* connection,
- uint32 max_flow_control_receive_window_bytes,
QuicCryptoClientConfig* crypto_config);
virtual ~QuicClientSession();
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index 50f4c13..e2d39c1 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -39,7 +39,6 @@
QuicServerId(kServerHostname, kPort, false, PRIVACY_MODE_DISABLED),
DefaultQuicConfig(),
connection_,
- kInitialFlowControlWindowForTest,
&crypto_config_));
session_->config()->SetDefaults();
}
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 310450f..715e408 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -162,8 +162,7 @@
QuicDispatcher::QuicDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
const QuicVersionVector& supported_versions,
- EpollServer* epoll_server,
- uint32 initial_flow_control_window_bytes)
+ EpollServer* epoll_server)
: config_(config),
crypto_config_(crypto_config),
delete_sessions_alarm_(new DeleteSessionsAlarm(this)),
@@ -174,8 +173,7 @@
supported_versions_no_connection_flow_control_(supported_versions),
current_packet_(NULL),
framer_(supported_versions, /*unused*/ QuicTime::Zero(), true),
- framer_visitor_(new QuicFramerVisitor(this)),
- initial_flow_control_window_bytes_(initial_flow_control_window_bytes) {
+ framer_visitor_(new QuicFramerVisitor(this)) {
framer_.set_visitor(framer_visitor_.get());
}
@@ -382,7 +380,6 @@
QuicServerSession* session = new QuicServerSession(
config_,
CreateQuicConnection(connection_id, server_address, client_address),
- initial_flow_control_window_bytes_,
this);
session->InitializeSession(crypto_config_);
return session;
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h
index 4ec5449f..2468f1c 100644
--- a/net/tools/quic/quic_dispatcher.h
+++ b/net/tools/quic/quic_dispatcher.h
@@ -61,8 +61,7 @@
QuicDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
const QuicVersionVector& supported_versions,
- EpollServer* epoll_server,
- uint32 initial_flow_control_window_bytes);
+ EpollServer* epoll_server);
virtual ~QuicDispatcher();
@@ -166,10 +165,6 @@
QuicPacketWriter* writer() { return writer_.get(); }
- const uint32 initial_flow_control_window_bytes() const {
- return initial_flow_control_window_bytes_;
- }
-
private:
class QuicFramerVisitor;
friend class net::tools::test::QuicDispatcherPeer;
@@ -238,10 +233,6 @@
QuicFramer framer_;
scoped_ptr<QuicFramerVisitor> framer_visitor_;
- // Initial flow control window size to advertize to peer on newly created
- // connections.
- const uint32 initial_flow_control_window_bytes_;
-
DISALLOW_COPY_AND_ASSIGN(QuicDispatcher);
};
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index 67d4d63..41c3c27 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -24,15 +24,16 @@
using base::StringPiece;
using net::EpollServer;
-using net::test::MockSession;
using net::test::ConstructEncryptedPacket;
+using net::test::MockSession;
+using net::test::ValueRestore;
using net::tools::test::MockConnection;
using std::make_pair;
-using testing::_;
using testing::DoAll;
-using testing::Invoke;
using testing::InSequence;
+using testing::Invoke;
using testing::WithoutArgs;
+using testing::_;
namespace net {
namespace tools {
@@ -47,8 +48,7 @@
: QuicDispatcher(config,
crypto_config,
QuicSupportedVersions(),
- eps,
- kInitialFlowControlWindowForTest) {
+ eps) {
}
MOCK_METHOD3(CreateQuicSession, QuicSession*(
@@ -283,12 +283,11 @@
kTestVersions.push_back(kTestQuicVersions[i]);
}
- QuicDispatcher dispatcher(config, server_config, kTestVersions, &eps,
- kInitialFlowControlWindowForTest);
+ QuicDispatcher dispatcher(config, server_config, kTestVersions, &eps);
dispatcher.Initialize(0);
// When flag is enabled, new connections should support QUIC_VERSION_17.
- FLAGS_enable_quic_stream_flow_control_2 = true;
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_stream_flow_control_2, true);
scoped_ptr<QuicConnection> connection_1(
QuicDispatcherPeer::CreateQuicConnection(&dispatcher, kCID, client,
server));
diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc
index 2d1a52d..be3d9fb 100644
--- a/net/tools/quic/quic_server.cc
+++ b/net/tools/quic/quic_server.cc
@@ -42,17 +42,14 @@
overflow_supported_(false),
use_recvmmsg_(false),
crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()),
- supported_versions_(QuicSupportedVersions()),
- server_initial_flow_control_receive_window_(
- kServerInitialFlowControlWindow) {
+ supported_versions_(QuicSupportedVersions()) {
// Use hardcoded crypto parameters for now.
config_.SetDefaults();
Initialize();
}
QuicServer::QuicServer(const QuicConfig& config,
- const QuicVersionVector& supported_versions,
- uint32 server_initial_flow_control_receive_window)
+ const QuicVersionVector& supported_versions)
: port_(0),
fd_(-1),
packets_dropped_(0),
@@ -60,9 +57,7 @@
use_recvmmsg_(false),
config_(config),
crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()),
- supported_versions_(supported_versions),
- server_initial_flow_control_receive_window_(
- server_initial_flow_control_receive_window) {
+ supported_versions_(supported_versions) {
Initialize();
}
@@ -80,6 +75,9 @@
crypto_config_.AddDefaultConfig(
QuicRandom::GetInstance(), &clock,
QuicCryptoServerConfig::ConfigOptions()));
+
+ // Set flow control options in the config.
+ config_.SetInitialCongestionWindowToSend(kServerInitialFlowControlWindow);
}
QuicServer::~QuicServer() {
@@ -164,17 +162,20 @@
}
epoll_server_.RegisterFD(fd_, this, kEpollFlags);
- dispatcher_.reset(new QuicDispatcher(
- config_,
- crypto_config_,
- supported_versions_,
- &epoll_server_,
- server_initial_flow_control_receive_window_));
+ dispatcher_.reset(CreateQuicDispatcher());
dispatcher_->Initialize(fd_);
return true;
}
+QuicDispatcher* QuicServer::CreateQuicDispatcher() {
+ return new QuicDispatcher(
+ config_,
+ crypto_config_,
+ supported_versions_,
+ &epoll_server_);
+}
+
void QuicServer::WaitForEvents() {
epoll_server_.WaitForEventsAndExecuteCallbacks();
}
diff --git a/net/tools/quic/quic_server.h b/net/tools/quic/quic_server.h
index 119fa78..6285fd76 100644
--- a/net/tools/quic/quic_server.h
+++ b/net/tools/quic/quic_server.h
@@ -31,8 +31,7 @@
public:
QuicServer();
QuicServer(const QuicConfig& config,
- const QuicVersionVector& supported_versions,
- uint32 server_initial_flow_control_receive_window);
+ const QuicVersionVector& supported_versions);
virtual ~QuicServer();
@@ -81,6 +80,18 @@
int port() { return port_; }
+ protected:
+ virtual QuicDispatcher* CreateQuicDispatcher();
+
+ const QuicConfig& config() const { return config_; }
+ const QuicCryptoServerConfig& crypto_config() const {
+ return crypto_config_;
+ }
+ const QuicVersionVector& supported_versions() const {
+ return supported_versions_;
+ }
+ EpollServer* epoll_server() { return &epoll_server_; }
+
private:
friend class net::tools::test::QuicServerPeer;
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 7c31ef0..d7bc3b8 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -14,9 +14,8 @@
QuicServerSession::QuicServerSession(const QuicConfig& config,
QuicConnection* connection,
- uint32 max_flow_control_window_bytes,
QuicServerSessionVisitor* visitor)
- : QuicSession(connection, max_flow_control_window_bytes, config),
+ : QuicSession(connection, config),
visitor_(visitor) {}
QuicServerSession::~QuicServerSession() {}
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h
index 9fc4611e..e05ba16 100644
--- a/net/tools/quic/quic_server_session.h
+++ b/net/tools/quic/quic_server_session.h
@@ -47,7 +47,6 @@
public:
QuicServerSession(const QuicConfig& config,
QuicConnection* connection,
- uint32 max_flow_control_window_bytes,
QuicServerSessionVisitor* visitor);
// Override the base class to notify the owner of the connection close.
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc
index 728b2bc..34c0066 100644
--- a/net/tools/quic/quic_server_session_test.cc
+++ b/net/tools/quic/quic_server_session_test.cc
@@ -52,11 +52,11 @@
QuicRandom::GetInstance()) {
config_.SetDefaults();
config_.set_max_streams_per_connection(3, 3);
+ config_.SetInitialFlowControlWindowToSend(kInitialFlowControlWindowForTest);
connection_ =
new StrictMock<MockConnection>(true, SupportedVersions(GetParam()));
- session_.reset(new QuicServerSession(
- config_, connection_, kInitialFlowControlWindowForTest, &owner_));
+ session_.reset(new QuicServerSession(config_, connection_, &owner_));
session_->InitializeSession(crypto_config_);
visitor_ = QuicConnectionPeer::GetVisitor(connection_);
}
diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc
index 4de5c9b..db38924c 100644
--- a/net/tools/quic/quic_spdy_client_stream_test.cc
+++ b/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -32,7 +32,6 @@
session_(QuicServerId("example.com", 80, false, PRIVACY_MODE_DISABLED),
DefaultQuicConfig(),
connection_,
- kInitialFlowControlWindowForTest,
&crypto_config_),
body_("hello world") {
crypto_config_.SetDefaults();
diff --git a/net/tools/quic/quic_spdy_server_stream_test.cc b/net/tools/quic/quic_spdy_server_stream_test.cc
index 954f0a4..a6a015d 100644
--- a/net/tools/quic/quic_spdy_server_stream_test.cc
+++ b/net/tools/quic/quic_spdy_server_stream_test.cc
@@ -84,9 +84,8 @@
// New streams rely on having the peer's flow control receive window
// negotiated in the config.
- const uint32 kInitialWindow = 10 * kMaxPacketSize;
session_.config()->SetInitialFlowControlWindowToSend(
- kInitialWindow);
+ kInitialFlowControlWindowForTest);
stream_.reset(new QuicSpdyServerStreamPeer(3, &session_));
}
diff --git a/net/tools/quic/test_tools/mock_epoll_server.h b/net/tools/quic/test_tools/mock_epoll_server.h
index abead02e..cdb6a36 100644
--- a/net/tools/quic/test_tools/mock_epoll_server.h
+++ b/net/tools/quic/test_tools/mock_epoll_server.h
@@ -85,16 +85,16 @@
protected: // functions
// These functions do nothing here, as we're not actually
// using the epoll_* syscalls.
- virtual void DelFD(int fd) const OVERRIDE { }
- virtual void AddFD(int fd, int event_mask) const OVERRIDE { }
- virtual void ModFD(int fd, int event_mask) const OVERRIDE { }
+ virtual void DelFD(int fd) const OVERRIDE {}
+ virtual void AddFD(int fd, int event_mask) const OVERRIDE {}
+ virtual void ModFD(int fd, int event_mask) const OVERRIDE {}
// Replaces the epoll_server's epoll_wait_impl.
virtual int epoll_wait_impl(int epfd,
struct epoll_event* events,
int max_events,
int timeout_in_ms) OVERRIDE;
- virtual void SetNonblocking (int fd) OVERRIDE { }
+ virtual void SetNonblocking (int fd) OVERRIDE {}
private: // members
EventQueue event_queue_;
diff --git a/net/tools/quic/test_tools/mock_quic_dispatcher.cc b/net/tools/quic/test_tools/mock_quic_dispatcher.cc
index 21195bc..dc7f0d3f 100644
--- a/net/tools/quic/test_tools/mock_quic_dispatcher.cc
+++ b/net/tools/quic/test_tools/mock_quic_dispatcher.cc
@@ -19,8 +19,7 @@
: QuicDispatcher(config,
crypto_config,
QuicSupportedVersions(),
- eps,
- kInitialFlowControlWindowForTest) {}
+ eps) {}
MockQuicDispatcher::~MockQuicDispatcher() {}
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.cc b/net/tools/quic/test_tools/packet_dropping_test_writer.cc
index 148591d0c..f438eb0 100644
--- a/net/tools/quic/test_tools/packet_dropping_test_writer.cc
+++ b/net/tools/quic/test_tools/packet_dropping_test_writer.cc
@@ -19,7 +19,7 @@
class WriteUnblockedAlarm : public QuicAlarm::Delegate {
public:
explicit WriteUnblockedAlarm(PacketDroppingTestWriter* writer)
- : writer_(writer) { }
+ : writer_(writer) {}
virtual QuicTime OnAlarm() OVERRIDE {
DVLOG(1) << "Unblocking socket.";
@@ -36,7 +36,7 @@
class DelayAlarm : public QuicAlarm::Delegate {
public:
explicit DelayAlarm(PacketDroppingTestWriter* writer)
- : writer_(writer) { }
+ : writer_(writer) {}
virtual QuicTime OnAlarm() OVERRIDE {
return writer_->ReleaseOldPackets();
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.h b/net/tools/quic/test_tools/packet_dropping_test_writer.h
index 78f0a40..3509722 100644
--- a/net/tools/quic/test_tools/packet_dropping_test_writer.h
+++ b/net/tools/quic/test_tools/packet_dropping_test_writer.h
@@ -12,6 +12,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "net/quic/quic_alarm.h"
+#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/quic_epoll_clock.h"
#include "net/tools/quic/quic_packet_writer_wrapper.h"
#include "net/tools/quic/test_tools/quic_test_client.h"
@@ -134,7 +135,7 @@
scoped_ptr<QuicAlarm> write_unblocked_alarm_;
scoped_ptr<QuicAlarm> delay_alarm_;
scoped_ptr<Delegate> on_can_write_;
- SimpleRandom simple_random_;
+ net::test::SimpleRandom simple_random_;
// Stored packets delayed by fake packet delay or bandwidth restrictions.
DelayedPacketList delayed_packets_;
QuicByteCount cur_buffer_size_;
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 51f599d..d0cfe68 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -12,7 +12,9 @@
#include "net/quic/crypto/proof_verifier.h"
#include "net/quic/quic_server_id.h"
#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/reliable_quic_stream_peer.h"
#include "net/tools/balsa/balsa_headers.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_packet_writer_wrapper.h"
@@ -23,8 +25,10 @@
using base::StringPiece;
using net::QuicServerId;
-using net::test::kInitialFlowControlWindowForTest;
using net::test::QuicConnectionPeer;
+using net::test::QuicSessionPeer;
+using net::test::ReliableQuicStreamPeer;
+using net::test::kInitialFlowControlWindowForTest;
using std::string;
using std::vector;
@@ -100,13 +104,11 @@
MockableQuicClient::MockableQuicClient(
IPEndPoint server_address,
const QuicServerId& server_id,
- const QuicVersionVector& supported_versions,
- uint32 initial_flow_control_window)
+ const QuicVersionVector& supported_versions)
: QuicClient(server_address,
server_id,
supported_versions,
- false,
- initial_flow_control_window),
+ false),
override_connection_id_(0),
test_writer_(NULL) {}
@@ -114,13 +116,12 @@
IPEndPoint server_address,
const QuicServerId& server_id,
const QuicConfig& config,
- const QuicVersionVector& supported_versions,
- uint32 initial_flow_control_window)
+ const QuicVersionVector& supported_versions)
: QuicClient(server_address,
server_id,
- config,
supported_versions,
- initial_flow_control_window),
+ false,
+ config),
override_connection_id_(0),
test_writer_(NULL) {}
@@ -162,8 +163,7 @@
server_address.port(),
false,
PRIVACY_MODE_DISABLED),
- supported_versions,
- kInitialFlowControlWindowForTest)) {
+ supported_versions)) {
Initialize(true);
}
@@ -176,8 +176,7 @@
server_address.port(),
secure,
PRIVACY_MODE_DISABLED),
- supported_versions,
- kInitialFlowControlWindowForTest)) {
+ supported_versions)) {
Initialize(secure);
}
@@ -186,8 +185,7 @@
const string& server_hostname,
bool secure,
const QuicConfig& config,
- const QuicVersionVector& supported_versions,
- uint32 client_initial_flow_control_receive_window)
+ const QuicVersionVector& supported_versions)
: client_(
new MockableQuicClient(server_address,
QuicServerId(server_hostname,
@@ -195,8 +193,7 @@
secure,
PRIVACY_MODE_DISABLED),
config,
- supported_versions,
- client_initial_flow_control_receive_window)) {
+ supported_versions)) {
Initialize(secure);
}
@@ -215,6 +212,7 @@
secure_ = secure;
auto_reconnect_ = false;
buffer_body_ = true;
+ fec_policy_ = FEC_PROTECT_OPTIONAL;
proof_verifier_ = NULL;
ClearPerRequestState();
ExpectCertificates(secure_);
@@ -333,6 +331,8 @@
}
stream_->set_visitor(this);
reinterpret_cast<QuicSpdyClientStream*>(stream_)->set_priority(priority_);
+ // Set FEC policy on stream.
+ ReliableQuicStreamPeer::SetFecPolicy(stream_, fec_policy_);
}
return stream_;
@@ -545,6 +545,15 @@
}
}
+void QuicTestClient::SetFecPolicy(FecPolicy fec_policy) {
+ fec_policy_ = fec_policy;
+ // Set policy for headers and crypto streams.
+ ReliableQuicStreamPeer::SetFecPolicy(
+ QuicSessionPeer::GetHeadersStream(client()->session()), fec_policy);
+ ReliableQuicStreamPeer::SetFecPolicy(client()->session()->GetCryptoStream(),
+ fec_policy);
+}
+
} // namespace test
} // namespace tools
} // namespace net
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h
index 975ce5a..1c70c33 100644
--- a/net/tools/quic/test_tools/quic_test_client.h
+++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -35,14 +35,12 @@
public:
MockableQuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
- const QuicVersionVector& supported_versions,
- uint32 initial_flow_control_window);
+ const QuicVersionVector& supported_versions);
MockableQuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicConfig& config,
- const QuicVersionVector& supported_versions,
- uint32 initial_flow_control_window);
+ const QuicVersionVector& supported_versions);
virtual ~MockableQuicClient() OVERRIDE;
virtual QuicPacketWriter* CreateQuicPacketWriter() OVERRIDE;
@@ -72,8 +70,7 @@
const string& server_hostname,
bool secure,
const QuicConfig& config,
- const QuicVersionVector& supported_versions,
- uint32 client_initial_flow_control_receive_window);
+ const QuicVersionVector& supported_versions);
virtual ~QuicTestClient();
@@ -154,6 +151,10 @@
void set_priority(QuicPriority priority) { priority_ = priority; }
+ // Sets client's FEC policy. This policy applies to the data stream(s), and
+ // also to the headers and crypto streams.
+ void SetFecPolicy(FecPolicy fec_policy);
+
void WaitForWriteToFlush();
protected:
@@ -189,7 +190,8 @@
bool auto_reconnect_;
// Should we buffer the response body? Defaults to true.
bool buffer_body_;
-
+ // FEC policy for data sent by this client.
+ FecPolicy fec_policy_;
// proof_verifier_ points to a RecordingProofVerifier that is owned by
// client_.
ProofVerifier* proof_verifier_;
diff --git a/net/tools/quic/test_tools/quic_test_utils.cc b/net/tools/quic/test_tools/quic_test_utils.cc
index 18a6a62..e552c24b 100644
--- a/net/tools/quic/test_tools/quic_test_utils.cc
+++ b/net/tools/quic/test_tools/quic_test_utils.cc
@@ -4,7 +4,6 @@
#include "net/tools/quic/test_tools/quic_test_utils.h"
-#include "base/sha1.h"
#include "net/quic/quic_connection.h"
#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
@@ -80,18 +79,10 @@
return ack;
}
-uint64 SimpleRandom::RandUint64() {
- unsigned char hash[base::kSHA1Length];
- base::SHA1HashBytes(reinterpret_cast<unsigned char*>(&seed_), sizeof(seed_),
- hash);
- memcpy(&seed_, hash, sizeof(seed_));
- return seed_;
-}
-
TestSession::TestSession(QuicConnection* connection,
const QuicConfig& config)
- : QuicSession(connection, kInitialFlowControlWindowForTest, config),
- crypto_stream_(NULL) {
+ : QuicSession(connection, config),
+ crypto_stream_(NULL) {
}
TestSession::~TestSession() {}
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h
index 44dbd2bd..2ff8c84 100644
--- a/net/tools/quic/test_tools/quic_test_utils.h
+++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -34,25 +34,6 @@
QuicAckFrame MakeAckFrameWithNackRanges(size_t num_nack_ranges,
QuicPacketSequenceNumber least_unacked);
-// Simple random number generator used to compute random numbers suitable
-// for pseudo-randomly dropping packets in tests. It works by computing
-// the sha1 hash of the current seed, and using the first 64 bits as
-// the next random number, and the next seed.
-class SimpleRandom {
- public:
- SimpleRandom() : seed_(0) {}
-
- // Returns a random number in the range [0, kuint64max].
- uint64 RandUint64();
-
- void set_seed(uint64 seed) { seed_ = seed; }
-
- private:
- uint64 seed_;
-
- DISALLOW_COPY_AND_ASSIGN(SimpleRandom);
-};
-
class MockConnection : public QuicConnection {
public:
// Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
diff --git a/net/tools/quic/test_tools/server_thread.cc b/net/tools/quic/test_tools/server_thread.cc
index 839e137..337cc64 100644
--- a/net/tools/quic/test_tools/server_thread.cc
+++ b/net/tools/quic/test_tools/server_thread.cc
@@ -10,25 +10,21 @@
namespace tools {
namespace test {
-ServerThread::ServerThread(IPEndPoint address,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions,
- bool strike_register_no_startup_period,
- uint32 server_initial_flow_control_receive_window)
+ServerThread::ServerThread(QuicServer* server,
+ IPEndPoint address,
+ bool strike_register_no_startup_period)
: SimpleThread("server_thread"),
confirmed_(true, false),
pause_(true, false),
paused_(true, false),
resume_(true, false),
quit_(true, false),
- server_(config,
- supported_versions,
- server_initial_flow_control_receive_window),
+ server_(server),
address_(address),
port_(0),
initialized_(false) {
if (strike_register_no_startup_period) {
- server_.SetStrikeRegisterNoStartupPeriod();
+ server_->SetStrikeRegisterNoStartupPeriod();
}
}
@@ -39,10 +35,10 @@
return;
}
- server_.Listen(address_);
+ server_->Listen(address_);
port_lock_.Acquire();
- port_ = server_.port();
+ port_ = server_->port();
port_lock_.Release();
initialized_ = true;
@@ -58,11 +54,11 @@
paused_.Signal();
resume_.Wait();
}
- server_.WaitForEvents();
+ server_->WaitForEvents();
MaybeNotifyOfHandshakeConfirmation();
}
- server_.Shutdown();
+ server_->Shutdown();
}
int ServerThread::GetPort() {
diff --git a/net/tools/quic/test_tools/server_thread.h b/net/tools/quic/test_tools/server_thread.h
index 9473784..6066d974 100644
--- a/net/tools/quic/test_tools/server_thread.h
+++ b/net/tools/quic/test_tools/server_thread.h
@@ -17,11 +17,9 @@
// Simple wrapper class to run server in a thread.
class ServerThread : public base::SimpleThread {
public:
- ServerThread(IPEndPoint address,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions,
- bool strike_register_no_startup_period,
- uint32 server_initial_flow_control_receive_window);
+ ServerThread(QuicServer* server,
+ IPEndPoint address,
+ bool strike_register_no_startup_period);
virtual ~ServerThread();
@@ -50,7 +48,7 @@
// Returns the underlying server. Care must be taken to avoid data races
// when accessing the server. It is always safe to access the server
// after calling Pause() and before calling Resume().
- QuicServer* server() { return &server_; }
+ QuicServer* server() { return server_.get(); }
// Returns the port that the server is listening on.
int GetPort();
@@ -65,7 +63,7 @@
base::WaitableEvent resume_; // Notified when the server should resume.
base::WaitableEvent quit_; // Notified when the server should quit.
- tools::QuicServer server_;
+ scoped_ptr<QuicServer> server_;
IPEndPoint address_;
base::Lock port_lock_;
int port_;