summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-17 15:51:33 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-17 15:51:33 +0000
commitce7bb141d5359dfe1224a85bafa802a09f1e683d (patch)
treed2f27658cb8e127a89d7b4198fe04949283e30e7
parentf5d0fa6e33af3ac62a6d98e4cac1b1420533f6d7 (diff)
downloadchromium_src-ce7bb141d5359dfe1224a85bafa802a09f1e683d.zip
chromium_src-ce7bb141d5359dfe1224a85bafa802a09f1e683d.tar.gz
chromium_src-ce7bb141d5359dfe1224a85bafa802a09f1e683d.tar.bz2
Land Recent QUIC Changes.
Stub for BBRv2, based on TCP congestion feedback frames. Merge internal change: 67154078 https://codereview.chromium.org/283333008/ Update QuicSentPacketManager to sample a new recent min rtt within the first 2 rtt samples after quiescence. Merge internal change: 67149500 https://codereview.chromium.org/286143007/ Change the test QUIC stream id to be the first non reserved stream ID (and also to use the right typedef). Merge internal change: 67146383 https://codereview.chromium.org/292453003/ Adds dynamic FEC on/off switch in packet creator. Tightens use of max_packets_per_fec_group through use of a setter method across the QUIC code. FEC operations are now decided based on should_fec_protect_, which is expected to be a dynamic on/off control in the packet creator, instead of max_packets_per_fec_group. Adds dynamic FEC on/off switch in packet_creator. Merge internal change: 67144415 https://codereview.chromium.org/286153003/ Minor cleanup to simplify QuicSentPacketManager's OnPacketSent and always reset the retransmission alarm anytime a new pending packet is sent. Always setting the retransmission alarm is only a simplification of the approach, and not intended to fix any issues. Merge internal change: 67143274 https://codereview.chromium.org/288333002/ Don't set QUIC's write alarm if we are connection flow control blocked. Added QUIC_VERSION_19 to kSupportedQuicVersions. Merge internal change: 67141668 https://codereview.chromium.org/285193006/ Minor cleanup of QuicUnackedPacketMap to simplify the implementation of HasPendingPackets and move a test only method, GetNumRetransmittablePackets, into QuicSentPacketManagerPeer. Merge internal change: 67123054 https://codereview.chromium.org/282323003/ Fix a QUIC bug where a crypto packet was never removed from the UnackedPacketMap if it was not acked and spuriously retransmitted at least twice. Merge internal change: 67050631 https://codereview.chromium.org/284273002/ Refactor: move flow controller from QuicConnection to QuicSession. No behavior change intended. Merge internal change: 67036889 https://codereview.chromium.org/286213002/ Fix a QUIC bug where a packet could remain in the UnackedPacketMap indefinitely. This can cause a memory leak when tracking entropy. Merge internal change: 67028206 https://codereview.chromium.org/285233006/ Delete dead code used only in tests. Merge internal change: 66938996 https://codereview.chromium.org/288303002/ Add handling + parsing for ALTSVC frame. Also change frame type number and add an extra version check for BLOCKED frame. SPDY4/HTTP2 only. Merge internal change: 66925490 https://codereview.chromium.org/286173002/ QUIC loadtest fixes: - Wait for the QUIC handshake to complete before saying that the QuicTestClient is connected. - Force connect at client creation time when talking HTTP/HTTPS/SPDY for consistency. Merge internal change: 66855236 https://codereview.chromium.org/282153004/ QUIC now respects configured SPDY stream limits. Merge internal change: 66831620 https://codereview.chromium.org/286113004/ R=rch@chromium.org Review URL: https://codereview.chromium.org/288313003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271211 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/net.gypi2
-rw-r--r--net/quic/congestion_control/quic_max_sized_map.h77
-rw-r--r--net/quic/congestion_control/quic_max_sized_map_test.cc66
-rw-r--r--net/quic/congestion_control/receive_algorithm_interface.cc3
-rw-r--r--net/quic/congestion_control/send_algorithm_interface.cc3
-rw-r--r--net/quic/congestion_control/send_algorithm_interface.h9
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.h3
-rw-r--r--net/quic/quic_client_session.cc5
-rw-r--r--net/quic/quic_client_session.h1
-rw-r--r--net/quic/quic_client_session_base.cc10
-rw-r--r--net/quic/quic_client_session_base.h1
-rw-r--r--net/quic/quic_client_session_test.cc4
-rw-r--r--net/quic/quic_connection.cc34
-rw-r--r--net/quic/quic_connection.h26
-rw-r--r--net/quic/quic_connection_logger.cc4
-rw-r--r--net/quic/quic_connection_test.cc50
-rw-r--r--net/quic/quic_crypto_client_stream.cc2
-rw-r--r--net/quic/quic_crypto_server_stream.cc6
-rw-r--r--net/quic/quic_crypto_server_stream.h4
-rw-r--r--net/quic/quic_data_stream_test.cc12
-rw-r--r--net/quic/quic_headers_stream_test.cc6
-rw-r--r--net/quic/quic_http_stream_test.cc6
-rw-r--r--net/quic/quic_packet_creator.cc101
-rw-r--r--net/quic/quic_packet_creator.h39
-rw-r--r--net/quic/quic_packet_creator_test.cc90
-rw-r--r--net/quic/quic_packet_generator_test.cc6
-rw-r--r--net/quic/quic_protocol.cc4
-rw-r--r--net/quic/quic_protocol.h6
-rw-r--r--net/quic/quic_sent_packet_manager.cc48
-rw-r--r--net/quic/quic_sent_packet_manager_test.cc74
-rw-r--r--net/quic/quic_session.cc68
-rw-r--r--net/quic/quic_session.h18
-rw-r--r--net/quic/quic_session_test.cc81
-rw-r--r--net/quic/quic_stream_factory.cc4
-rw-r--r--net/quic/quic_unacked_packet_map.cc25
-rw-r--r--net/quic/quic_unacked_packet_map.h9
-rw-r--r--net/quic/quic_write_blocked_list.h13
-rw-r--r--net/quic/quic_write_blocked_list_test.cc24
-rw-r--r--net/quic/reliable_quic_stream.cc6
-rw-r--r--net/quic/reliable_quic_stream_test.cc30
-rw-r--r--net/quic/test_tools/quic_packet_creator_peer.cc8
-rw-r--r--net/quic/test_tools/quic_packet_creator_peer.h3
-rw-r--r--net/quic/test_tools/quic_sent_packet_manager_peer.cc10
-rw-r--r--net/quic/test_tools/quic_session_peer.cc6
-rw-r--r--net/quic/test_tools/quic_session_peer.h2
-rw-r--r--net/quic/test_tools/quic_test_utils.cc26
-rw-r--r--net/quic/test_tools/quic_test_utils.h2
-rw-r--r--net/tools/quic/end_to_end_test.cc7
-rw-r--r--net/tools/quic/quic_client.cc9
-rw-r--r--net/tools/quic/quic_client_session.cc5
-rw-r--r--net/tools/quic/quic_client_session.h1
-rw-r--r--net/tools/quic/quic_client_session_test.cc2
-rw-r--r--net/tools/quic/quic_dispatcher.cc19
-rw-r--r--net/tools/quic/quic_dispatcher.h3
-rw-r--r--net/tools/quic/quic_dispatcher_test.cc8
-rw-r--r--net/tools/quic/quic_server_session.cc10
-rw-r--r--net/tools/quic/quic_server_session.h1
-rw-r--r--net/tools/quic/quic_server_session_test.cc2
-rw-r--r--net/tools/quic/quic_spdy_client_stream_test.cc1
-rw-r--r--net/tools/quic/test_tools/quic_dispatcher_peer.cc6
-rw-r--r--net/tools/quic/test_tools/quic_dispatcher_peer.h3
-rw-r--r--net/tools/quic/test_tools/quic_test_utils.cc23
62 files changed, 674 insertions, 463 deletions
diff --git a/net/net.gypi b/net/net.gypi
index 7db357e..2b407ef 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -751,7 +751,6 @@
'quic/congestion_control/paced_sender.h',
'quic/congestion_control/pacing_sender.cc',
'quic/congestion_control/pacing_sender.h',
- 'quic/congestion_control/quic_max_sized_map.h',
'quic/congestion_control/receive_algorithm_interface.cc',
'quic/congestion_control/receive_algorithm_interface.h',
'quic/congestion_control/rtt_stats.cc',
@@ -1425,7 +1424,6 @@
'quic/congestion_control/leaky_bucket_test.cc',
'quic/congestion_control/paced_sender_test.cc',
'quic/congestion_control/pacing_sender_test.cc',
- 'quic/congestion_control/quic_max_sized_map_test.cc',
'quic/congestion_control/rtt_stats_test.cc',
'quic/congestion_control/tcp_cubic_sender_test.cc',
'quic/congestion_control/tcp_loss_algorithm_test.cc',
diff --git a/net/quic/congestion_control/quic_max_sized_map.h b/net/quic/congestion_control/quic_max_sized_map.h
deleted file mode 100644
index a4ed776..0000000
--- a/net/quic/congestion_control/quic_max_sized_map.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Simple max sized map. Automatically deletes the oldest element when the
-// max limit is reached.
-// Note: the ConstIterator will NOT be valid after an Insert or RemoveAll.
-#ifndef NET_QUIC_CONGESTION_CONTROL_QUIC_MAX_SIZED_MAP_H_
-#define NET_QUIC_CONGESTION_CONTROL_QUIC_MAX_SIZED_MAP_H_
-
-#include <stdlib.h>
-
-#include <list>
-#include <map>
-
-#include "base/basictypes.h"
-
-namespace net {
-
-template <class Key, class Value>
-class QuicMaxSizedMap {
- public:
- typedef typename std::multimap<Key, Value>::const_iterator ConstIterator;
-
- explicit QuicMaxSizedMap(size_t max_numer_of_items)
- : max_numer_of_items_(max_numer_of_items) {
- }
-
- size_t MaxSize() const {
- return max_numer_of_items_;
- }
-
- size_t Size() const {
- return table_.size();
- }
-
- void Insert(const Key& k, const Value& value) {
- if (Size() == MaxSize()) {
- ListIterator list_it = insert_order_.begin();
- table_.erase(*list_it);
- insert_order_.pop_front();
- }
- TableIterator it = table_.insert(std::pair<Key, Value>(k, value));
- insert_order_.push_back(it);
- }
-
- void RemoveAll() {
- table_.clear();
- insert_order_.clear();
- }
-
- // STL style const_iterator support.
- ConstIterator Find(const Key& k) const {
- return table_.find(k);
- }
-
- ConstIterator Begin() const {
- return ConstIterator(table_.begin());
- }
-
- ConstIterator End() const {
- return ConstIterator(table_.end());
- }
-
- private:
- typedef typename std::multimap<Key, Value>::iterator TableIterator;
- typedef typename std::list<TableIterator>::iterator ListIterator;
-
- const size_t max_numer_of_items_;
- std::multimap<Key, Value> table_;
- std::list<TableIterator> insert_order_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicMaxSizedMap);
-};
-
-} // namespace net
-#endif // NET_QUIC_CONGESTION_CONTROL_QUIC_MAX_SIZED_MAP_H_
diff --git a/net/quic/congestion_control/quic_max_sized_map_test.cc b/net/quic/congestion_control/quic_max_sized_map_test.cc
deleted file mode 100644
index 89c05cc..0000000
--- a/net/quic/congestion_control/quic_max_sized_map_test.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/logging.h"
-#include "net/quic/congestion_control/quic_max_sized_map.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-class QuicMaxSizedMapTest : public ::testing::Test {
-};
-
-TEST_F(QuicMaxSizedMapTest, Basic) {
- QuicMaxSizedMap<int, int> test_map(100);
- EXPECT_EQ(100u, test_map.MaxSize());
- EXPECT_EQ(0u, test_map.Size());
- test_map.Insert(1, 2);
- test_map.Insert(1, 3);
- EXPECT_EQ(100u, test_map.MaxSize());
- EXPECT_EQ(2u, test_map.Size());
- test_map.RemoveAll();
- EXPECT_EQ(100u, test_map.MaxSize());
- EXPECT_EQ(0u, test_map.Size());
-}
-
-TEST_F(QuicMaxSizedMapTest, Find) {
- QuicMaxSizedMap<int, int> test_map(100);
- test_map.Insert(1, 2);
- test_map.Insert(1, 3);
- test_map.Insert(2, 4);
- test_map.Insert(3, 5);
- QuicMaxSizedMap<int, int>::ConstIterator it = test_map.Find(2);
- EXPECT_TRUE(it != test_map.End());
- EXPECT_EQ(4, it->second);
- it = test_map.Find(1);
- EXPECT_TRUE(it != test_map.End());
- EXPECT_EQ(2, it->second);
- ++it;
- EXPECT_TRUE(it != test_map.End());
- EXPECT_EQ(3, it->second);
-}
-
-TEST_F(QuicMaxSizedMapTest, Sort) {
- QuicMaxSizedMap<int, int> test_map(100);
- test_map.Insert(9, 9);
- test_map.Insert(8, 8);
- test_map.Insert(7, 7);
- test_map.Insert(6, 6);
- test_map.Insert(2, 2);
- test_map.Insert(4, 4);
- test_map.Insert(5, 5);
- test_map.Insert(3, 3);
- test_map.Insert(0, 0);
- test_map.Insert(1, 1);
- QuicMaxSizedMap<int, int>::ConstIterator it = test_map.Begin();
- for (int i = 0; i < 10; ++i, ++it) {
- EXPECT_TRUE(it != test_map.End());
- EXPECT_EQ(i, it->first);
- EXPECT_EQ(i, it->second);
- }
-}
-
-} // namespace test
-} // namespace net
diff --git a/net/quic/congestion_control/receive_algorithm_interface.cc b/net/quic/congestion_control/receive_algorithm_interface.cc
index f5672f8..5384bdc 100644
--- a/net/quic/congestion_control/receive_algorithm_interface.cc
+++ b/net/quic/congestion_control/receive_algorithm_interface.cc
@@ -15,6 +15,9 @@ ReceiveAlgorithmInterface* ReceiveAlgorithmInterface::Create(
switch (type) {
case kTCP:
return new TcpReceiver();
+ case kTCPBBR:
+ LOG(DFATAL) << "TCPBBR is not yet supported.";
+ return NULL;
case kInterArrival:
LOG(DFATAL) << "InterArrivalSendAlgorithm no longer supported.";
return NULL;
diff --git a/net/quic/congestion_control/send_algorithm_interface.cc b/net/quic/congestion_control/send_algorithm_interface.cc
index e5c3329..58b92bc 100644
--- a/net/quic/congestion_control/send_algorithm_interface.cc
+++ b/net/quic/congestion_control/send_algorithm_interface.cc
@@ -29,6 +29,9 @@ SendAlgorithmInterface* SendAlgorithmInterface::Create(
return NULL;
case kFixRate:
return new FixRateSender(rtt_stats);
+ case kTCPBBR:
+ LOG(DFATAL) << "BbrTcpSender is not supported.";
+ return NULL;
}
return NULL;
}
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index 8412a043..12cf8f6 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -51,10 +51,11 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface {
const CongestionMap& acked_packets,
const CongestionMap& lost_packets) = 0;
- // Inform that we sent x bytes to the wire, and if that was a retransmission.
- // Returns true if the packet should be tracked by the congestion manager,
- // false otherwise. This is used by implementations such as tcp_cubic_sender
- // that do not count outgoing ACK packets against the congestion window.
+ // Inform that we sent |bytes| to the wire, and if the packet is
+ // retransmittable. Returns true if the packet should be tracked by the
+ // congestion manager and included in bytes_in_flight, false otherwise.
+ // |bytes_in_flight| is the number of bytes in flight before the packet was
+ // sent.
// Note: this function must be called for every packet sent to the wire.
virtual bool OnPacketSent(QuicTime sent_time,
QuicByteCount bytes_in_flight,
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index 3327bda..12fd997 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -21,9 +21,6 @@
namespace net {
-// Default maximum packet size used in Linux TCP implementations.
-const QuicByteCount kDefaultTCPMSS = 1460;
-
class RttStats;
namespace test {
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index b154970..0dd5606 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -136,9 +136,12 @@ QuicClientSession::QuicClientSession(
scoped_ptr<QuicServerInfo> server_info,
const QuicServerId& server_id,
const QuicConfig& config,
+ uint32 max_flow_control_receive_window_bytes,
QuicCryptoClientConfig* crypto_config,
NetLog* net_log)
- : QuicClientSessionBase(connection, config),
+ : QuicClientSessionBase(connection,
+ max_flow_control_receive_window_bytes,
+ config),
require_confirmation_(false),
stream_factory_(stream_factory),
socket_(socket.Pass()),
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index 94c5c59..35eca5f 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -97,6 +97,7 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicClientSessionBase {
scoped_ptr<QuicServerInfo> server_info,
const QuicServerId& server_id,
const QuicConfig& config,
+ uint32 max_flow_control_receive_window_bytes,
QuicCryptoClientConfig* crypto_config,
NetLog* net_log);
diff --git a/net/quic/quic_client_session_base.cc b/net/quic/quic_client_session_base.cc
index b9cbaff..f735fac 100644
--- a/net/quic/quic_client_session_base.cc
+++ b/net/quic/quic_client_session_base.cc
@@ -6,9 +6,13 @@
namespace net {
-QuicClientSessionBase::QuicClientSessionBase(QuicConnection* connection,
- const QuicConfig& config)
- : QuicSession(connection, config) {}
+QuicClientSessionBase::QuicClientSessionBase(
+ QuicConnection* connection,
+ uint32 max_flow_control_receive_window_bytes,
+ const QuicConfig& config)
+ : QuicSession(connection,
+ max_flow_control_receive_window_bytes,
+ config) {}
QuicClientSessionBase::~QuicClientSessionBase() {}
diff --git a/net/quic/quic_client_session_base.h b/net/quic/quic_client_session_base.h
index eab5d08..007d3ba 100644
--- a/net/quic/quic_client_session_base.h
+++ b/net/quic/quic_client_session_base.h
@@ -14,6 +14,7 @@ namespace net {
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 9e55602..22f8024 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -22,6 +22,7 @@
#include "net/socket/socket_test_util.h"
#include "net/udp/datagram_client_socket.h"
+using net::test::kInitialFlowControlWindowForTest;
using testing::_;
namespace net {
@@ -72,7 +73,8 @@ class QuicClientSessionTest : public ::testing::TestWithParam<QuicVersion> {
make_scoped_ptr((QuicServerInfo*)NULL),
QuicServerId(kServerHostname, kServerPort, false,
PRIVACY_MODE_DISABLED),
- DefaultQuicConfig(), &crypto_config_, &net_log_) {
+ DefaultQuicConfig(), kInitialFlowControlWindowForTest,
+ &crypto_config_, &net_log_) {
session_.config()->SetDefaults();
crypto_config_.SetDefaults();
}
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index be606c2..523ce6e 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -23,7 +23,6 @@
#include "net/quic/quic_bandwidth.h"
#include "net/quic/quic_config.h"
#include "net/quic/quic_flags.h"
-#include "net/quic/quic_flow_controller.h"
#include "net/quic/quic_utils.h"
using base::hash_map;
@@ -193,8 +192,7 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id,
QuicConnectionHelperInterface* helper,
QuicPacketWriter* writer,
bool is_server,
- const QuicVersionVector& supported_versions,
- uint32 max_flow_control_receive_window_bytes)
+ const QuicVersionVector& supported_versions)
: framer_(supported_versions, helper->GetClock()->ApproximateNow(),
is_server),
helper_(helper),
@@ -238,22 +236,7 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id,
peer_ip_changed_(false),
peer_port_changed_(false),
self_ip_changed_(false),
- self_port_changed_(false),
- max_flow_control_receive_window_bytes_(
- max_flow_control_receive_window_bytes) {
- if (max_flow_control_receive_window_bytes_ < kDefaultFlowControlSendWindow) {
- DLOG(ERROR) << "Initial receive window ("
- << max_flow_control_receive_window_bytes_
- << ") cannot be set lower than default ("
- << kDefaultFlowControlSendWindow << ").";
- max_flow_control_receive_window_bytes_ = kDefaultFlowControlSendWindow;
- }
-
- flow_controller_.reset(new QuicFlowController(
- supported_versions.front(), 0, is_server_,
- kDefaultFlowControlSendWindow, max_flow_control_receive_window_bytes_,
- max_flow_control_receive_window_bytes_));
-
+ self_port_changed_(false) {
if (!is_server_) {
// Pacing will be enabled if the client negotiates it.
sent_packet_manager_.MaybeEnablePacing();
@@ -375,10 +358,6 @@ bool QuicConnection::OnProtocolVersionMismatch(QuicVersion received_version) {
// Store the new version.
framer_.set_version(received_version);
- if (received_version < QUIC_VERSION_19) {
- flow_controller_->Disable();
- }
-
// TODO(satyamshekhar): Store the sequence number of this packet and close the
// connection if we ever received a packet with incorrect version and whose
// sequence number is greater.
@@ -494,9 +473,6 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
DCHECK_EQ(header.public_header.versions[0], version());
version_negotiation_state_ = NEGOTIATED_VERSION;
visitor_->OnSuccessfulVersionNegotiation(version());
- if (version() < QUIC_VERSION_19) {
- flow_controller_->Disable();
- }
}
} else {
DCHECK(!header.public_header.version_flag);
@@ -505,9 +481,6 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
packet_creator_.StopSendingVersion();
version_negotiation_state_ = NEGOTIATED_VERSION;
visitor_->OnSuccessfulVersionNegotiation(version());
- if (version() < QUIC_VERSION_19) {
- flow_controller_->Disable();
- }
}
}
@@ -1184,7 +1157,8 @@ void QuicConnection::OnCanWrite() {
// After the visitor writes, it may have caused the socket to become write
// blocked or the congestion manager to prohibit sending, so check again.
- if (visitor_->HasPendingWrites() && !resume_writes_alarm_->IsSet() &&
+ if (visitor_->WillingAndAbleToWrite() &&
+ !resume_writes_alarm_->IsSet() &&
CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA)) {
// We're not write blocked, but some stream didn't write out all of its
// bytes. Register for 'immediate' resumption so we'll keep writing after
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 3e43e9d..8b6e034 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -49,7 +49,6 @@ class QuicConnection;
class QuicDecrypter;
class QuicEncrypter;
class QuicFecGroup;
-class QuicFlowController;
class QuicRandom;
namespace test {
@@ -94,10 +93,12 @@ class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface {
// Called when a blocked socket becomes writable.
virtual void OnCanWrite() = 0;
- // Called to ask if any writes are pending in this visitor. Writes may be
- // pending because they were write-blocked, congestion-throttled or
- // yielded to other connections.
- virtual bool HasPendingWrites() const = 0;
+ // Called to ask if the visitor wants to schedule write resumption as it has
+ // both has pending data to write, and is able to write (e.g. based on flow
+ // control limits).
+ // Writes may be pending because they were write-blocked, congestion-throttled
+ // or yielded to other connections.
+ virtual bool WillingAndAbleToWrite() const = 0;
// Called to ask if any handshake messages are pending in this visitor.
virtual bool HasPendingHandshake() const = 0;
@@ -217,8 +218,7 @@ class NET_EXPORT_PRIVATE QuicConnection
QuicConnectionHelperInterface* helper,
QuicPacketWriter* writer,
bool is_server,
- const QuicVersionVector& supported_versions,
- uint32 max_flow_control_receive_window_bytes);
+ const QuicVersionVector& supported_versions);
virtual ~QuicConnection();
// Sets connection parameters from the supplied |config|.
@@ -267,8 +267,6 @@ class NET_EXPORT_PRIVATE QuicConnection
QuicStreamId last_good_stream_id,
const std::string& reason);
- QuicFlowController* flow_controller() { return flow_controller_.get(); }
-
// Returns statistics tracked for this connection.
const QuicConnectionStats& GetStats();
@@ -460,10 +458,6 @@ class NET_EXPORT_PRIVATE QuicConnection
bool CanWrite(TransmissionType transmission_type,
HasRetransmittableData retransmittable);
- uint32 max_flow_control_receive_window_bytes() const {
- return max_flow_control_receive_window_bytes_;
- }
-
// Stores current batch state for connection, puts the connection
// into batch mode, and destruction restores the stored batch state.
// While the bundler is in scope, any generated frames are bundled
@@ -760,12 +754,6 @@ class NET_EXPORT_PRIVATE QuicConnection
// version negotiation packet.
QuicVersionVector server_supported_versions_;
- // Initial flow control receive window size for new streams.
- uint32 max_flow_control_receive_window_bytes_;
-
- // Used for connection level flow control.
- scoped_ptr<QuicFlowController> flow_controller_;
-
DISALLOW_COPY_AND_ASSIGN(QuicConnection);
};
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index 477cc7e..3dd13e8 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -150,6 +150,10 @@ base::Value* NetLogQuicCongestionFeedbackFrameCallback(
dict->SetString("type", "TCP");
dict->SetInteger("receive_window", frame->tcp.receive_window);
break;
+ case kTCPBBR:
+ dict->SetString("type", "TCPBBR");
+ // TODO(rtenneti): Add support for BBR.
+ break;
}
return dict;
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 6ca7c30..48cb2db 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -419,11 +419,9 @@ class TestConnection : public QuicConnection {
TestConnectionHelper* helper,
TestPacketWriter* writer,
bool is_server,
- QuicVersion version,
- uint32 flow_control_send_window)
+ QuicVersion version)
: QuicConnection(connection_id, address, helper, writer, is_server,
- SupportedVersions(version),
- flow_control_send_window),
+ SupportedVersions(version)),
writer_(writer) {
// Disable tail loss probes for most tests.
QuicSentPacketManagerPeer::SetMaxTailLossProbes(
@@ -588,8 +586,7 @@ class QuicConnectionTest : public ::testing::TestWithParam<QuicVersion> {
helper_(new TestConnectionHelper(&clock_, &random_generator_)),
writer_(new TestPacketWriter(version())),
connection_(connection_id_, IPEndPoint(), helper_.get(),
- writer_.get(), false, version(),
- kDefaultFlowControlSendWindow),
+ writer_.get(), false, version()),
frame1_(1, false, 0, MakeIOVector(data1)),
frame2_(1, false, 3, MakeIOVector(data2)),
sequence_number_length_(PACKET_6BYTE_SEQUENCE_NUMBER),
@@ -613,7 +610,7 @@ class QuicConnectionTest : public ::testing::TestWithParam<QuicVersion> {
Return(kMaxPacketSize));
ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
.WillByDefault(Return(true));
- EXPECT_CALL(visitor_, HasPendingWrites()).Times(AnyNumber());
+ EXPECT_CALL(visitor_, WillingAndAbleToWrite()).Times(AnyNumber());
EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber());
EXPECT_CALL(visitor_, OnCanWrite()).Times(AnyNumber());
EXPECT_CALL(visitor_, HasOpenDataStreams()).WillRepeatedly(Return(false));
@@ -1444,7 +1441,8 @@ TEST_P(QuicConnectionTest, FECSending) {
connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
IN_FEC_GROUP, &payload_length);
// And send FEC every two packets.
- connection_.options()->max_packets_per_fec_group = 2;
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(
+ QuicConnectionPeer::GetPacketCreator(&connection_), 2));
// Send 4 data packets and 2 FEC packets.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6);
@@ -1463,7 +1461,8 @@ TEST_P(QuicConnectionTest, FECQueueing) {
connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
IN_FEC_GROUP, &payload_length);
// And send FEC every two packets.
- connection_.options()->max_packets_per_fec_group = 2;
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(
+ QuicConnectionPeer::GetPacketCreator(&connection_), 2));
EXPECT_EQ(0u, connection_.NumQueuedPackets());
BlockOnNextWrite();
@@ -1475,7 +1474,9 @@ TEST_P(QuicConnectionTest, FECQueueing) {
}
TEST_P(QuicConnectionTest, AbandonFECFromCongestionWindow) {
- connection_.options()->max_packets_per_fec_group = 1;
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(
+ QuicConnectionPeer::GetPacketCreator(&connection_), 1));
+
// 1 Data and 1 FEC packet.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL);
@@ -1493,7 +1494,8 @@ TEST_P(QuicConnectionTest, AbandonFECFromCongestionWindow) {
TEST_P(QuicConnectionTest, DontAbandonAckedFEC) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- connection_.options()->max_packets_per_fec_group = 1;
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(
+ QuicConnectionPeer::GetPacketCreator(&connection_), 1));
// 1 Data and 1 FEC packet.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6);
@@ -1520,7 +1522,8 @@ TEST_P(QuicConnectionTest, DontAbandonAckedFEC) {
TEST_P(QuicConnectionTest, AbandonAllFEC) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- connection_.options()->max_packets_per_fec_group = 1;
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(
+ QuicConnectionPeer::GetPacketCreator(&connection_), 1));
// 1 Data and 1 FEC packet.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6);
@@ -1645,7 +1648,9 @@ TEST_P(QuicConnectionTest, FramePackingFEC) {
return;
}
// Enable fec.
- connection_.options()->max_packets_per_fec_group = 6;
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(
+ QuicConnectionPeer::GetPacketCreator(&connection_), 6));
+
// Block the connection.
connection_.GetSendAlarm()->Set(
clock_.ApproximateNow().Add(QuicTime::Delta::FromSeconds(1)));
@@ -1778,7 +1783,7 @@ TEST_P(QuicConnectionTest, OnCanWrite) {
&TestConnection::SendStreamData3)),
IgnoreResult(InvokeWithoutArgs(&connection_,
&TestConnection::SendStreamData5))));
- EXPECT_CALL(visitor_, HasPendingWrites()).WillOnce(Return(true));
+ EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillOnce(Return(true));
EXPECT_CALL(*send_algorithm_,
TimeUntilSend(_, _, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
@@ -3948,11 +3953,9 @@ TEST_P(QuicConnectionTest, Pacing) {
ValueRestore<bool> old_flag(&FLAGS_enable_quic_pacing, true);
TestConnection server(connection_id_, IPEndPoint(), helper_.get(),
- writer_.get(), true, version(),
- kDefaultFlowControlSendWindow);
+ writer_.get(), true, version());
TestConnection client(connection_id_, IPEndPoint(), helper_.get(),
- writer_.get(), false, version(),
- kDefaultFlowControlSendWindow);
+ writer_.get(), false, version());
EXPECT_TRUE(client.sent_packet_manager().using_pacing());
EXPECT_FALSE(server.sent_packet_manager().using_pacing());
}
@@ -3980,17 +3983,6 @@ TEST_P(QuicConnectionTest, ControlFramesInstigateAcks) {
EXPECT_TRUE(ack_alarm->IsSet());
}
-TEST_P(QuicConnectionTest, InvalidFlowControlWindow) {
- ValueRestore<bool> old_flag(&FLAGS_enable_quic_pacing, true);
-
- const uint32 kSmallerFlowControlWindow = kDefaultFlowControlSendWindow - 1;
- TestConnection connection(connection_id_, IPEndPoint(), helper_.get(),
- writer_.get(), true, version(),
- kSmallerFlowControlWindow);
- EXPECT_EQ(kDefaultFlowControlSendWindow,
- connection.max_flow_control_receive_window_bytes());
-}
-
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 97452f5..d684a49 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -155,7 +155,7 @@ void QuicCryptoClientStream::DoHandshakeLoop(
server_id_,
session()->connection()->connection_id(),
session()->connection()->supported_versions().front(),
- session()->connection()->max_flow_control_receive_window_bytes(),
+ 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 c9ed0ece..62b7795 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -91,6 +91,7 @@ void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
// If we are returning a SHLO then we accepted the handshake.
QuicConfig* config = session()->config();
+ OverrideQuicConfigDefaults(config);
error = config->ProcessPeerHello(message, CLIENT, &error_details);
if (error != QUIC_NO_ERROR) {
CloseConnectionWithDetails(error, error_details);
@@ -172,12 +173,15 @@ QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
session()->connection()->peer_address(),
session()->connection()->version(),
session()->connection()->supported_versions(),
- session()->connection()->max_flow_control_receive_window_bytes(),
+ session()->max_flow_control_receive_window_bytes(),
session()->connection()->clock(),
session()->connection()->random_generator(),
&crypto_negotiated_params_, reply, error_details);
}
+void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {
+}
+
QuicCryptoServerStream::ValidateCallback::ValidateCallback(
QuicCryptoServerStream* parent) : parent_(parent) {
}
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h
index 316ae85..ee40131 100644
--- a/net/quic/quic_crypto_server_stream.h
+++ b/net/quic/quic_crypto_server_stream.h
@@ -51,6 +51,10 @@ class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream {
CryptoHandshakeMessage* reply,
std::string* error_details);
+ // Hook that allows the server to set QuicConfig defaults just
+ // before going through the parameter negotiation step.
+ virtual void OverrideQuicConfigDefaults(QuicConfig* config);
+
private:
friend class test::CryptoTestUtils;
diff --git a/net/quic/quic_data_stream_test.cc b/net/quic/quic_data_stream_test.cc
index b3c0f4c..164e7e4 100644
--- a/net/quic/quic_data_stream_test.cc
+++ b/net/quic/quic_data_stream_test.cc
@@ -30,7 +30,9 @@ namespace net {
namespace test {
namespace {
-const QuicConnectionId kStreamId = 3;
+// First non-reserved client stream ID.
+const QuicStreamId kStreamId = 5;
+
const bool kIsServer = true;
const bool kShouldProcessData = true;
@@ -435,9 +437,9 @@ TEST_P(QuicDataStreamTest, ConnectionFlowControlWindowUpdate) {
kWindow);
QuicFlowControllerPeer::SetMaxReceiveWindow(stream2_->flow_controller(),
kWindow);
- QuicFlowControllerPeer::SetReceiveWindowOffset(connection_->flow_controller(),
+ QuicFlowControllerPeer::SetReceiveWindowOffset(session_->flow_controller(),
kWindow);
- QuicFlowControllerPeer::SetMaxReceiveWindow(connection_->flow_controller(),
+ QuicFlowControllerPeer::SetMaxReceiveWindow(session_->flow_controller(),
kWindow);
// Supply headers to both streams so that they are happy to receive data.
@@ -463,7 +465,7 @@ TEST_P(QuicDataStreamTest, ConnectionFlowControlWindowUpdate) {
EXPECT_CALL(*connection_, SendWindowUpdate(kStreamId + 2, _)).Times(0);
EXPECT_CALL(*connection_,
SendWindowUpdate(0, QuicFlowControllerPeer::ReceiveWindowOffset(
- connection_->flow_controller()) +
+ session_->flow_controller()) +
1 + kWindow / 2));
QuicStreamFrame frame3(kStreamId, false, (kWindow / 4), MakeIOVector("a"));
stream_->OnStreamFrame(frame3);
@@ -518,7 +520,7 @@ TEST_P(QuicDataStreamTest, ConnectionFlowControlViolation) {
const uint64 kConnectionWindow = 10;
QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
kStreamWindow);
- QuicFlowControllerPeer::SetReceiveWindowOffset(connection_->flow_controller(),
+ QuicFlowControllerPeer::SetReceiveWindowOffset(session_->flow_controller(),
kConnectionWindow);
string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc
index 1c83b77..4022073 100644
--- a/net/quic/quic_headers_stream_test.cc
+++ b/net/quic/quic_headers_stream_test.cc
@@ -62,6 +62,12 @@ class MockVisitor : public SpdyFramerVisitorInterface {
SpdyStreamId promised_stream_id,
bool end));
MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end));
+ MOCK_METHOD6(OnAltSvc, void(SpdyStreamId stream_id,
+ uint32 max_age,
+ uint16 port,
+ StringPiece protocol_id,
+ StringPiece host,
+ StringPiece origin));
};
class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> {
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 557e976..206c00d 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -60,7 +60,7 @@ class TestQuicConnection : public QuicConnection {
QuicConnectionHelper* helper,
QuicPacketWriter* writer)
: QuicConnection(connection_id, address, helper, writer, false,
- versions, kInitialFlowControlWindowForTest) {
+ versions) {
}
void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) {
@@ -212,7 +212,9 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> {
make_scoped_ptr((QuicServerInfo*)NULL),
QuicServerId(kServerHostname, kServerPort,
false, PRIVACY_MODE_DISABLED),
- DefaultQuicConfig(), &crypto_config_, NULL));
+ DefaultQuicConfig(),
+ kInitialFlowControlWindowForTest, &crypto_config_,
+ NULL));
session_->GetCryptoStream()->CryptoConnect();
EXPECT_TRUE(session_->IsCryptoHandshakeConfirmed());
stream_.reset(use_closing_stream_ ?
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index 4c57b4b..e567a05 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -64,6 +64,7 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId connection_id,
framer_(framer),
random_bool_source_(new QuicRandomBoolSource(random_generator)),
sequence_number_(0),
+ should_fec_protect_(false),
fec_group_number_(0),
is_server_(is_server),
send_version_in_packet_(!is_server),
@@ -85,12 +86,59 @@ void QuicPacketCreator::OnBuiltFecProtectedPayload(
bool QuicPacketCreator::ShouldSendFec(bool force_close) const {
return fec_group_.get() != NULL && fec_group_->NumReceivedPackets() > 0 &&
- (force_close ||
- fec_group_->NumReceivedPackets() >= options_.max_packets_per_fec_group);
+ (force_close || fec_group_->NumReceivedPackets() >=
+ options_.max_packets_per_fec_group);
}
-InFecGroup QuicPacketCreator::MaybeStartFEC() {
- if (IsFecEnabled() && fec_group_.get() == NULL) {
+void QuicPacketCreator::StartFecProtectingPackets() {
+ if (!IsFecEnabled()) {
+ LOG(DFATAL) << "Cannot start FEC protection when FEC is not enabled.";
+ return;
+ }
+ // TODO(jri): This currently requires that the generator flush out any
+ // pending frames when FEC protection is turned on. If current packet can be
+ // converted to an FEC protected packet, do it. This will require the
+ // generator to check if the resulting expansion still allows the incoming
+ // frame to be added to the packet.
+ if (HasPendingFrames()) {
+ LOG(DFATAL) << "Cannot start FEC protection with pending frames.";
+ return;
+ }
+ DCHECK(!should_fec_protect_);
+ should_fec_protect_ = true;
+}
+
+void QuicPacketCreator::StopFecProtectingPackets() {
+ if (fec_group_.get() != NULL) {
+ LOG(DFATAL) << "Cannot stop FEC protection with open FEC group.";
+ return;
+ }
+ DCHECK(should_fec_protect_);
+ should_fec_protect_ = false;
+ fec_group_number_ = 0;
+}
+
+bool QuicPacketCreator::IsFecProtected() const {
+ return should_fec_protect_;
+}
+
+bool QuicPacketCreator::IsFecEnabled() const {
+ return options_.max_packets_per_fec_group > 0;
+}
+
+size_t QuicPacketCreator::max_packets_per_fec_group() const {
+ return options_.max_packets_per_fec_group;
+}
+
+void QuicPacketCreator::set_max_packets_per_fec_group(
+ size_t max_packets_per_fec_group) {
+ // To turn off FEC protection, use StopFecProtectingPackets().
+ DCHECK_NE(0u, max_packets_per_fec_group);
+ options_.max_packets_per_fec_group = max_packets_per_fec_group;
+}
+
+InFecGroup QuicPacketCreator::MaybeStartFec() {
+ if (should_fec_protect_ && fec_group_.get() == NULL) {
DCHECK(queued_frames_.empty());
// Set the fec group number to the sequence number of the next packet.
fec_group_number_ = sequence_number() + 1;
@@ -134,7 +182,8 @@ bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id,
// QuicPacketCreator.
return BytesFree() >
QuicFramer::GetMinStreamFrameSize(framer_->version(), id, offset, true,
- IsFecEnabled());
+ should_fec_protect_ ? IN_FEC_GROUP :
+ NOT_IN_FEC_GROUP);
}
// static
@@ -159,7 +208,8 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
StreamFramePacketOverhead(
framer_->version(), PACKET_8BYTE_CONNECTION_ID, kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, IN_FEC_GROUP));
- InFecGroup is_in_fec_group = MaybeStartFEC();
+
+ InFecGroup is_in_fec_group = MaybeStartFec();
LOG_IF(DFATAL, !HasRoomForStreamFrame(id, offset))
<< "No room for Stream frame, BytesFree: " << BytesFree()
@@ -210,25 +260,22 @@ size_t QuicPacketCreator::CreateStreamFrameWithNotifier(
SerializedPacket QuicPacketCreator::ReserializeAllFrames(
const QuicFrames& frames,
QuicSequenceNumberLength original_length) {
- const QuicSequenceNumberLength start_length = sequence_number_length_;
- const QuicSequenceNumberLength start_options_length =
+ DCHECK(fec_group_.get() == NULL);
+ const QuicSequenceNumberLength saved_length = sequence_number_length_;
+ const QuicSequenceNumberLength saved_options_length =
options_.send_sequence_number_length;
- const QuicFecGroupNumber start_fec_group = fec_group_number_;
- const size_t start_max_packets_per_fec_group =
- options_.max_packets_per_fec_group;
+ const bool saved_should_fec_protect = should_fec_protect_;
- // Temporarily set the sequence number length and disable FEC.
+ // Temporarily set the sequence number length and stop FEC protection.
sequence_number_length_ = original_length;
options_.send_sequence_number_length = original_length;
- fec_group_number_ = 0;
- options_.max_packets_per_fec_group = 0;
+ should_fec_protect_ = false;
- // Serialize the packet and restore the fec and sequence number length state.
+ // Serialize the packet and restore the FEC and sequence number length state.
SerializedPacket serialized_packet = SerializeAllFrames(frames);
- sequence_number_length_ = start_length;
- options_.send_sequence_number_length = start_options_length;
- fec_group_number_ = start_fec_group;
- options_.max_packets_per_fec_group = start_max_packets_per_fec_group;
+ sequence_number_length_ = saved_length;
+ options_.send_sequence_number_length = saved_options_length;
+ should_fec_protect_ = saved_should_fec_protect;
return serialized_packet;
}
@@ -256,7 +303,7 @@ bool QuicPacketCreator::HasPendingFrames() {
size_t QuicPacketCreator::ExpansionOnNewFrame() const {
// If packet is FEC protected, there's no expansion.
- if (fec_group_.get() != NULL) {
+ if (should_fec_protect_) {
return 0;
}
// If the last frame in the packet is a stream frame, then it will expand to
@@ -274,11 +321,6 @@ size_t QuicPacketCreator::BytesFree() const {
+ ExpansionOnNewFrame());
}
-InFecGroup QuicPacketCreator::IsFecEnabled() const {
- return (options_.max_packets_per_fec_group == 0) ?
- NOT_IN_FEC_GROUP : IN_FEC_GROUP;
-}
-
size_t QuicPacketCreator::PacketSize() const {
if (queued_frames_.empty()) {
// Only adjust the sequence number length when the FEC group is not open,
@@ -290,7 +332,8 @@ size_t QuicPacketCreator::PacketSize() const {
packet_size_ = GetPacketHeaderSize(options_.send_connection_id_length,
send_version_in_packet_,
sequence_number_length_,
- IsFecEnabled());
+ should_fec_protect_ ? IN_FEC_GROUP :
+ NOT_IN_FEC_GROUP);
}
return packet_size_;
}
@@ -302,8 +345,9 @@ bool QuicPacketCreator::AddSavedFrame(const QuicFrame& frame) {
SerializedPacket QuicPacketCreator::SerializePacket() {
LOG_IF(DFATAL, queued_frames_.empty())
<< "Attempt to serialize empty packet";
+ DCHECK_GE(sequence_number_ + 1, fec_group_number_);
QuicPacketHeader header;
- FillPacketHeader(fec_group_number_, false, &header);
+ FillPacketHeader(should_fec_protect_ ? fec_group_number_ : 0, false, &header);
MaybeAddPadding();
@@ -348,7 +392,6 @@ SerializedPacket QuicPacketCreator::SerializeFec() {
fec_data.redundancy = fec_group_->payload_parity();
SerializedPacket serialized = framer_->BuildFecPacket(header, fec_data);
fec_group_.reset(NULL);
- fec_group_number_ = 0;
packet_size_ = 0;
LOG_IF(DFATAL, !serialized.packet)
<< "Failed to serialize fec packet for group:" << fec_data.fec_group;
@@ -407,7 +450,7 @@ bool QuicPacketCreator::ShouldRetransmit(const QuicFrame& frame) {
bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
bool save_retransmittable_frames) {
DVLOG(1) << "Adding frame: " << frame;
- InFecGroup is_in_fec_group = MaybeStartFEC();
+ InFecGroup is_in_fec_group = MaybeStartFec();
size_t frame_len = framer_->GetSerializedFrameLength(
frame, BytesFree(), queued_frames_.empty(), true, is_in_fec_group,
options()->send_sequence_number_length);
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index 95c0847..f8b60ee 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -57,10 +57,27 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
virtual void OnBuiltFecProtectedPayload(const QuicPacketHeader& header,
base::StringPiece payload) OVERRIDE;
+ // Turn on FEC protection for subsequently created packets. FEC should
+ // be enabled first (set_max_packets_per_fec_group should be non-zero) for
+ // FEC protection to start.
+ void StartFecProtectingPackets();
+
+ // Turn off FEC protection for subsequently created packets. If the creator
+ // has any open fec group, call will fail. It is the caller's responsibility
+ // to flush out FEC packets in generation, and to verify with ShouldSendFec()
+ // that there is no open FEC group.
+ void StopFecProtectingPackets();
+
// Checks if it's time to send an FEC packet. |force_close| forces this to
// return true if an fec group is open.
bool ShouldSendFec(bool force_close) const;
+ // Returns current max number of packets covered by an FEC group.
+ size_t max_packets_per_fec_group() const;
+
+ // Sets creator's max number of packets covered by an FEC group.
+ void set_max_packets_per_fec_group(size_t max_packets_per_fec_group);
+
// Makes the framer not serialize the protocol version in sent packets.
void StopSendingVersion();
@@ -109,19 +126,23 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
// Re-serializes frames with the original packet's sequence number length.
// Used for retransmitting packets to ensure they aren't too long.
+ // Caller must ensure that any open FEC group are closed before calling this
+ // method.
SerializedPacket ReserializeAllFrames(
const QuicFrames& frames, QuicSequenceNumberLength original_length);
// Returns true if there are frames pending to be serialized.
bool HasPendingFrames();
- // Returns IN_FEC_GROUP or NOT_IN_FEC_GROUP, depending on whether FEC is
- // enabled or not. Note: This does not mean that an FEC group is currently
- // active; i.e., fec_group_.get() may still be NULL.
- // TODO(jri): Straighten out naming: Enabling FEC for the connection
- // should use FEC_ENABLED/DISABLED, and IN_FEC_GROUP/NOT_IN_FEC_GROUP should
- // be used if a given packet is in an fec group.
- InFecGroup IsFecEnabled() const;
+ // Returns whether FEC protection is currently enabled. Note: Enabled does not
+ // mean that an FEC group is currently active; i.e., IsFecProtected() may
+ // still return NOT_IN_FEC_GROUP, and fec_group_.get() may still be NULL.
+ bool IsFecEnabled() const;
+
+ // Returns true if subsequent packets will be FEC protected. Note: True does
+ // not mean that an FEC packet is currently under construction; i.e.,
+ // fec_group_.get() may still be NULL, until MaybeStartFec() is called.
+ bool IsFecProtected() const;
// Returns the number of bytes which are available to be used by additional
// frames in the packet. Since stream frames are slightly smaller when they
@@ -202,7 +223,7 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
// Starts a new FEC group with the next serialized packet, if FEC is enabled
// and there is not already an FEC group open.
- InFecGroup MaybeStartFEC();
+ InFecGroup MaybeStartFec();
void FillPacketHeader(QuicFecGroupNumber fec_group,
bool fec_flag,
@@ -223,6 +244,8 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
QuicFramer* framer_;
scoped_ptr<QuicRandomBoolSource> random_bool_source_;
QuicPacketSequenceNumber sequence_number_;
+ // If true, any created packets will be FEC protected.
+ bool should_fec_protect_;
QuicFecGroupNumber fec_group_number_;
scoped_ptr<QuicFecGroup> fec_group_;
// bool to keep track if this packet creator is being used the server.
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index 6d0ea5c..72faf7e 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -119,7 +119,6 @@ class QuicPacketCreatorTest : public ::testing::TestWithParam<TestParams> {
return QuicFramer::GetMinStreamFrameSize(
client_framer_.version(), kStreamId, kOffset, true, is_in_fec_group);
}
-
static const QuicStreamId kStreamId = 1u;
static const QuicStreamOffset kOffset = 1u;
@@ -140,7 +139,6 @@ INSTANTIATE_TEST_CASE_P(QuicPacketCreatorTests,
QuicPacketCreatorTest,
::testing::ValuesIn(GetTestParams()));
-
TEST_P(QuicPacketCreatorTest, SerializeFrames) {
frames_.push_back(QuicFrame(new QuicAckFrame(MakeAckFrame(0u, 0u))));
frames_.push_back(QuicFrame(new QuicStreamFrame(0u, false, 0u, IOVector())));
@@ -167,7 +165,8 @@ TEST_P(QuicPacketCreatorTest, SerializeFrames) {
}
TEST_P(QuicPacketCreatorTest, SerializeWithFEC) {
- creator_.options()->max_packets_per_fec_group = 6;
+ // Enable FEC protection, and send FEC packet every 6 packets.
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(&creator_, 6));
// Should return false since we do not have enough packets in the FEC group to
// trigger an FEC packet.
ASSERT_FALSE(creator_.ShouldSendFec(/*force_close=*/false));
@@ -259,7 +258,9 @@ TEST_P(QuicPacketCreatorTest, SerializeWithFECChangingSequenceNumberLength) {
// P1 <change seq num length> P2 FEC,
// and we expect that sequence number length should not change until the end
// of the open FEC group.
- creator_.options()->max_packets_per_fec_group = 6;
+
+ // Enable FEC protection, and send FEC packet every 6 packets.
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(&creator_, 6));
// Should return false since we do not have enough packets in the FEC group to
// trigger an FEC packet.
ASSERT_FALSE(creator_.ShouldSendFec(/*force_close=*/false));
@@ -391,6 +392,83 @@ TEST_P(QuicPacketCreatorTest, SerializeConnectionClose) {
delete serialized.packet;
}
+TEST_P(QuicPacketCreatorTest, SwitchFecOnOffWithNoGroup) {
+ // Enable FEC protection.
+ creator_.set_max_packets_per_fec_group(6);
+ EXPECT_TRUE(creator_.IsFecEnabled());
+ EXPECT_FALSE(creator_.IsFecProtected());
+
+ // Turn on FEC protection.
+ creator_.StartFecProtectingPackets();
+ EXPECT_TRUE(creator_.IsFecProtected());
+ // We have no packets in the FEC group, so no FEC packet can be created.
+ EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/true));
+ // Since no packets are in FEC group yet, we should be able to turn FEC
+ // off with no trouble.
+ creator_.StopFecProtectingPackets();
+ EXPECT_FALSE(creator_.IsFecProtected());
+}
+
+TEST_P(QuicPacketCreatorTest, SwitchFecOnOffWithGroupInProgress) {
+ // Enable FEC protection, and send FEC packet every 6 packets.
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(&creator_, 6));
+ frames_.push_back(QuicFrame(new QuicStreamFrame(0u, false, 0u, IOVector())));
+ SerializedPacket serialized = creator_.SerializeAllFrames(frames_);
+ delete frames_[0].stream_frame;
+ delete serialized.packet;
+
+ EXPECT_TRUE(creator_.IsFecProtected());
+ // We do not have enough packets in the FEC group to trigger an FEC packet.
+ EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/false));
+ // Should return true since there are packets in the FEC group.
+ EXPECT_TRUE(creator_.ShouldSendFec(/*force_close=*/true));
+
+ // Switching FEC off should not change creator state, since there is an
+ // FEC packet under construction.
+ EXPECT_DFATAL(creator_.StopFecProtectingPackets(),
+ "Cannot stop FEC protection with open FEC group.");
+ EXPECT_TRUE(creator_.IsFecProtected());
+ // Confirm that FEC packet is still under construction.
+ EXPECT_TRUE(creator_.ShouldSendFec(/*force_close=*/true));
+
+ serialized = creator_.SerializeFec();
+ delete serialized.packet;
+
+ // Switching FEC on/off should work now.
+ creator_.StopFecProtectingPackets();
+ EXPECT_FALSE(creator_.IsFecProtected());
+ creator_.StartFecProtectingPackets();
+ EXPECT_TRUE(creator_.IsFecProtected());
+}
+
+TEST_P(QuicPacketCreatorTest, SwitchFecOnWithStreamFrameQueued) {
+ // Add a stream frame to the creator.
+ QuicFrame frame;
+ size_t consumed = creator_.CreateStreamFrame(
+ 1u, MakeIOVector("test"), 0u, false, &frame);
+ EXPECT_EQ(4u, consumed);
+ ASSERT_TRUE(frame.stream_frame);
+ EXPECT_TRUE(creator_.AddSavedFrame(frame));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+
+ // Enable FEC protection, and send FEC packet every 6 packets.
+ creator_.set_max_packets_per_fec_group(6);
+ EXPECT_TRUE(creator_.IsFecEnabled());
+ EXPECT_DFATAL(creator_.StartFecProtectingPackets(),
+ "Cannot start FEC protection with pending frames.");
+ EXPECT_FALSE(creator_.IsFecProtected());
+
+ // Serialize packet for transmission.
+ SerializedPacket serialized = creator_.SerializePacket();
+ delete serialized.packet;
+ delete serialized.retransmittable_frames;
+ EXPECT_FALSE(creator_.HasPendingFrames());
+
+ // Since all pending frames have been serialized, turning FEC on should work.
+ creator_.StartFecProtectingPackets();
+ EXPECT_TRUE(creator_.IsFecProtected());
+}
+
TEST_P(QuicPacketCreatorTest, CreateStreamFrame) {
QuicFrame frame;
size_t consumed = creator_.CreateStreamFrame(1u, MakeIOVector("test"), 0u,
@@ -469,8 +547,8 @@ TEST_P(QuicPacketCreatorTest, StreamFrameConsumption) {
}
TEST_P(QuicPacketCreatorTest, StreamFrameConsumptionWithFec) {
- // Turn on FEC protection.
- creator_.options()->max_packets_per_fec_group = 6;
+ // Enable FEC protection, and send FEC packet every 6 packets.
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(&creator_, 6));
// Compute the total overhead for a single frame in packet.
const size_t overhead = GetPacketHeaderOverhead(IN_FEC_GROUP)
+ GetEncryptionOverhead() + GetStreamFrameOverhead(IN_FEC_GROUP);
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index 8bb1dfd..16f9748 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -11,6 +11,7 @@
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/quic_utils.h"
+#include "net/quic/test_tools/quic_packet_creator_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/simple_quic_framer.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -439,7 +440,7 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataFEC) {
delegate_.SetCanWriteAnything();
// Send FEC every two packets.
- creator_.options()->max_packets_per_fec_group = 2;
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(&creator_, 2));
{
InSequence dummy;
@@ -475,8 +476,7 @@ TEST_F(QuicPacketGeneratorTest, ConsumeDataSendsFecAtEnd) {
delegate_.SetCanWriteAnything();
// Send FEC every six packets.
- creator_.options()->max_packets_per_fec_group = 6;
-
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(&creator_, 6));
{
InSequence dummy;
EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 32c5c31..0f92e45 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -525,6 +525,10 @@ ostream& operator<<(ostream& os,
os << " receive_window: " << tcp.receive_window;
break;
}
+ case kTCPBBR: {
+ LOG(DFATAL) << "TCPBBR is not yet supported.";
+ break;
+ }
}
return os;
}
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 1a14201..93236bb 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -57,6 +57,8 @@ const QuicByteCount kDefaultMaxPacketSize = 1200;
// additional 8 bytes. This is a total overhead of 48 bytes. Ethernet's
// max packet size is 1500 bytes, 1500 - 48 = 1452.
const QuicByteCount kMaxPacketSize = 1452;
+// Default maximum packet size used in Linux TCP implementations.
+const QuicByteCount kDefaultTCPMSS = 1460;
// Maximum size of the initial congestion window in packets.
const size_t kDefaultInitialWindow = 10;
@@ -275,7 +277,8 @@ enum QuicVersion {
//
// IMPORTANT: if you are addding to this list, follow the instructions at
// http://sites/quic/adding-and-removing-versions
-static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_18,
+static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_19,
+ QUIC_VERSION_18,
QUIC_VERSION_17,
QUIC_VERSION_16,
QUIC_VERSION_15};
@@ -688,6 +691,7 @@ enum CongestionFeedbackType {
kTCP, // Used to mimic TCP.
kInterArrival, // Use additional inter arrival information.
kFixRate, // Provided for testing.
+ kTCPBBR, // BBR implementation based on TCP congestion feedback.
};
enum LossDetectionType {
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index cffdd4d..d92140a 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -38,6 +38,9 @@ static const size_t kMinHandshakeTimeoutMs = 10;
static const size_t kDefaultMaxTailLossProbes = 2;
static const int64 kMinTailLossProbeTimeoutMs = 10;
+// Number of samples before we force a new recent min rtt to be captured.
+static const size_t kNumMinRttSamplesAfterQuiescence = 2;
+
bool HasCryptoHandshake(const TransmissionInfo& transmission_info) {
if (transmission_info.retransmittable_frames == NULL) {
return false;
@@ -172,7 +175,7 @@ void QuicSentPacketManager::HandleAckForSentPackets(
if (IsAwaitingPacket(received_info, sequence_number)) {
// Remove any packets not being tracked by the send algorithm, allowing
// the high water mark to be raised if necessary.
- if (QuicUnackedPacketMap::IsSentAndNotPending(it->second)) {
+ if (QuicUnackedPacketMap::IsForRttOnly(it->second)) {
it = MarkPacketHandled(sequence_number, delta_largest_observed);
} else {
// Consider it multiple nacks when there is a gap between the missing
@@ -261,10 +264,14 @@ void QuicSentPacketManager::NeuterUnencryptedPackets() {
// they are not retransmitted or considered lost from a congestion control
// perspective.
pending_retransmissions_.erase(it->first);
- // TODO(ianswett): This may cause packets to linger forever in the
- // UnackedPacketMap.
- unacked_packets_.NeuterPacket(it->first);
unacked_packets_.SetNotPending(it->first);
+ // TODO(ianswett): Clean this up so UnackedPacketMap maintains the correct
+ // invariants between the various transmissions for NeuterPacket.
+ SequenceNumberSet all_transmissions = *it->second.all_transmissions;
+ for (SequenceNumberSet::const_iterator all_it = all_transmissions.begin();
+ all_it != all_transmissions.end(); ++all_it) {
+ unacked_packets_.NeuterPacket(*all_it);
+ }
}
}
}
@@ -440,24 +447,25 @@ bool QuicSentPacketManager::OnPacketSent(
return false;
}
- // Only track packets as pending that the send algorithm wants us to track.
- if (!send_algorithm_->OnPacketSent(sent_time,
- unacked_packets_.bytes_in_flight(),
- sequence_number,
- bytes,
- has_retransmittable_data)) {
- unacked_packets_.SetSent(sequence_number, sent_time, bytes, false);
- // Do not reset the retransmission timer, since the packet isn't tracked.
- return false;
+ if (unacked_packets_.bytes_in_flight() == 0) {
+ // TODO(ianswett): Consider being less aggressive to force a new
+ // recent_min_rtt, likely by not discarding a relatively new sample.
+ DVLOG(1) << "Sampling a new recent min rtt within 2 samples. currently:"
+ << rtt_stats_.recent_min_rtt().ToMilliseconds() << "ms";
+ rtt_stats_.SampleNewRecentMinRtt(kNumMinRttSamplesAfterQuiescence);
}
- const bool set_retransmission_timer = !unacked_packets_.HasPendingPackets();
-
- unacked_packets_.SetSent(sequence_number, sent_time, bytes, true);
-
- // Reset the retransmission timer anytime a packet is sent in tail loss probe
- // mode or before the crypto handshake has completed.
- return set_retransmission_timer || GetRetransmissionMode() != RTO_MODE;
+ // Only track packets as pending that the send algorithm wants us to track.
+ const bool pending =
+ send_algorithm_->OnPacketSent(sent_time,
+ unacked_packets_.bytes_in_flight(),
+ sequence_number,
+ bytes,
+ has_retransmittable_data);
+ unacked_packets_.SetSent(sequence_number, sent_time, bytes, pending);
+
+ // Reset the retransmission timer anytime a pending packet is sent.
+ return pending;
}
void QuicSentPacketManager::OnRetransmissionTimeout() {
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index 7d0bfed..aef7c10 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -191,6 +191,7 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
SerializedPacket packet(CreateDataPacket(sequence_number));
packet.retransmittable_frames->AddStreamFrame(
new QuicStreamFrame(1, false, 0, IOVector()));
+ packet.retransmittable_frames->set_encryption_level(ENCRYPTION_NONE);
manager_.OnSerializedPacket(packet);
manager_.OnPacketSent(sequence_number, clock_.ApproximateNow(),
packet.packet->length(), NOT_RETRANSMISSION,
@@ -981,6 +982,41 @@ TEST_F(QuicSentPacketManagerTest,
EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
}
+TEST_F(QuicSentPacketManagerTest,
+ CryptoHandshakeRetransmissionThenNeuterAndAck) {
+ // Send 1 crypto packet.
+ SendCryptoPacket(1);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+
+ // Retransmit the crypto packet as 2.
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(2);
+
+ // Retransmit the crypto packet as 3.
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(3);
+
+ // Now neuter all unacked unencrypted packets, which occurs when the
+ // connection goes forward secure.
+ manager_.NeuterUnencryptedPackets();
+ QuicPacketSequenceNumber unacked[] = { 1, 2, 3};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(NULL, 0);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+ EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+
+ // Ensure both packets get discarded when packet 2 is acked.
+ ReceivedPacketInfo received_info;
+ received_info.largest_observed = 3;
+ received_info.missing_packets.insert(1);
+ received_info.missing_packets.insert(2);
+ ExpectUpdatedRtt(3);
+ manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
+ VerifyUnackedPackets(NULL, 0);
+ VerifyRetransmittablePackets(NULL, 0);
+}
+
TEST_F(QuicSentPacketManagerTest, TailLossProbeTimeoutUnsentDataPacket) {
QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2);
// Serialize two data packets and send the latter.
@@ -998,6 +1034,44 @@ TEST_F(QuicSentPacketManagerTest, TailLossProbeTimeoutUnsentDataPacket) {
EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
}
+TEST_F(QuicSentPacketManagerTest, ResetRecentMinRTTWithEmptyWindow) {
+ QuicTime::Delta min_rtt = QuicTime::Delta::FromMilliseconds(50);
+ QuicSentPacketManagerPeer::GetRttStats(&manager_)->UpdateRtt(
+ min_rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_EQ(min_rtt,
+ QuicSentPacketManagerPeer::GetRttStats(&manager_)->min_rtt());
+ EXPECT_EQ(min_rtt,
+ QuicSentPacketManagerPeer::GetRttStats(
+ &manager_)->recent_min_rtt());
+
+ // Send two packets with no prior bytes in flight.
+ SendDataPacket(1);
+ SendDataPacket(2);
+
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
+ // Ack two packets with 100ms RTT observations.
+ ReceivedPacketInfo received_info;
+ received_info.delta_time_largest_observed = QuicTime::Delta::Zero();
+ received_info.largest_observed = 1;
+ ExpectAck(1);
+ manager_.OnIncomingAck(received_info, clock_.Now());
+
+ // First ack does not change recent min rtt.
+ EXPECT_EQ(min_rtt,
+ QuicSentPacketManagerPeer::GetRttStats(
+ &manager_)->recent_min_rtt());
+
+ received_info.largest_observed = 2;
+ ExpectAck(2);
+ manager_.OnIncomingAck(received_info, clock_.Now());
+
+ EXPECT_EQ(min_rtt,
+ QuicSentPacketManagerPeer::GetRttStats(&manager_)->min_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100),
+ QuicSentPacketManagerPeer::GetRttStats(
+ &manager_)->recent_min_rtt());
+}
+
TEST_F(QuicSentPacketManagerTest, RetransmissionTimeout) {
// Send 100 packets and then ensure all are abandoned when the RTO fires.
const size_t kNumSentPackets = 100;
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 6d749ec..9b28103 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -8,6 +8,7 @@
#include "net/quic/crypto/proof_verifier.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_flags.h"
+#include "net/quic/quic_flow_controller.h"
#include "net/quic/quic_headers_stream.h"
#include "net/ssl/ssl_info.h"
@@ -78,8 +79,8 @@ class VisitorShim : public QuicConnectionVisitorInterface {
session_->OnWriteBlocked();
}
- virtual bool HasPendingWrites() const OVERRIDE {
- return session_->HasPendingWrites();
+ virtual bool WillingAndAbleToWrite() const OVERRIDE {
+ return session_->WillingAndAbleToWrite();
}
virtual bool HasPendingHandshake() const OVERRIDE {
@@ -95,6 +96,7 @@ class VisitorShim : public QuicConnectionVisitorInterface {
};
QuicSession::QuicSession(QuicConnection* connection,
+ uint32 max_flow_control_receive_window_bytes,
const QuicConfig& config)
: connection_(connection),
visitor_shim_(new VisitorShim(this)),
@@ -105,7 +107,20 @@ QuicSession::QuicSession(QuicConnection* connection,
error_(QUIC_NO_ERROR),
goaway_received_(false),
goaway_sent_(false),
- has_pending_handshake_(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;
+ }
+ flow_controller_.reset(new QuicFlowController(
+ connection_->supported_versions().front(), 0, is_server(),
+ kDefaultFlowControlSendWindow, max_flow_control_receive_window_bytes_,
+ max_flow_control_receive_window_bytes_));
connection_->set_visitor(visitor_shim_.get());
connection_->SetFromConfig(config_);
@@ -229,8 +244,7 @@ void QuicSession::OnWindowUpdateFrames(
<< "Received connection level flow control window update with "
"byte offset: " << frames[i].byte_offset;
if (FLAGS_enable_quic_connection_flow_control &&
- connection()->flow_controller()->UpdateSendWindowOffset(
- frames[i].byte_offset)) {
+ flow_controller_->UpdateSendWindowOffset(frames[i].byte_offset)) {
connection_window_updated = true;
}
continue;
@@ -261,9 +275,22 @@ void QuicSession::OnBlockedFrames(const vector<QuicBlockedFrame>& frames) {
void QuicSession::OnCanWrite() {
// We limit the number of writes to the number of pending streams. If more
- // streams become pending, HasPendingWrites will be true, which will cause
- // the connection to request resumption before yielding to other connections.
+ // streams become pending, WillingAndAbleToWrite will be true, which will
+ // cause the connection to request resumption before yielding to other
+ // connections.
size_t num_writes = write_blocked_streams_.NumBlockedStreams();
+ if (flow_controller_->IsBlocked()) {
+ // If we are connection level flow control blocked, then only allow the
+ // crypto and headers streams to try writing as all other streams will be
+ // blocked.
+ num_writes = 0;
+ if (write_blocked_streams_.crypto_stream_blocked()) {
+ num_writes += 1;
+ }
+ if (write_blocked_streams_.headers_stream_blocked()) {
+ num_writes += 1;
+ }
+ }
if (num_writes == 0) {
return;
}
@@ -271,7 +298,8 @@ void QuicSession::OnCanWrite() {
QuicConnection::ScopedPacketBundler ack_bundler(
connection_.get(), QuicConnection::NO_ACK);
for (size_t i = 0; i < num_writes; ++i) {
- if (!write_blocked_streams_.HasWriteBlockedStreams()) {
+ if (!(write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
+ write_blocked_streams_.HasWriteBlockedDataStreams())) {
// Writing one stream removed another!? Something's broken.
LOG(DFATAL) << "WriteBlockedStream is missing";
connection_->CloseConnection(QUIC_INTERNAL_ERROR, false);
@@ -293,8 +321,14 @@ void QuicSession::OnCanWrite() {
}
}
-bool QuicSession::HasPendingWrites() const {
- return write_blocked_streams_.HasWriteBlockedStreams();
+bool QuicSession::WillingAndAbleToWrite() const {
+ // If the crypto or headers streams are blocked, we want to schedule a write -
+ // they don't get blocked by connection level flow control. Otherwise only
+ // schedule a write if we are not flow control blocked at the connection
+ // level.
+ return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
+ (!flow_controller_->IsBlocked() &&
+ write_blocked_streams_.HasWriteBlockedDataStreams());
}
bool QuicSession::HasPendingHandshake() const {
@@ -399,8 +433,7 @@ void QuicSession::OnConfigNegotiated() {
}
// Update connection level window.
- connection()->flow_controller()->UpdateSendWindowOffset(
- new_flow_control_send_window);
+ flow_controller_->UpdateSendWindowOffset(new_flow_control_send_window);
}
}
@@ -591,8 +624,9 @@ void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) {
}
bool QuicSession::HasDataToWrite() const {
- return write_blocked_streams_.HasWriteBlockedStreams() ||
- connection_->HasQueuedData();
+ return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
+ write_blocked_streams_.HasWriteBlockedDataStreams() ||
+ connection_->HasQueuedData();
}
bool QuicSession::GetSSLInfo(SSLInfo* ssl_info) const {
@@ -605,4 +639,10 @@ void QuicSession::PostProcessAfterData() {
closed_streams_.clear();
}
+void QuicSession::OnSuccessfulVersionNegotiation(const QuicVersion& version) {
+ if (version < QUIC_VERSION_19) {
+ flow_controller_->Disable();
+ }
+}
+
} // namespace net
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 2bbd8ba..d23b684 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -25,6 +25,7 @@
namespace net {
class QuicCryptoStream;
+class QuicFlowController;
class ReliableQuicStream;
class SSLInfo;
class VisitorShim;
@@ -53,6 +54,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
};
QuicSession(QuicConnection* connection,
+ uint32 max_flow_control_receive_window_bytes,
const QuicConfig& config);
virtual ~QuicSession();
@@ -69,9 +71,9 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
virtual void OnConnectionClosed(QuicErrorCode error, bool from_peer) OVERRIDE;
virtual void OnWriteBlocked() OVERRIDE {}
virtual void OnSuccessfulVersionNegotiation(
- const QuicVersion& version) OVERRIDE {}
+ const QuicVersion& version) OVERRIDE;
virtual void OnCanWrite() OVERRIDE;
- virtual bool HasPendingWrites() const OVERRIDE;
+ virtual bool WillingAndAbleToWrite() const OVERRIDE;
virtual bool HasPendingHandshake() const OVERRIDE;
virtual bool HasOpenDataStreams() const OVERRIDE;
@@ -201,6 +203,12 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
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:
typedef base::hash_map<QuicStreamId, QuicDataStream*> DataStreamMap;
@@ -295,6 +303,12 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
// Indicate if there is pending data for the crypto stream.
bool has_pending_handshake_;
+ // 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 b2dfa0e..17f53f5 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -17,6 +17,7 @@
#include "net/quic/reliable_quic_stream.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"
#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"
@@ -66,6 +67,15 @@ class TestCryptoStream : public QuicCryptoStream {
MOCK_METHOD0(OnCanWrite, void());
};
+class TestHeadersStream : public QuicHeadersStream {
+ public:
+ explicit TestHeadersStream(QuicSession* session)
+ : QuicHeadersStream(session) {
+ }
+
+ MOCK_METHOD0(OnCanWrite, void());
+};
+
class TestStream : public QuicDataStream {
public:
TestStream(QuicStreamId id, QuicSession* session)
@@ -104,11 +114,12 @@ class StreamBlocker {
class TestSession : public QuicSession {
public:
- explicit TestSession(QuicConnection* connection)
- : QuicSession(connection, DefaultQuicConfig()),
+ explicit TestSession(QuicConnection* connection,
+ uint32 max_initial_flow_control_window)
+ : QuicSession(connection, max_initial_flow_control_window,
+ DefaultQuicConfig()),
crypto_stream_(this),
- writev_consumes_all_data_(false) {
- }
+ writev_consumes_all_data_(false) {}
virtual TestCryptoStream* GetCryptoStream() OVERRIDE {
return &crypto_stream_;
@@ -156,7 +167,7 @@ class TestSession : public QuicSession {
}
private:
- TestCryptoStream crypto_stream_;
+ StrictMock<TestCryptoStream> crypto_stream_;
bool writev_consumes_all_data_;
};
@@ -165,7 +176,7 @@ class QuicSessionTest : public ::testing::TestWithParam<QuicVersion> {
protected:
QuicSessionTest()
: connection_(new MockConnection(true, SupportedVersions(GetParam()))),
- session_(connection_) {
+ session_(connection_, kInitialFlowControlWindowForTest) {
headers_[":host"] = "www.google.com";
headers_[":path"] = "/index.hml";
headers_[":scheme"] = "http";
@@ -349,7 +360,7 @@ TEST_P(QuicSessionTest, OnCanWrite) {
EXPECT_CALL(*stream6, OnCanWrite());
EXPECT_CALL(*stream4, OnCanWrite());
session_.OnCanWrite();
- EXPECT_TRUE(session_.HasPendingWrites());
+ EXPECT_TRUE(session_.WillingAndAbleToWrite());
}
TEST_P(QuicSessionTest, OnCanWriteBundlesStreams) {
@@ -383,7 +394,7 @@ TEST_P(QuicSessionTest, OnCanWriteBundlesStreams) {
Return(WriteResult(WRITE_STATUS_OK, 0)));
EXPECT_CALL(*send_algorithm, OnPacketSent(_, _, _, _, _));
session_.OnCanWrite();
- EXPECT_FALSE(session_.HasPendingWrites());
+ EXPECT_FALSE(session_.WillingAndAbleToWrite());
}
TEST_P(QuicSessionTest, OnCanWriteCongestionControlBlocks) {
@@ -413,13 +424,13 @@ TEST_P(QuicSessionTest, OnCanWriteCongestionControlBlocks) {
// stream4->OnCanWrite is not called.
session_.OnCanWrite();
- EXPECT_TRUE(session_.HasPendingWrites());
+ EXPECT_TRUE(session_.WillingAndAbleToWrite());
// Still congestion-control blocked.
EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillOnce(Return(
QuicTime::Delta::Infinite()));
session_.OnCanWrite();
- EXPECT_TRUE(session_.HasPendingWrites());
+ EXPECT_TRUE(session_.WillingAndAbleToWrite());
// stream4->OnCanWrite is called once the connection stops being
// congestion-control blocked.
@@ -427,7 +438,7 @@ TEST_P(QuicSessionTest, OnCanWriteCongestionControlBlocks) {
QuicTime::Delta::Zero()));
EXPECT_CALL(*stream4, OnCanWrite());
session_.OnCanWrite();
- EXPECT_FALSE(session_.HasPendingWrites());
+ EXPECT_FALSE(session_.WillingAndAbleToWrite());
}
TEST_P(QuicSessionTest, BufferedHandshake) {
@@ -474,7 +485,7 @@ TEST_P(QuicSessionTest, BufferedHandshake) {
InvokeWithoutArgs(&stream4_blocker, &StreamBlocker::MarkWriteBlocked));
session_.OnCanWrite();
- EXPECT_TRUE(session_.HasPendingWrites());
+ EXPECT_TRUE(session_.WillingAndAbleToWrite());
EXPECT_FALSE(session_.HasPendingHandshake()); // Crypto stream wrote.
}
@@ -492,7 +503,40 @@ TEST_P(QuicSessionTest, OnCanWriteWithClosedStream) {
EXPECT_CALL(*stream2, OnCanWrite());
EXPECT_CALL(*stream4, OnCanWrite());
session_.OnCanWrite();
- EXPECT_FALSE(session_.HasPendingWrites());
+ EXPECT_FALSE(session_.WillingAndAbleToWrite());
+}
+
+TEST_P(QuicSessionTest, OnCanWriteLimitsNumWritesIfFlowControlBlocked) {
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control, true);
+ if (version() < QUIC_VERSION_19) {
+ return;
+ }
+
+ // Ensure connection level flow control blockage.
+ QuicFlowControllerPeer::SetSendWindowOffset(session_.flow_controller(), 0);
+ EXPECT_TRUE(session_.flow_controller()->IsBlocked());
+
+ // Mark the crypto and headers streams as write blocked, we expect them to be
+ // allowed to write later.
+ session_.MarkWriteBlocked(kCryptoStreamId, kHighestPriority);
+ session_.MarkWriteBlocked(kHeadersStreamId, kHighestPriority);
+
+ // Create a data stream, and although it is write blocked we never expect it
+ // to be allowed to write as we are connection level flow control blocked.
+ TestStream* stream = session_.CreateOutgoingDataStream();
+ session_.MarkWriteBlocked(stream->id(), kSomeMiddlePriority);
+ EXPECT_CALL(*stream, OnCanWrite()).Times(0);
+
+ // The crypto and headers streams should be called even though we are
+ // connection flow control blocked.
+ TestCryptoStream* crypto_stream = session_.GetCryptoStream();
+ EXPECT_CALL(*crypto_stream, OnCanWrite()).Times(1);
+ TestHeadersStream* headers_stream = new TestHeadersStream(&session_);
+ QuicSessionPeer::SetHeadersStream(&session_, headers_stream);
+ EXPECT_CALL(*headers_stream, OnCanWrite()).Times(1);
+
+ session_.OnCanWrite();
+ EXPECT_FALSE(session_.WillingAndAbleToWrite());
}
TEST_P(QuicSessionTest, SendGoAway) {
@@ -617,6 +661,17 @@ TEST_P(QuicSessionTest, InvalidFlowControlWindowInHandshake) {
session_.OnConfigNegotiated();
}
+TEST_P(QuicSessionTest, InvalidFlowControlWindow) {
+ 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());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 310f93e..b94b19b 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -736,7 +736,7 @@ int QuicStreamFactory::CreateSession(
QuicConnection* connection =
new QuicConnection(connection_id, addr, helper_.get(), writer.get(),
- false, supported_versions_, kInitialReceiveWindowSize);
+ false, supported_versions_);
writer->SetConnection(connection);
connection->options()->max_packet_length = max_packet_length_;
@@ -755,7 +755,7 @@ int QuicStreamFactory::CreateSession(
*session = new QuicClientSession(
connection, socket.Pass(), writer.Pass(), this,
quic_crypto_client_stream_factory_, server_info.Pass(), server_id,
- config, &crypto_config_, net_log.net_log());
+ config, kInitialReceiveWindowSize, &crypto_config_, net_log.net_log());
all_sessions_[*session] = server_id; // owning pointer
return OK;
}
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc
index a21d4a5..a8fe3b5 100644
--- a/net/quic/quic_unacked_packet_map.cc
+++ b/net/quic/quic_unacked_packet_map.cc
@@ -166,11 +166,11 @@ void QuicUnackedPacketMap::MaybeRemoveRetransmittableFrames(
}
// static
-bool QuicUnackedPacketMap::IsSentAndNotPending(
+bool QuicUnackedPacketMap::IsForRttOnly(
const TransmissionInfo& transmission_info) {
return !transmission_info.pending &&
- transmission_info.sent_time != QuicTime::Zero() &&
- transmission_info.bytes_sent == 0;
+ transmission_info.retransmittable_frames == NULL &&
+ transmission_info.all_transmissions->size() == 1;
}
bool QuicUnackedPacketMap::IsUnacked(
@@ -198,13 +198,7 @@ bool QuicUnackedPacketMap::HasUnackedPackets() const {
}
bool QuicUnackedPacketMap::HasPendingPackets() const {
- for (UnackedPacketMap::const_reverse_iterator it =
- unacked_packets_.rbegin(); it != unacked_packets_.rend(); ++it) {
- if (it->second.pending) {
- return true;
- }
- }
- return false;
+ return bytes_in_flight_ > 0;
}
const TransmissionInfo& QuicUnackedPacketMap::GetTransmissionInfo(
@@ -271,17 +265,6 @@ bool QuicUnackedPacketMap::HasUnackedRetransmittableFrames() const {
return false;
}
-size_t QuicUnackedPacketMap::GetNumRetransmittablePackets() const {
- size_t num_unacked_packets = 0;
- for (UnackedPacketMap::const_iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it) {
- if (it->second.retransmittable_frames != NULL) {
- ++num_unacked_packets;
- }
- }
- return num_unacked_packets;
-}
-
QuicPacketSequenceNumber
QuicUnackedPacketMap::GetLeastUnackedSentPacket() const {
if (unacked_packets_.empty()) {
diff --git a/net/quic/quic_unacked_packet_map.h b/net/quic/quic_unacked_packet_map.h
index 759bd7b..12a96a2 100644
--- a/net/quic/quic_unacked_packet_map.h
+++ b/net/quic/quic_unacked_packet_map.h
@@ -52,9 +52,6 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
// frames.
bool HasUnackedRetransmittableFrames() const;
- // Returns the number of unacked packets which have retransmittable frames.
- size_t GetNumRetransmittablePackets() const;
-
// Returns the largest sequence number that has been sent.
QuicPacketSequenceNumber largest_sent_packet() const {
return largest_sent_packet_;
@@ -122,8 +119,10 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
// frames, and sets all_transmissions to only include itself.
void NeuterPacket(QuicPacketSequenceNumber sequence_number);
- // Returns true if the packet has been marked as sent by SetSent.
- static bool IsSentAndNotPending(const TransmissionInfo& transmission_info);
+ // Returns true if the packet's only purpose is to measure RTT. It must not
+ // be pending, have retransmittable frames, or be linked to transmissions
+ // with retransmittable frames.
+ static bool IsForRttOnly(const TransmissionInfo& transmission_info);
private:
void MaybeRemoveRetransmittableFrames(TransmissionInfo* transmission_info);
diff --git a/net/quic/quic_write_blocked_list.h b/net/quic/quic_write_blocked_list.h
index cddd58f..6727fb4 100644
--- a/net/quic/quic_write_blocked_list.h
+++ b/net/quic/quic_write_blocked_list.h
@@ -27,10 +27,12 @@ class NET_EXPORT_PRIVATE QuicWriteBlockedList {
QuicWriteBlockedList();
~QuicWriteBlockedList();
- bool HasWriteBlockedStreams() const {
- return crypto_stream_blocked_ ||
- headers_stream_blocked_ ||
- base_write_blocked_list_.HasWriteBlockedStreams();
+ bool HasWriteBlockedDataStreams() const {
+ return base_write_blocked_list_.HasWriteBlockedStreams();
+ }
+
+ bool HasWriteBlockedCryptoOrHeadersStream() const {
+ return crypto_stream_blocked_ || headers_stream_blocked_;
}
size_t NumBlockedStreams() const {
@@ -89,6 +91,9 @@ class NET_EXPORT_PRIVATE QuicWriteBlockedList {
return;
}
+ bool crypto_stream_blocked() const { return crypto_stream_blocked_; }
+ bool headers_stream_blocked() const { return headers_stream_blocked_; }
+
private:
QuicWriteBlockedListBase base_write_blocked_list_;
bool crypto_stream_blocked_;
diff --git a/net/quic/quic_write_blocked_list_test.cc b/net/quic/quic_write_blocked_list_test.cc
index 6f6bba6..1643bc3 100644
--- a/net/quic/quic_write_blocked_list_test.cc
+++ b/net/quic/quic_write_blocked_list_test.cc
@@ -27,7 +27,8 @@ TEST(QuicWriteBlockedListTest, PriorityOrder) {
QuicWriteBlockedList::kHighestPriority);
EXPECT_EQ(5u, write_blocked_list.NumBlockedStreams());
- EXPECT_TRUE(write_blocked_list.HasWriteBlockedStreams());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams());
// The Crypto stream is highest priority.
EXPECT_EQ(kCryptoStreamId, write_blocked_list.PopFront());
// Followed by the Headers stream.
@@ -39,7 +40,8 @@ TEST(QuicWriteBlockedListTest, PriorityOrder) {
EXPECT_EQ(40u, write_blocked_list.PopFront());
EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
- EXPECT_FALSE(write_blocked_list.HasWriteBlockedStreams());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams());
}
TEST(QuicWriteBlockedListTest, CryptoStream) {
@@ -48,10 +50,10 @@ TEST(QuicWriteBlockedListTest, CryptoStream) {
QuicWriteBlockedList::kHighestPriority);
EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams());
- EXPECT_TRUE(write_blocked_list.HasWriteBlockedStreams());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
EXPECT_EQ(kCryptoStreamId, write_blocked_list.PopFront());
EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
- EXPECT_FALSE(write_blocked_list.HasWriteBlockedStreams());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
}
TEST(QuicWriteBlockedListTest, HeadersStream) {
@@ -60,10 +62,10 @@ TEST(QuicWriteBlockedListTest, HeadersStream) {
QuicWriteBlockedList::kHighestPriority);
EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams());
- EXPECT_TRUE(write_blocked_list.HasWriteBlockedStreams());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront());
EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
- EXPECT_FALSE(write_blocked_list.HasWriteBlockedStreams());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
}
TEST(QuicWriteBlockedListTest, VerifyHeadersStream) {
@@ -74,13 +76,15 @@ TEST(QuicWriteBlockedListTest, VerifyHeadersStream) {
QuicWriteBlockedList::kHighestPriority);
EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams());
- EXPECT_TRUE(write_blocked_list.HasWriteBlockedStreams());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams());
// In newer QUIC versions, there is a headers stream which is
// higher priority than data streams.
EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront());
EXPECT_EQ(5u, write_blocked_list.PopFront());
EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
- EXPECT_FALSE(write_blocked_list.HasWriteBlockedStreams());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams());
}
TEST(QuicWriteBlockedListTest, NoDuplicateEntries) {
@@ -99,12 +103,12 @@ TEST(QuicWriteBlockedListTest, NoDuplicateEntries) {
// This should only result in one blocked stream being added.
EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams());
- EXPECT_TRUE(write_blocked_list.HasWriteBlockedStreams());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams());
// There should only be one stream to pop off the front.
EXPECT_EQ(kBlockedId, write_blocked_list.PopFront());
EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
- EXPECT_FALSE(write_blocked_list.HasWriteBlockedStreams());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams());
}
} // namespace
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index 218bb09..aefdb41 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -130,9 +130,9 @@ ReliableQuicStream::ReliableQuicStream(QuicStreamId id, QuicSession* session)
session_->config()->HasReceivedInitialFlowControlWindowBytes() ?
session_->config()->ReceivedInitialFlowControlWindowBytes() :
kDefaultFlowControlSendWindow,
- session_->connection()->max_flow_control_receive_window_bytes(),
- session_->connection()->max_flow_control_receive_window_bytes()),
- connection_flow_controller_(session_->connection()->flow_controller()) {
+ session_->max_flow_control_receive_window_bytes(),
+ session_->max_flow_control_receive_window_bytes()),
+ connection_flow_controller_(session_->flow_controller()) {
}
ReliableQuicStream::~ReliableQuicStream() {
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index d1ad909..48e8616 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -37,7 +37,7 @@ namespace {
const char kData1[] = "FooAndBar";
const char kData2[] = "EepAndBaz";
const size_t kDataLen = 9;
-const QuicConnectionId kStreamId = 3;
+const QuicStreamId kStreamId = 3;
const bool kIsServer = true;
const bool kShouldProcessData = true;
@@ -134,6 +134,11 @@ class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> {
initial_flow_control_window_bytes_ = val;
}
+ bool HasWriteBlockedStreams() {
+ return write_blocked_list_->HasWriteBlockedCryptoOrHeadersStream() ||
+ write_blocked_list_->HasWriteBlockedDataStreams();
+ }
+
protected:
MockConnection* connection_;
scoped_ptr<MockSession> session_;
@@ -156,7 +161,7 @@ TEST_F(ReliableQuicStreamTest, WriteAllData) {
EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
Return(QuicConsumedData(kDataLen, true)));
stream_->WriteOrBufferData(kData1, false, NULL);
- EXPECT_FALSE(write_blocked_list_->HasWriteBlockedStreams());
+ EXPECT_FALSE(HasWriteBlockedStreams());
}
TEST_F(ReliableQuicStreamTest, NoBlockingIfNoDataOrFin) {
@@ -165,7 +170,7 @@ TEST_F(ReliableQuicStreamTest, NoBlockingIfNoDataOrFin) {
// Write no data and no fin. If we consume nothing we should not be write
// blocked.
EXPECT_DFATAL(stream_->WriteOrBufferData(StringPiece(), false, NULL), "");
- EXPECT_FALSE(write_blocked_list_->HasWriteBlockedStreams());
+ EXPECT_FALSE(HasWriteBlockedStreams());
}
TEST_F(ReliableQuicStreamTest, BlockIfOnlySomeDataConsumed) {
@@ -179,7 +184,6 @@ TEST_F(ReliableQuicStreamTest, BlockIfOnlySomeDataConsumed) {
ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
}
-
TEST_F(ReliableQuicStreamTest, BlockIfFinNotConsumedWithData) {
Initialize(kShouldProcessData);
@@ -207,7 +211,7 @@ TEST_F(ReliableQuicStreamTest, BlockIfSoloFinNotConsumed) {
TEST_F(ReliableQuicStreamTest, WriteOrBufferData) {
Initialize(kShouldProcessData);
- EXPECT_FALSE(write_blocked_list_->HasWriteBlockedStreams());
+ EXPECT_FALSE(HasWriteBlockedStreams());
connection_->options()->max_packet_length =
1 + QuicPacketCreator::StreamFramePacketOverhead(
connection_->version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
@@ -215,7 +219,7 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferData) {
EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).WillOnce(
Return(QuicConsumedData(kDataLen - 1, false)));
stream_->WriteOrBufferData(kData1, false, NULL);
- EXPECT_TRUE(write_blocked_list_->HasWriteBlockedStreams());
+ EXPECT_TRUE(HasWriteBlockedStreams());
// Queue a bytes_consumed write.
stream_->WriteOrBufferData(kData2, false, NULL);
@@ -395,7 +399,7 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithQuicAckNotifier) {
// Set a large flow control send window so this doesn't interfere with test.
stream_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
if (FLAGS_enable_quic_connection_flow_control) {
- connection_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
+ session_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
}
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
@@ -405,7 +409,7 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithQuicAckNotifier) {
&SaveProxyAckNotifierDelegate, &proxy_delegate))),
Return(QuicConsumedData(kFirstWriteSize, false))));
stream_->WriteOrBufferData(kData, false, delegate.get());
- EXPECT_TRUE(write_blocked_list_->HasWriteBlockedStreams());
+ EXPECT_TRUE(HasWriteBlockedStreams());
EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, proxy_delegate.get())).
WillOnce(
@@ -450,7 +454,7 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataAckNotificationBeforeFlush) {
// Set a large flow control send window so this doesn't interfere with test.
stream_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
if (FLAGS_enable_quic_connection_flow_control) {
- connection_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
+ session_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
}
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
@@ -460,7 +464,7 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferDataAckNotificationBeforeFlush) {
&SaveProxyAckNotifierDelegate, &proxy_delegate))),
Return(QuicConsumedData(kInitialWriteSize, false))));
stream_->WriteOrBufferData(kData, false, delegate.get());
- EXPECT_TRUE(write_blocked_list_->HasWriteBlockedStreams());
+ EXPECT_TRUE(HasWriteBlockedStreams());
// Handle the ack of the first write.
proxy_delegate->OnAckNotification(1, 2, 3, 4, zero_);
@@ -491,7 +495,7 @@ TEST_F(ReliableQuicStreamTest, WriteAndBufferDataWithAckNotiferNoBuffer) {
&SaveProxyAckNotifierDelegate, &proxy_delegate))),
Return(QuicConsumedData(kDataLen, true))));
stream_->WriteOrBufferData(kData1, true, delegate.get());
- EXPECT_FALSE(write_blocked_list_->HasWriteBlockedStreams());
+ EXPECT_FALSE(HasWriteBlockedStreams());
// Handle the ack.
EXPECT_CALL(*delegate, OnAckNotification(1, 2, 3, 4, zero_));
@@ -510,7 +514,7 @@ TEST_F(ReliableQuicStreamTest, BufferOnWriteAndBufferDataWithAckNotifer) {
EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
Return(QuicConsumedData(0, false)));
stream_->WriteOrBufferData(kData1, true, delegate.get());
- EXPECT_TRUE(write_blocked_list_->HasWriteBlockedStreams());
+ EXPECT_TRUE(HasWriteBlockedStreams());
EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(DoAll(
WithArgs<4>(Invoke(CreateFunctor(
@@ -538,7 +542,7 @@ TEST_F(ReliableQuicStreamTest, WriteAndBufferDataWithAckNotiferOnlyFinRemains) {
&SaveProxyAckNotifierDelegate, &proxy_delegate))),
Return(QuicConsumedData(kDataLen, false))));
stream_->WriteOrBufferData(kData1, true, delegate.get());
- EXPECT_TRUE(write_blocked_list_->HasWriteBlockedStreams());
+ EXPECT_TRUE(HasWriteBlockedStreams());
EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(DoAll(
WithArgs<4>(Invoke(CreateFunctor(
diff --git a/net/quic/test_tools/quic_packet_creator_peer.cc b/net/quic/test_tools/quic_packet_creator_peer.cc
index 1acdf24..07658e5 100644
--- a/net/quic/test_tools/quic_packet_creator_peer.cc
+++ b/net/quic/test_tools/quic_packet_creator_peer.cc
@@ -39,5 +39,13 @@ void QuicPacketCreatorPeer::SetIsServer(QuicPacketCreator* creator,
creator->is_server_ = is_server;
}
+// static
+bool QuicPacketCreatorPeer::SwitchFecProtectionOn(
+ QuicPacketCreator* creator, size_t max_packets_per_fec_group) {
+ creator->set_max_packets_per_fec_group(max_packets_per_fec_group);
+ creator->StartFecProtectingPackets();
+ return creator->IsFecProtected();
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/quic_packet_creator_peer.h b/net/quic/test_tools/quic_packet_creator_peer.h
index 12ae676..95002a8 100644
--- a/net/quic/test_tools/quic_packet_creator_peer.h
+++ b/net/quic/test_tools/quic_packet_creator_peer.h
@@ -26,6 +26,9 @@ class QuicPacketCreatorPeer {
static void SetIsServer(QuicPacketCreator* creator, bool is_server);
+ static bool SwitchFecProtectionOn(QuicPacketCreator* creator,
+ size_t max_packets_per_fec_group);
+
private:
DISALLOW_COPY_AND_ASSIGN(QuicPacketCreatorPeer);
};
diff --git a/net/quic/test_tools/quic_sent_packet_manager_peer.cc b/net/quic/test_tools/quic_sent_packet_manager_peer.cc
index 7f72615..db1a26d 100644
--- a/net/quic/test_tools/quic_sent_packet_manager_peer.cc
+++ b/net/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -109,7 +109,15 @@ bool QuicSentPacketManagerPeer::HasUnackedCryptoPackets(
// static
size_t QuicSentPacketManagerPeer::GetNumRetransmittablePackets(
const QuicSentPacketManager* sent_packet_manager) {
- return sent_packet_manager->unacked_packets_.GetNumRetransmittablePackets();
+ size_t num_unacked_packets = 0;
+ for (QuicUnackedPacketMap::const_iterator it =
+ sent_packet_manager->unacked_packets_.begin();
+ it != sent_packet_manager->unacked_packets_.end(); ++it) {
+ if (it->second.retransmittable_frames != NULL) {
+ ++num_unacked_packets;
+ }
+ }
+ return num_unacked_packets;
}
// static
diff --git a/net/quic/test_tools/quic_session_peer.cc b/net/quic/test_tools/quic_session_peer.cc
index 080643b..a46b6fe 100644
--- a/net/quic/test_tools/quic_session_peer.cc
+++ b/net/quic/test_tools/quic_session_peer.cc
@@ -27,6 +27,12 @@ QuicHeadersStream* QuicSessionPeer::GetHeadersStream(QuicSession* session) {
}
// static
+void QuicSessionPeer::SetHeadersStream(QuicSession* session,
+ QuicHeadersStream* headers_stream) {
+ session->headers_stream_.reset(headers_stream);
+}
+
+// static
QuicWriteBlockedList* QuicSessionPeer::GetWriteblockedStreams(
QuicSession* session) {
return &session->write_blocked_streams_;
diff --git a/net/quic/test_tools/quic_session_peer.h b/net/quic/test_tools/quic_session_peer.h
index d8f1c75..ef9fef7 100644
--- a/net/quic/test_tools/quic_session_peer.h
+++ b/net/quic/test_tools/quic_session_peer.h
@@ -21,6 +21,8 @@ class QuicSessionPeer {
static void SetNextStreamId(QuicSession* session, QuicStreamId id);
static void SetMaxOpenStreams(QuicSession* session, uint32 max_streams);
static QuicHeadersStream* GetHeadersStream(QuicSession* session);
+ static void SetHeadersStream(QuicSession* session,
+ QuicHeadersStream* headers_stream);
static QuicWriteBlockedList* GetWriteblockedStreams(QuicSession* session);
static QuicDataStream* GetIncomingDataStream(QuicSession* session,
QuicStreamId stream_id);
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 5e4d7f5..f14dd73 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -191,8 +191,7 @@ MockConnection::MockConnection(bool is_server)
IPEndPoint(TestPeerIPAddress(), kTestPort),
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
- is_server, QuicSupportedVersions(),
- kInitialFlowControlWindowForTest),
+ is_server, QuicSupportedVersions()),
writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
@@ -202,8 +201,7 @@ MockConnection::MockConnection(IPEndPoint address,
: QuicConnection(kTestConnectionId, address,
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
- is_server, QuicSupportedVersions(),
- kInitialFlowControlWindowForTest),
+ is_server, QuicSupportedVersions()),
writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
@@ -214,8 +212,7 @@ MockConnection::MockConnection(QuicConnectionId connection_id,
IPEndPoint(TestPeerIPAddress(), kTestPort),
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
- is_server, QuicSupportedVersions(),
- kInitialFlowControlWindowForTest),
+ is_server, QuicSupportedVersions()),
writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
@@ -226,8 +223,7 @@ MockConnection::MockConnection(bool is_server,
IPEndPoint(TestPeerIPAddress(), kTestPort),
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
- is_server, supported_versions,
- kInitialFlowControlWindowForTest),
+ is_server, supported_versions),
writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
@@ -266,7 +262,8 @@ bool PacketSavingConnection::SendOrQueuePacket(
}
MockSession::MockSession(QuicConnection* connection)
- : QuicSession(connection, DefaultQuicConfig()) {
+ : QuicSession(connection, kInitialFlowControlWindowForTest,
+ DefaultQuicConfig()) {
ON_CALL(*this, WritevData(_, _, _, _, _))
.WillByDefault(testing::Return(QuicConsumedData(0, false)));
}
@@ -274,11 +271,9 @@ MockSession::MockSession(QuicConnection* connection)
MockSession::~MockSession() {
}
-TestSession::TestSession(QuicConnection* connection,
- const QuicConfig& config)
- : QuicSession(connection, config),
- crypto_stream_(NULL) {
-}
+TestSession::TestSession(QuicConnection* connection, const QuicConfig& config)
+ : QuicSession(connection, kInitialFlowControlWindowForTest, config),
+ crypto_stream_(NULL) {}
TestSession::~TestSession() {}
@@ -292,7 +287,8 @@ QuicCryptoStream* TestSession::GetCryptoStream() {
TestClientSession::TestClientSession(QuicConnection* connection,
const QuicConfig& config)
- : QuicClientSessionBase(connection, config),
+ : QuicClientSessionBase(connection, kInitialFlowControlWindowForTest,
+ config),
crypto_stream_(NULL) {
EXPECT_CALL(*this, OnProofValid(_)).Times(AnyNumber());
}
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 4582a0e..6901824 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -194,7 +194,7 @@ class MockConnectionVisitor : public QuicConnectionVisitorInterface {
MOCK_METHOD2(OnConnectionClosed, void(QuicErrorCode error, bool from_peer));
MOCK_METHOD0(OnWriteBlocked, void());
MOCK_METHOD0(OnCanWrite, void());
- MOCK_CONST_METHOD0(HasPendingWrites, bool());
+ MOCK_CONST_METHOD0(WillingAndAbleToWrite, bool());
MOCK_CONST_METHOD0(HasPendingHandshake, bool());
MOCK_CONST_METHOD0(HasOpenDataStreams, bool());
MOCK_METHOD1(OnSuccessfulVersionNegotiation,
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index cf56826..8d04535 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_packet_creator_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,6 +51,7 @@ using base::WaitableEvent;
using net::EpollServer;
using net::test::GenerateBody;
using net::test::QuicConnectionPeer;
+using net::test::QuicPacketCreatorPeer;
using net::test::QuicSessionPeer;
using net::test::ReliableQuicStreamPeer;
using net::tools::test::PacketDroppingTestWriter;
@@ -644,7 +646,10 @@ TEST_P(EndToEndTest, LargePostFEC) {
client_->client()->WaitForCryptoHandshakeConfirmed();
SetPacketLossPercentage(30);
- client_->options()->max_packets_per_fec_group = 6;
+ // Turn on FEC protection.
+ QuicPacketCreator* creator = QuicConnectionPeer::GetPacketCreator(
+ client_->client()->session()->connection());
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(creator, 6));
string body;
GenerateBody(&body, 10240);
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index cb2b408..6935238 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -189,8 +189,8 @@ bool QuicClient::StartConnect() {
server_id_,
config_,
new QuicConnection(GenerateConnectionId(), server_address_, helper_.get(),
- writer_.get(), false, supported_versions_,
- initial_flow_control_window_),
+ writer_.get(), false, supported_versions_),
+ initial_flow_control_window_,
&crypto_config_));
return session_->CryptoConnect();
}
@@ -218,6 +218,7 @@ void QuicClient::SendRequestsAndWaitForResponse(
BalsaHeaders headers;
headers.SetRequestFirstlineFromStringPieces("GET", args[i], "HTTP/1.1");
QuicSpdyClientStream* stream = CreateReliableClientStream();
+ DCHECK(stream != NULL);
stream->SendRequest(headers, "", true);
stream->set_visitor(this);
}
@@ -236,7 +237,7 @@ QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
void QuicClient::WaitForStreamToClose(QuicStreamId id) {
DCHECK(connected());
- while (!session_->IsClosedStream(id)) {
+ while (connected() && !session_->IsClosedStream(id)) {
epoll_server_.WaitForEventsAndExecuteCallbacks();
}
}
@@ -244,7 +245,7 @@ void QuicClient::WaitForStreamToClose(QuicStreamId id) {
void QuicClient::WaitForCryptoHandshakeConfirmed() {
DCHECK(connected());
- while (!session_->IsCryptoHandshakeConfirmed()) {
+ while (connected() && !session_->IsCryptoHandshakeConfirmed()) {
epoll_server_.WaitForEventsAndExecuteCallbacks();
}
}
diff --git a/net/tools/quic/quic_client_session.cc b/net/tools/quic/quic_client_session.cc
index aca5418..c8e28db 100644
--- a/net/tools/quic/quic_client_session.cc
+++ b/net/tools/quic/quic_client_session.cc
@@ -18,8 +18,11 @@ QuicClientSession::QuicClientSession(
const QuicServerId& server_id,
const QuicConfig& config,
QuicConnection* connection,
+ uint32 max_flow_control_receive_window_bytes,
QuicCryptoClientConfig* crypto_config)
- : QuicClientSessionBase(connection, config),
+ : QuicClientSessionBase(connection,
+ max_flow_control_receive_window_bytes,
+ 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 3aad445..d04b420 100644
--- a/net/tools/quic/quic_client_session.h
+++ b/net/tools/quic/quic_client_session.h
@@ -28,6 +28,7 @@ class QuicClientSession : public QuicClientSessionBase {
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 7b50f42..983106d 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -15,6 +15,7 @@
using net::test::CryptoTestUtils;
using net::test::DefaultQuicConfig;
+using net::test::kInitialFlowControlWindowForTest;
using net::test::PacketSavingConnection;
using net::test::SupportedVersions;
using testing::_;
@@ -38,6 +39,7 @@ class ToolsQuicClientSessionTest
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 b074a5d..df9b9c6 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -382,8 +382,8 @@ QuicSession* QuicDispatcher::CreateQuicSession(
config_,
CreateQuicConnection(connection_id,
server_address,
- client_address,
- initial_flow_control_window_bytes_),
+ client_address),
+ initial_flow_control_window_bytes_,
this);
session->InitializeSession(crypto_config_);
return session;
@@ -392,14 +392,12 @@ QuicSession* QuicDispatcher::CreateQuicSession(
QuicConnection* QuicDispatcher::CreateQuicConnection(
QuicConnectionId connection_id,
const IPEndPoint& server_address,
- const IPEndPoint& client_address,
- uint32 initial_flow_control_window) {
+ const IPEndPoint& client_address) {
if (FLAGS_enable_quic_stream_flow_control_2 &&
FLAGS_enable_quic_connection_flow_control) {
DLOG(INFO) << "Creating QuicDispatcher with all versions.";
return new QuicConnection(connection_id, client_address, helper_.get(),
- writer_.get(), true, supported_versions_,
- initial_flow_control_window_bytes_);
+ writer_.get(), true, supported_versions_);
}
if (FLAGS_enable_quic_stream_flow_control_2 &&
@@ -408,15 +406,14 @@ QuicConnection* QuicDispatcher::CreateQuicConnection(
<< "WITHOUT version 19 or higher.";
return new QuicConnection(connection_id, client_address, helper_.get(),
writer_.get(), true,
- supported_versions_no_connection_flow_control_,
- initial_flow_control_window_bytes_);
+ supported_versions_no_connection_flow_control_);
}
DLOG(INFO) << "Flow control disabled, creating QuicDispatcher WITHOUT "
<< "version 17 or higher.";
- return new QuicConnection(
- connection_id, client_address, helper_.get(), writer_.get(), true,
- supported_versions_no_flow_control_, initial_flow_control_window_bytes_);
+ return new QuicConnection(connection_id, client_address, helper_.get(),
+ writer_.get(), true,
+ supported_versions_no_flow_control_);
}
QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() {
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h
index fbb2f40..b19d5c5 100644
--- a/net/tools/quic/quic_dispatcher.h
+++ b/net/tools/quic/quic_dispatcher.h
@@ -113,8 +113,7 @@ class QuicDispatcher : public QuicServerSessionVisitor {
virtual QuicConnection* CreateQuicConnection(
QuicConnectionId connection_id,
const IPEndPoint& server_address,
- const IPEndPoint& client_address,
- uint32 initial_flow_control_window);
+ const IPEndPoint& client_address);
// Called by |framer_visitor_| when the public header has been parsed.
virtual bool OnUnauthenticatedPublicHeader(
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index db8b76a..bd0d204 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -290,16 +290,16 @@ TEST(QuicDispatcherFlowControlTest, NoNewVersion17ConnectionsIfFlagDisabled) {
// When flag is enabled, new connections should support QUIC_VERSION_17.
FLAGS_enable_quic_stream_flow_control_2 = true;
scoped_ptr<QuicConnection> connection_1(
- QuicDispatcherPeer::CreateQuicConnection(
- &dispatcher, kCID, client, server, kInitialFlowControlWindowForTest));
+ QuicDispatcherPeer::CreateQuicConnection(&dispatcher, kCID, client,
+ server));
EXPECT_EQ(QUIC_VERSION_17, connection_1->version());
// When flag is disabled, new connections should not support QUIC_VERSION_17.
FLAGS_enable_quic_stream_flow_control_2 = false;
scoped_ptr<QuicConnection> connection_2(
- QuicDispatcherPeer::CreateQuicConnection(
- &dispatcher, kCID, client, server, kInitialFlowControlWindowForTest));
+ QuicDispatcherPeer::CreateQuicConnection(&dispatcher, kCID, client,
+ server));
EXPECT_EQ(QUIC_VERSION_16, connection_2->version());
}
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 2fc824d..7c31ef0 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -12,11 +12,11 @@
namespace net {
namespace tools {
-QuicServerSession::QuicServerSession(
- const QuicConfig& config,
- QuicConnection* connection,
- QuicServerSessionVisitor* visitor)
- : QuicSession(connection, config),
+QuicServerSession::QuicServerSession(const QuicConfig& config,
+ QuicConnection* connection,
+ uint32 max_flow_control_window_bytes,
+ QuicServerSessionVisitor* visitor)
+ : QuicSession(connection, max_flow_control_window_bytes, config),
visitor_(visitor) {}
QuicServerSession::~QuicServerSession() {}
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h
index ffd8b0a..41d7305 100644
--- a/net/tools/quic/quic_server_session.h
+++ b/net/tools/quic/quic_server_session.h
@@ -47,6 +47,7 @@ class QuicServerSession : public QuicSession {
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 22308fb..0d9c816 100644
--- a/net/tools/quic/quic_server_session_test.cc
+++ b/net/tools/quic/quic_server_session_test.cc
@@ -53,7 +53,7 @@ class QuicServerSessionTest : public ::testing::TestWithParam<QuicVersion> {
connection_ =
new StrictMock<MockConnection>(true, SupportedVersions(GetParam()));
session_.reset(new QuicServerSession(
- config_, connection_, &owner_));
+ config_, connection_, kInitialFlowControlWindowForTest, &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 67f9d89..98ca650 100644
--- a/net/tools/quic/quic_spdy_client_stream_test.cc
+++ b/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -33,6 +33,7 @@ class QuicSpdyClientStreamTest : public TestWithParam<QuicVersion> {
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/test_tools/quic_dispatcher_peer.cc b/net/tools/quic/test_tools/quic_dispatcher_peer.cc
index 0622881..cd27802 100644
--- a/net/tools/quic/test_tools/quic_dispatcher_peer.cc
+++ b/net/tools/quic/test_tools/quic_dispatcher_peer.cc
@@ -41,12 +41,10 @@ QuicConnection* QuicDispatcherPeer::CreateQuicConnection(
QuicDispatcher* dispatcher,
QuicConnectionId connection_id,
const IPEndPoint& server,
- const IPEndPoint& client,
- uint32 initial_flow_control_window_bytes) {
+ const IPEndPoint& client) {
return dispatcher->CreateQuicConnection(connection_id,
server,
- client,
- initial_flow_control_window_bytes);
+ client);
}
} // namespace test
diff --git a/net/tools/quic/test_tools/quic_dispatcher_peer.h b/net/tools/quic/test_tools/quic_dispatcher_peer.h
index e647820..45125c2 100644
--- a/net/tools/quic/test_tools/quic_dispatcher_peer.h
+++ b/net/tools/quic/test_tools/quic_dispatcher_peer.h
@@ -34,8 +34,7 @@ class QuicDispatcherPeer {
QuicDispatcher* dispatcher,
QuicConnectionId connection_id,
const IPEndPoint& server,
- const IPEndPoint& client,
- uint32 initial_flow_control_window_bytes);
+ const IPEndPoint& client);
private:
DISALLOW_COPY_AND_ASSIGN(QuicDispatcherPeer);
diff --git a/net/tools/quic/test_tools/quic_test_utils.cc b/net/tools/quic/test_tools/quic_test_utils.cc
index 78e67ca..bbb03d3 100644
--- a/net/tools/quic/test_tools/quic_test_utils.cc
+++ b/net/tools/quic/test_tools/quic_test_utils.cc
@@ -13,6 +13,7 @@
using base::StringPiece;
using net::test::kInitialFlowControlWindowForTest;
using net::test::MockHelper;
+using net::test::QuicConnectionPeer;
namespace net {
namespace tools {
@@ -23,9 +24,8 @@ MockConnection::MockConnection(bool is_server)
IPEndPoint(net::test::Loopback4(), kTestPort),
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
- is_server, QuicSupportedVersions(),
- kInitialFlowControlWindowForTest),
- writer_(net::test::QuicConnectionPeer::GetWriter(this)),
+ is_server, QuicSupportedVersions()),
+ writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
@@ -34,9 +34,8 @@ MockConnection::MockConnection(IPEndPoint address,
: QuicConnection(kTestConnectionId, address,
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
- is_server, QuicSupportedVersions(),
- kInitialFlowControlWindowForTest),
- writer_(net::test::QuicConnectionPeer::GetWriter(this)),
+ is_server, QuicSupportedVersions()),
+ writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
@@ -46,9 +45,8 @@ MockConnection::MockConnection(QuicConnectionId connection_id,
IPEndPoint(net::test::Loopback4(), kTestPort),
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
- is_server, QuicSupportedVersions(),
- kInitialFlowControlWindowForTest),
- writer_(net::test::QuicConnectionPeer::GetWriter(this)),
+ is_server, QuicSupportedVersions()),
+ writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
@@ -58,9 +56,8 @@ MockConnection::MockConnection(bool is_server,
IPEndPoint(net::test::Loopback4(), kTestPort),
new testing::NiceMock<MockHelper>(),
new testing::NiceMock<MockPacketWriter>(),
- is_server, QuicSupportedVersions(),
- kInitialFlowControlWindowForTest),
- writer_(net::test::QuicConnectionPeer::GetWriter(this)),
+ is_server, QuicSupportedVersions()),
+ writer_(QuicConnectionPeer::GetWriter(this)),
helper_(helper()) {
}
@@ -81,7 +78,7 @@ uint64 SimpleRandom::RandUint64() {
TestSession::TestSession(QuicConnection* connection,
const QuicConfig& config)
- : QuicSession(connection, config),
+ : QuicSession(connection, kInitialFlowControlWindowForTest, config),
crypto_stream_(NULL) {
}