summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-07 22:48:48 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-07 22:48:48 +0000
commit77b5d50b63b575049688c9ef1edb4b5141f7235d (patch)
treeff849af6e3d04c94336daed39e83dee93bf76180 /net
parent504fca8eaf5f65db2d3766f40be721639a3097f9 (diff)
downloadchromium_src-77b5d50b63b575049688c9ef1edb4b5141f7235d.zip
chromium_src-77b5d50b63b575049688c9ef1edb4b5141f7235d.tar.gz
chromium_src-77b5d50b63b575049688c9ef1edb4b5141f7235d.tar.bz2
Land Recent QUIC Changes.
Removed QUIC_VERSION_19 from kSupportedQuicVersions. Will submit a separate CL after making sure all tests pass with QUIC_VERSION_19. Introduces QUIC_VERSION_19, connection level flow control. QuicConnection now has its own flow_controller_ which aggregates bytes sent/received/consumed from all the streams on a given connection. WINDOW_UPDATE and BLOCKED frames are sent with a stream_id of 0 when they refer to the connection. On receipt of a WINDOW_UPDATE which unblocks the connection level flow control, all blocked streams are given a chance to write through a call to OnCanWrite. QUIC_VERSION_19: connection flow control. Protected behind --FLAGS_enable_quic_connection_flow_control Merge internal change: 66020935 https://codereview.chromium.org/265953003/ New QUIC SendAlgorithmInterface which replaces OnPacketAcked, OnPacketLost, OnPacketAbandoned, and OnRttUpdated with a single OnCongestionEvent method. Merge internal change: 66018835 https://codereview.chromium.org/264743011/ Move TransmissionInfo from QuicUnackedPacketMap to QuicProtocol and add a simple bytes_in_flight accessor. Merge internal change: 65886839 https://codereview.chromium.org/265993003/ If stream N is added to the write blocked list, and later a WINDOW_UPDATE frame arrives for the same stream, then stream N will added for a second time to the write blocked list. This is wrong - a stream should only be on the write blocked list once. The write blocked list is implemented as a deque. This CL adds a parallel set<QuicStreamId> which also keeps track of blocked streams, but allows more efficient membership testing. This is used to ensure no duplicate stream IDs end up in the write blocked list. Don't allow duplicate IDs in QUIC write blocked list. Merge internal change: 65878293 https://codereview.chromium.org/261983003/ Sync'ing changes with internal source tree. Minor formatting changes. Merge internal change: 65851919 https://codereview.chromium.org/265813010/ Test-only change to clean up QuicSentPacketManagerTest in order to make changing the SendAlgorithmInterface easier. Merge internal change: 65816291 https://codereview.chromium.org/268623010/ R=rch@chromium.org Review URL: https://codereview.chromium.org/265833015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@268980 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/quic/congestion_control/fix_rate_sender.cc28
-rw-r--r--net/quic/congestion_control/fix_rate_sender.h13
-rw-r--r--net/quic/congestion_control/fix_rate_test.cc22
-rw-r--r--net/quic/congestion_control/pacing_sender.cc37
-rw-r--r--net/quic/congestion_control/pacing_sender.h14
-rw-r--r--net/quic/congestion_control/pacing_sender_test.cc29
-rw-r--r--net/quic/congestion_control/send_algorithm_interface.h29
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.cc90
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.h34
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender_test.cc185
-rw-r--r--net/quic/crypto/quic_crypto_server_config.cc9
-rw-r--r--net/quic/crypto/quic_crypto_server_config.h18
-rw-r--r--net/quic/quic_connection.cc17
-rw-r--r--net/quic/quic_connection.h6
-rw-r--r--net/quic/quic_connection_test.cc204
-rw-r--r--net/quic/quic_data_stream_test.cc93
-rw-r--r--net/quic/quic_flags.cc9
-rw-r--r--net/quic/quic_flags.h1
-rw-r--r--net/quic/quic_flow_controller.cc15
-rw-r--r--net/quic/quic_flow_controller.h2
-rw-r--r--net/quic/quic_http_stream_test.cc2
-rw-r--r--net/quic/quic_protocol.cc41
-rw-r--r--net/quic/quic_protocol.h34
-rw-r--r--net/quic/quic_sent_packet_manager.cc110
-rw-r--r--net/quic/quic_sent_packet_manager.h26
-rw-r--r--net/quic/quic_sent_packet_manager_test.cc247
-rw-r--r--net/quic/quic_session.cc24
-rw-r--r--net/quic/quic_session_test.cc12
-rw-r--r--net/quic/quic_stream_sequencer.cc8
-rw-r--r--net/quic/quic_unacked_packet_map.cc44
-rw-r--r--net/quic/quic_unacked_packet_map.h36
-rw-r--r--net/quic/quic_write_blocked_list.h40
-rw-r--r--net/quic/quic_write_blocked_list_test.cc24
-rw-r--r--net/quic/reliable_quic_stream.cc65
-rw-r--r--net/quic/reliable_quic_stream.h21
-rw-r--r--net/quic/reliable_quic_stream_test.cc6
-rw-r--r--net/quic/test_tools/quic_test_utils.h12
-rw-r--r--net/tools/quic/end_to_end_test.cc3
-rw-r--r--net/tools/quic/quic_dispatcher.cc36
-rw-r--r--net/tools/quic/quic_dispatcher.h12
40 files changed, 888 insertions, 770 deletions
diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc
index a5d750c..d7051b7 100644
--- a/net/quic/congestion_control/fix_rate_sender.cc
+++ b/net/quic/congestion_control/fix_rate_sender.cc
@@ -27,7 +27,6 @@ FixRateSender::FixRateSender(const RttStats* rtt_stats)
max_segment_size_(kDefaultMaxPacketSize),
fix_rate_leaky_bucket_(bitrate_),
paced_sender_(bitrate_, max_segment_size_),
- data_in_flight_(0),
latest_rtt_(QuicTime::Delta::Zero()) {
DVLOG(1) << "FixRateSender";
}
@@ -51,16 +50,10 @@ void FixRateSender::OnIncomingQuicCongestionFeedbackFrame(
// Silently ignore invalid messages in release mode.
}
-void FixRateSender::OnPacketAcked(
- QuicPacketSequenceNumber /*acked_sequence_number*/,
- QuicByteCount bytes_acked) {
- DCHECK_GE(data_in_flight_, bytes_acked);
- data_in_flight_ -= bytes_acked;
-}
-
-void FixRateSender::OnPacketLost(QuicPacketSequenceNumber /*sequence_number*/,
- QuicTime /*ack_receive_time*/) {
- // Ignore losses for fix rate sender.
+void FixRateSender::OnCongestionEvent(bool rtt_updated,
+ QuicByteCount bytes_in_flight,
+ const CongestionMap& acked_packets,
+ const CongestionMap& lost_packets) {
}
bool FixRateSender::OnPacketSent(
@@ -70,25 +63,18 @@ bool FixRateSender::OnPacketSent(
HasRetransmittableData /*has_retransmittable_data*/) {
fix_rate_leaky_bucket_.Add(sent_time, bytes);
paced_sender_.OnPacketSent(sent_time, bytes);
- data_in_flight_ += bytes;
return true;
}
void FixRateSender::OnRetransmissionTimeout(bool packets_retransmitted) { }
-void FixRateSender::OnPacketAbandoned(
- QuicPacketSequenceNumber /*sequence_number*/,
- QuicByteCount bytes_abandoned) {
- DCHECK_GE(data_in_flight_, bytes_abandoned);
- data_in_flight_ -= bytes_abandoned;
-}
-
QuicTime::Delta FixRateSender::TimeUntilSend(
QuicTime now,
+ QuicByteCount bytes_in_flight,
HasRetransmittableData /*has_retransmittable_data*/) {
if (CongestionWindow() > fix_rate_leaky_bucket_.BytesPending(now)) {
- if (CongestionWindow() <= data_in_flight_) {
+ if (CongestionWindow() <= bytes_in_flight) {
// We need an ack before we send more.
return QuicTime::Delta::Infinite();
}
@@ -113,8 +99,6 @@ QuicBandwidth FixRateSender::BandwidthEstimate() const {
return bitrate_;
}
-void FixRateSender::OnRttUpdated(QuicPacketSequenceNumber largest_observed) {
-}
QuicTime::Delta FixRateSender::RetransmissionDelay() const {
// TODO(pwestin): Calculate and return retransmission delay.
diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h
index 093733b..5a64d99 100644
--- a/net/quic/congestion_control/fix_rate_sender.h
+++ b/net/quic/congestion_control/fix_rate_sender.h
@@ -31,23 +31,21 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface {
virtual void OnIncomingQuicCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& feedback,
QuicTime feedback_receive_time) OVERRIDE;
- virtual void OnPacketAcked(QuicPacketSequenceNumber acked_sequence_number,
- QuicByteCount acked_bytes) OVERRIDE;
- virtual void OnPacketLost(QuicPacketSequenceNumber sequence_number,
- QuicTime ack_receive_time) OVERRIDE;
+ virtual void OnCongestionEvent(bool rtt_updated,
+ QuicByteCount bytes_in_flight,
+ const CongestionMap& acked_packets,
+ const CongestionMap& lost_packets) OVERRIDE;
virtual bool OnPacketSent(
QuicTime sent_time,
QuicPacketSequenceNumber sequence_number,
QuicByteCount bytes,
HasRetransmittableData has_retransmittable_data) OVERRIDE;
virtual void OnRetransmissionTimeout(bool packets_retransmitted) OVERRIDE;
- virtual void OnPacketAbandoned(QuicPacketSequenceNumber sequence_number,
- QuicByteCount bytes_abandoned) OVERRIDE;
virtual QuicTime::Delta TimeUntilSend(
QuicTime now,
+ QuicByteCount bytes_in_flight,
HasRetransmittableData has_retransmittable_data) OVERRIDE;
virtual QuicBandwidth BandwidthEstimate() const OVERRIDE;
- virtual void OnRttUpdated(QuicPacketSequenceNumber largest_observed) OVERRIDE;
virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE;
virtual QuicByteCount GetCongestionWindow() const OVERRIDE;
// End implementation of SendAlgorithmInterface.
@@ -60,7 +58,6 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface {
QuicByteCount max_segment_size_;
LeakyBucket fix_rate_leaky_bucket_;
PacedSender paced_sender_;
- QuicByteCount data_in_flight_;
QuicTime::Delta latest_rtt_;
DISALLOW_COPY_AND_ASSIGN(FixRateSender);
diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc
index 1ab48b8..14e1421 100644
--- a/net/quic/congestion_control/fix_rate_test.cc
+++ b/net/quic/congestion_control/fix_rate_test.cc
@@ -60,26 +60,30 @@ TEST_F(FixRateTest, SenderAPI) {
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
EXPECT_EQ(300000, sender_->BandwidthEstimate().ToBytesPerSecond());
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
+ 0,
HAS_RETRANSMITTABLE_DATA).IsZero());
sender_->OnPacketSent(clock_.Now(), 1, kDefaultMaxPacketSize,
HAS_RETRANSMITTABLE_DATA);
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
+ kDefaultMaxPacketSize,
HAS_RETRANSMITTABLE_DATA).IsZero());
sender_->OnPacketSent(clock_.Now(), 2, kDefaultMaxPacketSize,
HAS_RETRANSMITTABLE_DATA);
sender_->OnPacketSent(clock_.Now(), 3, 600,
HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
- sender_->TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA));
+ sender_->TimeUntilSend(clock_.Now(),
+ kDefaultMaxPacketSize * 2 + 600,
+ HAS_RETRANSMITTABLE_DATA));
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2));
EXPECT_EQ(QuicTime::Delta::Infinite(),
- sender_->TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA));
+ sender_->TimeUntilSend(clock_.Now(),
+ kDefaultMaxPacketSize * 2 + 600,
+ HAS_RETRANSMITTABLE_DATA));
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8));
- sender_->OnPacketAcked(1, kDefaultMaxPacketSize);
- sender_->OnPacketAcked(2, kDefaultMaxPacketSize);
- sender_->OnPacketAcked(3, 600);
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
+ 0,
HAS_RETRANSMITTABLE_DATA).IsZero());
}
@@ -95,18 +99,20 @@ TEST_F(FixRateTest, FixRatePacing) {
QuicPacketSequenceNumber sequence_number = 0;
for (int i = 0; i < num_packets; i += 2) {
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
+ 0,
HAS_RETRANSMITTABLE_DATA).IsZero());
sender_->OnPacketSent(clock_.Now(), sequence_number++, packet_size,
HAS_RETRANSMITTABLE_DATA);
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
+ kDefaultMaxPacketSize,
HAS_RETRANSMITTABLE_DATA).IsZero());
sender_->OnPacketSent(clock_.Now(), sequence_number++, packet_size,
HAS_RETRANSMITTABLE_DATA);
QuicTime::Delta advance_time =
- sender_->TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA);
+ sender_->TimeUntilSend(clock_.Now(),
+ 2 * kDefaultMaxPacketSize,
+ HAS_RETRANSMITTABLE_DATA);
clock_.AdvanceTime(advance_time);
- sender_->OnPacketAcked(sequence_number - 1, packet_size);
- sender_->OnPacketAcked(sequence_number - 2, packet_size);
acc_advance_time = acc_advance_time.Add(advance_time);
}
EXPECT_EQ(num_packets * packet_size * 1000000 / bitrate.ToBytesPerSecond(),
diff --git a/net/quic/congestion_control/pacing_sender.cc b/net/quic/congestion_control/pacing_sender.cc
index fc24afe..5193c75 100644
--- a/net/quic/congestion_control/pacing_sender.cc
+++ b/net/quic/congestion_control/pacing_sender.cc
@@ -12,7 +12,7 @@ PacingSender::PacingSender(SendAlgorithmInterface* sender,
alarm_granularity_(alarm_granularity),
next_packet_send_time_(QuicTime::Zero()),
was_last_send_delayed_(false),
- updated_rtt_(false) {
+ has_valid_rtt_(false) {
}
PacingSender::~PacingSender() {}
@@ -28,15 +28,15 @@ void PacingSender::OnIncomingQuicCongestionFeedbackFrame(
feedback, feedback_receive_time);
}
-void PacingSender::OnPacketAcked(
- QuicPacketSequenceNumber acked_sequence_number,
- QuicByteCount acked_bytes) {
- sender_->OnPacketAcked(acked_sequence_number, acked_bytes);
-}
-
-void PacingSender::OnPacketLost(QuicPacketSequenceNumber sequence_number,
- QuicTime ack_receive_time) {
- sender_->OnPacketLost(sequence_number, ack_receive_time);
+void PacingSender::OnCongestionEvent(bool rtt_updated,
+ QuicByteCount bytes_in_flight,
+ const CongestionMap& acked_packets,
+ const CongestionMap& lost_packets) {
+ if (rtt_updated) {
+ has_valid_rtt_ = true;
+ }
+ sender_->OnCongestionEvent(
+ rtt_updated, bytes_in_flight, acked_packets, lost_packets);
}
bool PacingSender::OnPacketSent(
@@ -45,7 +45,7 @@ bool PacingSender::OnPacketSent(
QuicByteCount bytes,
HasRetransmittableData has_retransmittable_data) {
// Only pace data packets once we have an updated RTT.
- if (has_retransmittable_data == HAS_RETRANSMITTABLE_DATA && updated_rtt_) {
+ if (has_retransmittable_data == HAS_RETRANSMITTABLE_DATA && has_valid_rtt_) {
// The next packet should be sent as soon as the current packets has
// been transferred. We pace at twice the rate of the underlying
// sender's bandwidth estimate to help ensure that pacing doesn't become
@@ -63,17 +63,13 @@ void PacingSender::OnRetransmissionTimeout(bool packets_retransmitted) {
sender_->OnRetransmissionTimeout(packets_retransmitted);
}
-void PacingSender::OnPacketAbandoned(QuicPacketSequenceNumber sequence_number,
- QuicByteCount abandoned_bytes) {
- sender_->OnPacketAbandoned(sequence_number, abandoned_bytes);
-}
-
QuicTime::Delta PacingSender::TimeUntilSend(
QuicTime now,
+ QuicByteCount bytes_in_flight,
HasRetransmittableData has_retransmittable_data) {
QuicTime::Delta time_until_send =
- sender_->TimeUntilSend(now, has_retransmittable_data);
- if (!updated_rtt_) {
+ sender_->TimeUntilSend(now, bytes_in_flight, has_retransmittable_data);
+ if (!has_valid_rtt_) {
// Don't pace if we don't have an updated RTT estimate.
return time_until_send;
}
@@ -117,11 +113,6 @@ QuicBandwidth PacingSender::BandwidthEstimate() const {
return sender_->BandwidthEstimate();
}
-void PacingSender::OnRttUpdated(QuicPacketSequenceNumber largest_observed) {
- updated_rtt_= true;
- sender_->OnRttUpdated(largest_observed);
-}
-
QuicTime::Delta PacingSender::RetransmissionDelay() const {
return sender_->RetransmissionDelay();
}
diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h
index 4ce91c2..718bcc4 100644
--- a/net/quic/congestion_control/pacing_sender.h
+++ b/net/quic/congestion_control/pacing_sender.h
@@ -34,22 +34,20 @@ class NET_EXPORT_PRIVATE PacingSender : public SendAlgorithmInterface {
virtual void OnIncomingQuicCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& feedback,
QuicTime feedback_receive_time) OVERRIDE;
- virtual void OnPacketAcked(QuicPacketSequenceNumber acked_sequence_number,
- QuicByteCount acked_bytes) OVERRIDE;
- virtual void OnPacketLost(QuicPacketSequenceNumber sequence_number,
- QuicTime ack_receive_time) OVERRIDE;
+ virtual void OnCongestionEvent(bool rtt_updated,
+ QuicByteCount bytes_in_flight,
+ const CongestionMap& acked_packets,
+ const CongestionMap& lost_packets) OVERRIDE;
virtual bool OnPacketSent(QuicTime sent_time,
QuicPacketSequenceNumber sequence_number,
QuicByteCount bytes,
HasRetransmittableData is_retransmittable) OVERRIDE;
virtual void OnRetransmissionTimeout(bool packets_retransmitted) OVERRIDE;
- virtual void OnPacketAbandoned(QuicPacketSequenceNumber sequence_number,
- QuicByteCount abandoned_bytes) OVERRIDE;
virtual QuicTime::Delta TimeUntilSend(
QuicTime now,
+ QuicByteCount bytes_in_flight,
HasRetransmittableData has_retransmittable_data) OVERRIDE;
virtual QuicBandwidth BandwidthEstimate() const OVERRIDE;
- virtual void OnRttUpdated(QuicPacketSequenceNumber largest_observed) OVERRIDE;
virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE;
virtual QuicByteCount GetCongestionWindow() const OVERRIDE;
@@ -58,7 +56,7 @@ class NET_EXPORT_PRIVATE PacingSender : public SendAlgorithmInterface {
QuicTime::Delta alarm_granularity_;
QuicTime next_packet_send_time_; // When can the next packet be sent.
bool was_last_send_delayed_; // True when the last send was delayed.
- bool updated_rtt_; // True if we have at least one RTT update.
+ bool has_valid_rtt_; // True if we have at least one RTT update.
DISALLOW_COPY_AND_ASSIGN(PacingSender);
};
diff --git a/net/quic/congestion_control/pacing_sender_test.cc b/net/quic/congestion_control/pacing_sender_test.cc
index 19e8e51..e883365 100644
--- a/net/quic/congestion_control/pacing_sender_test.cc
+++ b/net/quic/congestion_control/pacing_sender_test.cc
@@ -13,10 +13,13 @@
using testing::Return;
using testing::StrictMock;
+using testing::_;
namespace net {
namespace test {
+const QuicByteCount kBytesInFlight = 1024;
+
class PacingSenderTest : public ::testing::Test {
protected:
PacingSenderTest()
@@ -36,11 +39,13 @@ class PacingSenderTest : public ::testing::Test {
// In order for the packet to be sendable, the underlying sender must
// permit it to be sent immediately.
EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
HAS_RETRANSMITTABLE_DATA))
.WillOnce(Return(zero_time_));
// Verify that the packet can be sent immediately.
EXPECT_EQ(zero_time_,
pacing_sender_->TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
HAS_RETRANSMITTABLE_DATA));
// Actually send the packet.
@@ -48,40 +53,45 @@ class PacingSenderTest : public ::testing::Test {
OnPacketSent(clock_.Now(), sequence_number_, kMaxPacketSize,
HAS_RETRANSMITTABLE_DATA));
pacing_sender_->OnPacketSent(clock_.Now(), sequence_number_++,
- kMaxPacketSize,
- HAS_RETRANSMITTABLE_DATA);
+ kMaxPacketSize, HAS_RETRANSMITTABLE_DATA);
}
void CheckAckIsSentImmediately() {
// In order for the ack to be sendable, the underlying sender must
// permit it to be sent immediately.
EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
NO_RETRANSMITTABLE_DATA))
.WillOnce(Return(zero_time_));
+ LOG(ERROR) << __LINE__;
// Verify that the ACK can be sent immediately.
EXPECT_EQ(zero_time_,
pacing_sender_->TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
NO_RETRANSMITTABLE_DATA));
+ LOG(ERROR) << __LINE__;
// Actually send the packet.
EXPECT_CALL(*mock_sender_,
OnPacketSent(clock_.Now(), sequence_number_, kMaxPacketSize,
NO_RETRANSMITTABLE_DATA));
+ LOG(ERROR) << __LINE__;
pacing_sender_->OnPacketSent(clock_.Now(), sequence_number_++,
- kMaxPacketSize,
- NO_RETRANSMITTABLE_DATA);
+ kMaxPacketSize, NO_RETRANSMITTABLE_DATA);
}
void CheckPacketIsDelayed(QuicTime::Delta delay) {
// In order for the packet to be sendable, the underlying sender must
// permit it to be sent immediately.
EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
HAS_RETRANSMITTABLE_DATA))
.WillOnce(Return(zero_time_));
// Verify that the packet is delayed.
EXPECT_EQ(delay.ToMicroseconds(),
pacing_sender_->TimeUntilSend(
- clock_.Now(), HAS_RETRANSMITTABLE_DATA).ToMicroseconds());
+ clock_.Now(), kBytesInFlight,
+ HAS_RETRANSMITTABLE_DATA).ToMicroseconds());
}
const QuicTime::Delta zero_time_;
@@ -94,19 +104,23 @@ class PacingSenderTest : public ::testing::Test {
TEST_F(PacingSenderTest, NoSend) {
EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
HAS_RETRANSMITTABLE_DATA))
.WillOnce(Return(infinite_time_));
EXPECT_EQ(infinite_time_,
pacing_sender_->TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
HAS_RETRANSMITTABLE_DATA));
}
TEST_F(PacingSenderTest, SendNow) {
EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
HAS_RETRANSMITTABLE_DATA))
.WillOnce(Return(zero_time_));
EXPECT_EQ(zero_time_,
pacing_sender_->TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
HAS_RETRANSMITTABLE_DATA));
}
@@ -123,8 +137,9 @@ TEST_F(PacingSenderTest, VariousSending) {
}
// Now update the RTT and verify that packets are actually paced.
- EXPECT_CALL(*mock_sender_, OnRttUpdated(1));
- pacing_sender_->OnRttUpdated(1);
+ EXPECT_CALL(*mock_sender_, OnCongestionEvent(true, kBytesInFlight, _, _));
+ SendAlgorithmInterface::CongestionMap empty_map;
+ pacing_sender_->OnCongestionEvent(true, kBytesInFlight, empty_map, empty_map);
CheckPacketIsSentImmediately();
CheckPacketIsSentImmediately();
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index c17417a..330037c 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -25,6 +25,8 @@ class RttStats;
class NET_EXPORT_PRIVATE SendAlgorithmInterface {
public:
+ typedef std::map<QuicPacketSequenceNumber, TransmissionInfo> CongestionMap;
+
static SendAlgorithmInterface* Create(const QuicClock* clock,
const RttStats* rtt_stats,
CongestionFeedbackType type,
@@ -39,14 +41,15 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface {
const QuicCongestionFeedbackFrame& feedback,
QuicTime feedback_receive_time) = 0;
- // Called for each received ACK, with sequence number from remote peer.
- virtual void OnPacketAcked(QuicPacketSequenceNumber acked_sequence_number,
- QuicByteCount acked_bytes) = 0;
-
- // Indicates a loss event of one packet. |sequence_number| is the
- // sequence number of the lost packet.
- virtual void OnPacketLost(QuicPacketSequenceNumber sequence_number,
- QuicTime ack_receive_time) = 0;
+ // Indicates an update to the congestion state, caused either by an incoming
+ // ack or loss event timeout. |rtt_updated| indicates whether a new
+ // latest_rtt sample has been taken, |byte_in_flight| the bytes in flight
+ // prior to the congestion event. |acked_packets| and |lost_packets| are
+ // any packets considered acked or lost as a result of the congestion event.
+ virtual void OnCongestionEvent(bool rtt_updated,
+ QuicByteCount bytes_in_flight,
+ 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,
@@ -62,24 +65,16 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface {
// nor OnPacketLost will be called for these packets.
virtual void OnRetransmissionTimeout(bool packets_retransmitted) = 0;
- // Called when a packet is timed out.
- virtual void OnPacketAbandoned(QuicPacketSequenceNumber sequence_number,
- QuicByteCount abandoned_bytes) = 0;
-
// Calculate the time until we can send the next packet.
virtual QuicTime::Delta TimeUntilSend(
QuicTime now,
+ QuicByteCount bytes_in_flight,
HasRetransmittableData has_retransmittable_data) = 0;
// What's the current estimated bandwidth in bytes per second.
// Returns 0 when it does not have an estimate.
virtual QuicBandwidth BandwidthEstimate() const = 0;
- // Notifies the send algorithm of a new rtt sample and |largest_observed|.
- // TODO(ianswett): Now that the RTT is managed by RTTStats, it may be
- // possible to remove this method.
- virtual void OnRttUpdated(QuicPacketSequenceNumber largest_observed) = 0;
-
// Get the send algorithm specific retransmission delay, called RTO in TCP,
// Note 1: the caller is responsible for sanity checking this value.
// Note 2: this will return zero if we don't have enough data for an estimate.
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 7798a03..eabcd2d 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -38,7 +38,6 @@ TcpCubicSender::TcpCubicSender(
reno_(reno),
congestion_window_count_(0),
receive_window_(kDefaultReceiveWindow),
- bytes_in_flight_(0),
prr_out_(0),
prr_delivered_(0),
ack_count_since_loss_(0),
@@ -74,23 +73,41 @@ void TcpCubicSender::OnIncomingQuicCongestionFeedbackFrame(
receive_window_ = feedback.tcp.receive_window;
}
+void TcpCubicSender::OnCongestionEvent(
+ bool rtt_updated,
+ QuicByteCount bytes_in_flight,
+ const CongestionMap& acked_packets,
+ const CongestionMap& lost_packets) {
+ if (rtt_updated) {
+ OnRttUpdated();
+ }
+ for (CongestionMap::const_iterator it = lost_packets.begin();
+ it != lost_packets.end(); ++it) {
+ OnPacketLost(it->first, bytes_in_flight);
+ }
+ for (CongestionMap::const_iterator it = acked_packets.begin();
+ it != acked_packets.end(); ++it) {
+ OnPacketAcked(it->first, it->second.bytes_sent, bytes_in_flight);
+ }
+}
+
void TcpCubicSender::OnPacketAcked(
- QuicPacketSequenceNumber acked_sequence_number, QuicByteCount acked_bytes) {
- DCHECK_GE(bytes_in_flight_, acked_bytes);
- bytes_in_flight_ -= acked_bytes;
+ QuicPacketSequenceNumber acked_sequence_number,
+ QuicByteCount acked_bytes,
+ QuicByteCount bytes_in_flight) {
largest_acked_sequence_number_ = max(acked_sequence_number,
largest_acked_sequence_number_);
if (InRecovery()) {
PrrOnPacketAcked(acked_bytes);
return;
}
- MaybeIncreaseCwnd(acked_sequence_number);
+ MaybeIncreaseCwnd(acked_sequence_number, bytes_in_flight);
// TODO(ianswett): Should this even be called when not in slow start?
hybrid_slow_start_.OnPacketAcked(acked_sequence_number, InSlowStart());
}
void TcpCubicSender::OnPacketLost(QuicPacketSequenceNumber sequence_number,
- QuicTime /*ack_receive_time*/) {
+ QuicByteCount bytes_in_flight) {
// TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets
// already sent should be treated as a single loss event, since it's expected.
if (sequence_number <= largest_sent_at_last_cutback_) {
@@ -106,7 +123,7 @@ void TcpCubicSender::OnPacketLost(QuicPacketSequenceNumber sequence_number,
if (InSlowStart()) {
++stats_->slowstart_packets_lost;
}
- PrrOnPacketLost();
+ PrrOnPacketLost(bytes_in_flight);
// In a normal TCP we would need to know the lowest missing packet to detect
// if we receive 3 missing packets. Here we get a missing packet for which we
@@ -139,7 +156,6 @@ bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/,
return false;
}
- bytes_in_flight_ += bytes;
prr_out_ += bytes;
if (largest_sent_sequence_number_ < sequence_number) {
// TODO(rch): Ensure that packets are really sent in order.
@@ -150,14 +166,9 @@ bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/,
return true;
}
-void TcpCubicSender::OnPacketAbandoned(QuicPacketSequenceNumber sequence_number,
- QuicByteCount abandoned_bytes) {
- DCHECK_GE(bytes_in_flight_, abandoned_bytes);
- bytes_in_flight_ -= abandoned_bytes;
-}
-
QuicTime::Delta TcpCubicSender::TimeUntilSend(
QuicTime /* now */,
+ QuicByteCount bytes_in_flight,
HasRetransmittableData has_retransmittable_data) {
if (has_retransmittable_data == NO_RETRANSMITTABLE_DATA) {
// For TCP we can always send an ACK immediately.
@@ -166,19 +177,20 @@ QuicTime::Delta TcpCubicSender::TimeUntilSend(
return QuicTime::Delta::Zero();
}
if (InRecovery()) {
- return PrrTimeUntilSend();
+ return PrrTimeUntilSend(bytes_in_flight);
}
- if (AvailableSendWindow() > 0) {
+ if (AvailableSendWindow(bytes_in_flight) > 0) {
return QuicTime::Delta::Zero();
}
return QuicTime::Delta::Infinite();
}
-QuicByteCount TcpCubicSender::AvailableSendWindow() {
- if (bytes_in_flight_ > SendWindow()) {
+QuicByteCount TcpCubicSender::AvailableSendWindow(
+ QuicByteCount bytes_in_flight) {
+ if (bytes_in_flight > SendWindow()) {
return 0;
}
- return SendWindow() - bytes_in_flight_;
+ return SendWindow() - bytes_in_flight;
}
QuicByteCount TcpCubicSender::SendWindow() {
@@ -204,14 +216,14 @@ QuicByteCount TcpCubicSender::GetCongestionWindow() const {
return congestion_window_ * kMaxSegmentSize;
}
-bool TcpCubicSender::IsCwndLimited() const {
+bool TcpCubicSender::IsCwndLimited(QuicByteCount bytes_in_flight) const {
const QuicByteCount congestion_window_bytes = congestion_window_ *
kMaxSegmentSize;
- if (bytes_in_flight_ >= congestion_window_bytes) {
+ if (bytes_in_flight >= congestion_window_bytes) {
return true;
}
const QuicByteCount tcp_max_burst = kMaxBurstLength * kMaxSegmentSize;
- const QuicByteCount left = congestion_window_bytes - bytes_in_flight_;
+ const QuicByteCount left = congestion_window_bytes - bytes_in_flight;
return left <= tcp_max_burst;
}
@@ -223,9 +235,10 @@ bool TcpCubicSender::InRecovery() const {
// Called when we receive an ack. Normal TCP tracks how many packets one ack
// represents, but quic has a separate ack for each packet.
void TcpCubicSender::MaybeIncreaseCwnd(
- QuicPacketSequenceNumber acked_sequence_number) {
+ QuicPacketSequenceNumber acked_sequence_number,
+ QuicByteCount bytes_in_flight) {
LOG_IF(DFATAL, InRecovery()) << "Never increase the CWND during recovery.";
- if (!IsCwndLimited()) {
+ if (!IsCwndLimited(bytes_in_flight)) {
// We don't update the congestion window unless we are close to using the
// window we have available.
return;
@@ -266,7 +279,6 @@ void TcpCubicSender::MaybeIncreaseCwnd(
}
void TcpCubicSender::OnRetransmissionTimeout(bool packets_retransmitted) {
- bytes_in_flight_ = 0;
largest_sent_at_last_cutback_ = 0;
if (packets_retransmitted) {
cubic_.Reset();
@@ -275,8 +287,7 @@ void TcpCubicSender::OnRetransmissionTimeout(bool packets_retransmitted) {
}
}
-void TcpCubicSender::OnRttUpdated(
- QuicPacketSequenceNumber /*largest_observed*/) {
+void TcpCubicSender::OnRttUpdated() {
if (InSlowStart() &&
hybrid_slow_start_.ShouldExitSlowStart(rtt_stats_->latest_rtt(),
rtt_stats_->min_rtt(),
@@ -285,17 +296,11 @@ void TcpCubicSender::OnRttUpdated(
}
}
-void TcpCubicSender::PrrOnPacketLost() {
+void TcpCubicSender::PrrOnPacketLost(QuicByteCount bytes_in_flight) {
prr_out_ = 0;
- bytes_in_flight_before_loss_ = bytes_in_flight_;
- // Since all losses are triggered by an incoming ack currently, and acks are
- // registered before losses by the SentPacketManager, initialize the variables
- // as though one ack was received directly after the loss. This is too low
- // for stretch acks, but we expect missing packets to be immediately acked.
- // This ensures 1 or 2 packets are immediately able to be sent, depending upon
- // whether we're in PRR or PRR-SSRB mode.
- prr_delivered_ = kMaxPacketSize;
- ack_count_since_loss_ = 1;
+ bytes_in_flight_before_loss_ = bytes_in_flight;
+ prr_delivered_ = 0;
+ ack_count_since_loss_ = 0;
}
void TcpCubicSender::PrrOnPacketAcked(QuicByteCount acked_bytes) {
@@ -303,14 +308,19 @@ void TcpCubicSender::PrrOnPacketAcked(QuicByteCount acked_bytes) {
++ack_count_since_loss_;
}
-QuicTime::Delta TcpCubicSender::PrrTimeUntilSend() {
+QuicTime::Delta TcpCubicSender::PrrTimeUntilSend(
+ QuicByteCount bytes_in_flight) {
DCHECK(InRecovery());
- if (AvailableSendWindow() > 0) {
+ // Return QuicTime::Zero In order to ensure limited transmit always works.
+ if (prr_out_ == 0) {
+ return QuicTime::Delta::Zero();
+ }
+ if (AvailableSendWindow(bytes_in_flight) > 0) {
// During PRR-SSRB, limit outgoing packets to 1 extra MSS per ack, instead
// of sending the entire available window. This prevents burst retransmits
// when more packets are lost than the CWND reduction.
// limit = MAX(prr_delivered - prr_out, DeliveredData) + MSS
- if (prr_delivered_ + ack_count_since_loss_ * kMaxSegmentSize < prr_out_) {
+ if (prr_delivered_ + ack_count_since_loss_ * kMaxSegmentSize <= prr_out_) {
return QuicTime::Delta::Infinite();
}
return QuicTime::Delta::Zero();
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index f2a8072..5df86c6 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -47,22 +47,20 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
virtual void OnIncomingQuicCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& feedback,
QuicTime feedback_receive_time) OVERRIDE;
- virtual void OnPacketAcked(QuicPacketSequenceNumber acked_sequence_number,
- QuicByteCount acked_bytes) OVERRIDE;
- virtual void OnPacketLost(QuicPacketSequenceNumber largest_loss,
- QuicTime ack_receive_time) OVERRIDE;
+ virtual void OnCongestionEvent(bool rtt_updated,
+ QuicByteCount bytes_in_flight,
+ const CongestionMap& acked_packets,
+ const CongestionMap& lost_packets) OVERRIDE;
virtual bool OnPacketSent(QuicTime sent_time,
QuicPacketSequenceNumber sequence_number,
QuicByteCount bytes,
HasRetransmittableData is_retransmittable) OVERRIDE;
virtual void OnRetransmissionTimeout(bool packets_retransmitted) OVERRIDE;
- virtual void OnPacketAbandoned(QuicPacketSequenceNumber sequence_number,
- QuicByteCount abandoned_bytes) OVERRIDE;
virtual QuicTime::Delta TimeUntilSend(
QuicTime now,
+ QuicByteCount bytes_in_flight,
HasRetransmittableData has_retransmittable_data) OVERRIDE;
virtual QuicBandwidth BandwidthEstimate() const OVERRIDE;
- virtual void OnRttUpdated(QuicPacketSequenceNumber largest_observed) OVERRIDE;
virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE;
virtual QuicByteCount GetCongestionWindow() const OVERRIDE;
// End implementation of SendAlgorithmInterface.
@@ -70,15 +68,24 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
private:
friend class test::TcpCubicSenderPeer;
- QuicByteCount AvailableSendWindow();
+ // TODO(ianswett): Remove these and migrate to OnCongestionEvent.
+ void OnPacketAcked(QuicPacketSequenceNumber acked_sequence_number,
+ QuicByteCount acked_bytes,
+ QuicByteCount bytes_in_flight);
+ void OnPacketLost(QuicPacketSequenceNumber largest_loss,
+ QuicByteCount bytes_in_flight);
+ void OnRttUpdated();
+
+ QuicByteCount AvailableSendWindow(QuicByteCount bytes_in_flight);
QuicByteCount SendWindow();
- void MaybeIncreaseCwnd(QuicPacketSequenceNumber acked_sequence_number);
- bool IsCwndLimited() const;
+ void MaybeIncreaseCwnd(QuicPacketSequenceNumber acked_sequence_number,
+ QuicByteCount bytes_in_flight);
+ bool IsCwndLimited(QuicByteCount bytes_in_flight) const;
bool InRecovery() const;
// Methods for isolating PRR from the rest of TCP Cubic.
- void PrrOnPacketLost();
+ void PrrOnPacketLost(QuicByteCount bytes_in_flight);
void PrrOnPacketAcked(QuicByteCount acked_bytes);
- QuicTime::Delta PrrTimeUntilSend();
+ QuicTime::Delta PrrTimeUntilSend(QuicByteCount bytes_in_flight);
HybridSlowStart hybrid_slow_start_;
@@ -95,9 +102,6 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
// Receiver side advertised window.
QuicByteCount receive_window_;
- // Bytes in flight, aka bytes on the wire.
- QuicByteCount bytes_in_flight_;
-
// Bytes sent and acked since the last loss event. Used for PRR.
QuicByteCount prr_out_;
QuicByteCount prr_delivered_;
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index e6e9e8b..7d4f942 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -56,45 +56,64 @@ class TcpCubicSenderTest : public ::testing::Test {
kDefaultMaxCongestionWindowTCP)),
receiver_(new TcpReceiver()),
sequence_number_(1),
- acked_sequence_number_(0) {
+ acked_sequence_number_(0),
+ bytes_in_flight_(0) {
+ standard_packet_.bytes_sent = kDefaultTCPMSS;
}
int SendAvailableSendWindow() {
// Send as long as TimeUntilSend returns Zero.
int packets_sent = 0;
bool can_send = sender_->TimeUntilSend(
- clock_.Now(), HAS_RETRANSMITTABLE_DATA).IsZero();
+ clock_.Now(), bytes_in_flight_, HAS_RETRANSMITTABLE_DATA).IsZero();
while (can_send) {
sender_->OnPacketSent(clock_.Now(), sequence_number_++, kDefaultTCPMSS,
HAS_RETRANSMITTABLE_DATA);
++packets_sent;
+ bytes_in_flight_ += kDefaultTCPMSS;
can_send = sender_->TimeUntilSend(
- clock_.Now(), HAS_RETRANSMITTABLE_DATA).IsZero();
+ clock_.Now(), bytes_in_flight_, HAS_RETRANSMITTABLE_DATA).IsZero();
}
return packets_sent;
}
- void UpdateRtt(QuicTime::Delta rtt) {
- sender_->rtt_stats_.UpdateRtt(rtt, QuicTime::Delta::Zero(), clock_.Now());
- sender_->OnRttUpdated(acked_sequence_number_ + 1);
- }
-
// Normal is that TCP acks every other segment.
void AckNPackets(int n) {
+ sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(60),
+ QuicTime::Delta::Zero(),
+ clock_.Now());
+ SendAlgorithmInterface::CongestionMap acked_packets;
+ SendAlgorithmInterface::CongestionMap lost_packets;
for (int i = 0; i < n; ++i) {
++acked_sequence_number_;
- UpdateRtt(QuicTime::Delta::FromMilliseconds(60));
- sender_->OnPacketAcked(acked_sequence_number_, kDefaultTCPMSS);
+ acked_packets[acked_sequence_number_] = standard_packet_;
}
- clock_.AdvanceTime(one_ms_); // 1 millisecond.
+ sender_->OnCongestionEvent(
+ true, bytes_in_flight_, acked_packets, lost_packets);
+ bytes_in_flight_ -= n * kDefaultTCPMSS;
+ clock_.AdvanceTime(one_ms_);
}
void LoseNPackets(int n) {
+ SendAlgorithmInterface::CongestionMap acked_packets;
+ SendAlgorithmInterface::CongestionMap lost_packets;
for (int i = 0; i < n; ++i) {
++acked_sequence_number_;
- sender_->OnPacketAbandoned(acked_sequence_number_, kDefaultTCPMSS);
- sender_->OnPacketLost(acked_sequence_number_, clock_.Now());
+ lost_packets[acked_sequence_number_] = standard_packet_;
}
+ sender_->OnCongestionEvent(
+ false, bytes_in_flight_, acked_packets, lost_packets);
+ bytes_in_flight_ -= n * kDefaultTCPMSS;
+ }
+
+ // Does not increment acked_sequence_number_.
+ void LosePacket(QuicPacketSequenceNumber sequence_number) {
+ SendAlgorithmInterface::CongestionMap acked_packets;
+ SendAlgorithmInterface::CongestionMap lost_packets;
+ lost_packets[sequence_number] = standard_packet_;
+ sender_->OnCongestionEvent(
+ false, bytes_in_flight_, acked_packets, lost_packets);
+ bytes_in_flight_ -= kDefaultTCPMSS;
}
const QuicTime::Delta one_ms_;
@@ -103,34 +122,32 @@ class TcpCubicSenderTest : public ::testing::Test {
scoped_ptr<TcpReceiver> receiver_;
QuicPacketSequenceNumber sequence_number_;
QuicPacketSequenceNumber acked_sequence_number_;
+ QuicByteCount bytes_in_flight_;
+ TransmissionInfo standard_packet_;
};
TEST_F(TcpCubicSenderTest, SimpleSender) {
QuicCongestionFeedbackFrame feedback;
// At startup make sure we are at the default.
- EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableSendWindow());
EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
// At startup make sure we can send.
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
+ 0,
+ HAS_RETRANSMITTABLE_DATA).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
// Make sure we can send.
-
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
+ 0,
+ HAS_RETRANSMITTABLE_DATA).IsZero());
// And that window is un-affected.
- EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableSendWindow());
EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
- // There is available window, so we should be able to send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
-
// Fill the send window with data, then verify that we can't send.
SendAvailableSendWindow();
EXPECT_FALSE(sender_->TimeUntilSend(clock_.Now(),
+ sender_->GetCongestionWindow(),
HAS_RETRANSMITTABLE_DATA).IsZero());
}
@@ -139,13 +156,15 @@ TEST_F(TcpCubicSenderTest, ExponentialSlowStart) {
QuicCongestionFeedbackFrame feedback;
// At startup make sure we can send.
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
+ 0,
HAS_RETRANSMITTABLE_DATA).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
// Make sure we can send.
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
+ 0,
+ HAS_RETRANSMITTABLE_DATA).IsZero());
for (int i = 0; i < kNumberOfAcks; ++i) {
// Send our full send window.
@@ -165,15 +184,9 @@ TEST_F(TcpCubicSenderTest, SlowStartAckTrain) {
// Hence we should pass 30 at 65 = 5 + 10 + 20 + 30
const int kNumberOfAcks = 65;
QuicCongestionFeedbackFrame feedback;
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
- // Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
for (int i = 0; i < kNumberOfAcks; ++i) {
// Send our full send window.
@@ -183,7 +196,6 @@ TEST_F(TcpCubicSenderTest, SlowStartAckTrain) {
QuicByteCount expected_send_window =
kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
// We should now have fallen out of slow start.
// Testing Reno phase.
@@ -208,15 +220,9 @@ TEST_F(TcpCubicSenderTest, SlowStartAckTrain) {
TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) {
// Make sure that we fall out of slow start when we encounter a packet loss.
QuicCongestionFeedbackFrame feedback;
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
- // Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
const int kNumberOfAcks = 10;
for (int i = 0; i < kNumberOfAcks; ++i) {
@@ -229,12 +235,8 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) {
(kDefaultTCPMSS * 2 * kNumberOfAcks);
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- sender_->OnPacketLost(acked_sequence_number_ + 1, clock_.Now());
- ++acked_sequence_number_;
-
- // Make sure that we can send right now due to limited transmit.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
+ // Lose a packet to exit slow start.
+ LoseNPackets(1);
// We should now have fallen out of slow start.
// We expect window to be cut in half by Reno.
@@ -246,7 +248,6 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) {
size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
AckNPackets(number_of_packets_in_window);
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- EXPECT_EQ(0u, sender_->AvailableSendWindow());
// We need to ack every packet in the window before we exit recovery.
for (size_t i = 0; i < number_of_packets_in_window; ++i) {
@@ -276,9 +277,6 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLossPRR) {
// Test based on the first example in RFC6937.
// Make sure that we fall out of slow start when we encounter a packet loss.
QuicCongestionFeedbackFrame feedback;
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
@@ -302,11 +300,6 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLossPRR) {
expected_send_window /= 2;
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- // Send 1 packet to simulate limited transmit.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
- EXPECT_EQ(1, SendAvailableSendWindow());
-
// Testing TCP proportional rate reduction.
// We should send one packet for every two received acks over the remaining
// 18 outstanding packets.
@@ -317,18 +310,13 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLossPRR) {
for (size_t i = 0; i < remaining_packets_in_recovery - 1; i += 2) {
AckNPackets(2);
EXPECT_TRUE(sender_->TimeUntilSend(
- clock_.Now(), HAS_RETRANSMITTABLE_DATA).IsZero());
- EXPECT_EQ(0u, sender_->AvailableSendWindow());
+ clock_.Now(), bytes_in_flight_, HAS_RETRANSMITTABLE_DATA).IsZero());
EXPECT_EQ(1, SendAvailableSendWindow());
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
}
- // If there is one more packet to ack before completing recovery, ack it.
- if (remaining_packets_in_recovery % 2 == 1) {
- AckNPackets(1);
- }
// We need to ack another window before we increase CWND by 1.
- for (size_t i = 0; i < number_of_packets_in_window - 1; ++i) {
+ for (size_t i = 0; i < number_of_packets_in_window; ++i) {
AckNPackets(1);
EXPECT_EQ(1, SendAvailableSendWindow());
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
@@ -345,9 +333,6 @@ TEST_F(TcpCubicSenderTest, SlowStartBurstPacketLossPRR) {
// PRR immediately.
// Make sure that we fall out of slow start when we encounter a packet loss.
QuicCongestionFeedbackFrame feedback;
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
@@ -365,8 +350,12 @@ TEST_F(TcpCubicSenderTest, SlowStartBurstPacketLossPRR) {
EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
// Ack a packet with a 15 packet gap, losing 13 of them due to FACK.
- sender_->OnPacketAcked(acked_sequence_number_ + 15, kDefaultTCPMSS);
LoseNPackets(13);
+ // Immediately after the loss, ensure at least one packet can be sent.
+ // Losses without subsequent acks can occur with timer based loss detection.
+ EXPECT_TRUE(sender_->TimeUntilSend(
+ clock_.Now(), bytes_in_flight_, HAS_RETRANSMITTABLE_DATA).IsZero());
+ AckNPackets(1);
// We should now have fallen out of slow start.
// We expect window to be cut in half by Reno.
@@ -377,15 +366,15 @@ TEST_F(TcpCubicSenderTest, SlowStartBurstPacketLossPRR) {
EXPECT_EQ(2, SendAvailableSendWindow());
// Ack the next packet, which triggers another loss.
- sender_->OnPacketAcked(acked_sequence_number_ + 4, kDefaultTCPMSS);
LoseNPackets(1);
+ AckNPackets(1);
// Send 2 packets to simulate PRR-SSRB.
EXPECT_EQ(2, SendAvailableSendWindow());
// Ack the next packet, which triggers another loss.
- sender_->OnPacketAcked(acked_sequence_number_ + 4, kDefaultTCPMSS);
LoseNPackets(1);
+ AckNPackets(1);
// Send 2 packets to simulate PRR-SSRB.
EXPECT_EQ(2, SendAvailableSendWindow());
@@ -428,7 +417,8 @@ TEST_F(TcpCubicSenderTest, RetransmissionDelay) {
const int64 kDeviationMs = 3;
EXPECT_EQ(QuicTime::Delta::Zero(), sender_->RetransmissionDelay());
- UpdateRtt(QuicTime::Delta::FromMilliseconds(kRttMs));
+ sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(kRttMs),
+ QuicTime::Delta::Zero(), clock_.Now());
// Initial value is to set the median deviation to half of the initial
// rtt, the median in then multiplied by a factor of 4 and finally the
@@ -439,8 +429,12 @@ TEST_F(TcpCubicSenderTest, RetransmissionDelay) {
for (int i = 0; i < 100; ++i) {
// Run to make sure that we converge.
- UpdateRtt(QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs));
- UpdateRtt(QuicTime::Delta::FromMilliseconds(kRttMs - kDeviationMs));
+ sender_->rtt_stats_.UpdateRtt(
+ QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs),
+ QuicTime::Delta::Zero(), clock_.Now());
+ sender_->rtt_stats_.UpdateRtt(
+ QuicTime::Delta::FromMilliseconds(kRttMs - kDeviationMs),
+ QuicTime::Delta::Zero(), clock_.Now());
}
expected_delay = QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs * 4);
@@ -461,15 +455,9 @@ TEST_F(TcpCubicSenderTest, SlowStartMaxSendWindow) {
new TcpCubicSenderPeer(&clock_, false, kMaxCongestionWindowTCP));
QuicCongestionFeedbackFrame feedback;
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
- // Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
for (int i = 0; i < kNumberOfAcks; ++i) {
// Send our full send window.
@@ -488,21 +476,14 @@ TEST_F(TcpCubicSenderTest, TcpRenoMaxCongestionWindow) {
new TcpCubicSenderPeer(&clock_, true, kMaxCongestionWindowTCP));
QuicCongestionFeedbackFrame feedback;
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
- // Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
-
SendAvailableSendWindow();
AckNPackets(2);
// Make sure we fall out of slow start.
- sender_->OnPacketLost(acked_sequence_number_ + 1, clock_.Now());
+ LoseNPackets(1);
for (int i = 0; i < kNumberOfAcks; ++i) {
// Send our full send window.
@@ -524,20 +505,14 @@ TEST_F(TcpCubicSenderTest, TcpCubicMaxCongestionWindow) {
new TcpCubicSenderPeer(&clock_, false, kMaxCongestionWindowTCP));
QuicCongestionFeedbackFrame feedback;
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
- // Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
SendAvailableSendWindow();
AckNPackets(2);
// Make sure we fall out of slow start.
- sender_->OnPacketLost(acked_sequence_number_ + 1, clock_.Now());
+ LoseNPackets(1);
for (int i = 0; i < kNumberOfAcks; ++i) {
// Send our full send window.
@@ -553,34 +528,27 @@ TEST_F(TcpCubicSenderTest, TcpCubicMaxCongestionWindow) {
TEST_F(TcpCubicSenderTest, MultipleLossesInOneWindow) {
SendAvailableSendWindow();
const QuicByteCount initial_window = sender_->GetCongestionWindow();
- sender_->OnPacketLost(acked_sequence_number_ + 1, clock_.Now());
+ LosePacket(acked_sequence_number_ + 1);
const QuicByteCount post_loss_window = sender_->GetCongestionWindow();
EXPECT_GT(initial_window, post_loss_window);
- sender_->OnPacketLost(acked_sequence_number_ + 3, clock_.Now());
+ LosePacket(acked_sequence_number_ + 3);
EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow());
- sender_->OnPacketLost(sequence_number_ - 1, clock_.Now());
+ LosePacket(sequence_number_ - 1);
EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow());
// Lose a later packet and ensure the window decreases.
- sender_->OnPacketLost(sequence_number_, clock_.Now());
+ LosePacket(sequence_number_);
EXPECT_GT(post_loss_window, sender_->GetCongestionWindow());
}
-TEST_F(TcpCubicSenderTest, SendWindowNotAffectedByAcks) {
- QuicByteCount send_window = sender_->AvailableSendWindow();
-
- // Send a packet with no retransmittable data, and ensure that the congestion
- // window doesn't change.
- QuicByteCount bytes_in_packet = min(kDefaultTCPMSS, send_window);
- sender_->OnPacketSent(clock_.Now(), sequence_number_++, bytes_in_packet,
- NO_RETRANSMITTABLE_DATA);
- EXPECT_EQ(send_window, sender_->AvailableSendWindow());
-
- // Send a data packet with retransmittable data, and ensure that the
- // congestion window has shrunk.
- sender_->OnPacketSent(clock_.Now(), sequence_number_++, bytes_in_packet,
- HAS_RETRANSMITTABLE_DATA);
- EXPECT_GT(send_window, sender_->AvailableSendWindow());
+TEST_F(TcpCubicSenderTest, DontTrackAckPackets) {
+ // Send a packet with no retransmittable data, and ensure it's not tracked.
+ EXPECT_FALSE(sender_->OnPacketSent(clock_.Now(), sequence_number_++,
+ kDefaultTCPMSS, NO_RETRANSMITTABLE_DATA));
+
+ // Send a data packet with retransmittable data, and ensure it is tracked.
+ EXPECT_TRUE(sender_->OnPacketSent(clock_.Now(), sequence_number_++,
+ kDefaultTCPMSS, HAS_RETRANSMITTABLE_DATA));
}
TEST_F(TcpCubicSenderTest, ConfigureMaxInitialWindow) {
@@ -595,9 +563,6 @@ TEST_F(TcpCubicSenderTest, ConfigureMaxInitialWindow) {
TEST_F(TcpCubicSenderTest, CongestionAvoidanceAtEndOfRecovery) {
// Make sure that we fall out of slow start when we encounter a packet loss.
QuicCongestionFeedbackFrame feedback;
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- HAS_RETRANSMITTABLE_DATA).IsZero());
// Get default QuicCongestionFeedbackFrame from receiver.
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc
index 0a3c1ad..260c0d4 100644
--- a/net/quic/crypto/quic_crypto_server_config.cc
+++ b/net/quic/crypto/quic_crypto_server_config.cc
@@ -1273,11 +1273,10 @@ void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
primary_config_changed_cb_.reset(cb);
}
-string QuicCryptoServerConfig::NewSourceAddressToken(
- const Config& config,
- const IPEndPoint& ip,
- QuicRandom* rand,
- QuicWallTime now) const {
+string QuicCryptoServerConfig::NewSourceAddressToken(const Config& config,
+ const IPEndPoint& ip,
+ QuicRandom* rand,
+ QuicWallTime now) const {
SourceAddressToken source_address_token;
source_address_token.set_ip(IPAddressToPackedString(ip.address()));
source_address_token.set_timestamp(now.ToUNIXSeconds());
diff --git a/net/quic/crypto/quic_crypto_server_config.h b/net/quic/crypto/quic_crypto_server_config.h
index feac852..216dbbf 100644
--- a/net/quic/crypto/quic_crypto_server_config.h
+++ b/net/quic/crypto/quic_crypto_server_config.h
@@ -381,20 +381,18 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// NewSourceAddressToken returns a fresh source address token for the given
// IP address.
- std::string NewSourceAddressToken(
- const Config& config,
- const IPEndPoint& ip,
- QuicRandom* rand,
- QuicWallTime now) const;
+ std::string NewSourceAddressToken(const Config& config,
+ const IPEndPoint& ip,
+ QuicRandom* rand,
+ QuicWallTime now) const;
// ValidateSourceAddressToken returns true if the source address token in
// |token| is a valid and timely token for the IP address |ip| given that the
// current time is |now|.
- bool ValidateSourceAddressToken(
- const Config& config,
- base::StringPiece token,
- const IPEndPoint& ip,
- QuicWallTime now) const;
+ bool ValidateSourceAddressToken(const Config& config,
+ base::StringPiece token,
+ const IPEndPoint& ip,
+ QuicWallTime now) const;
// NewServerNonce generates and encrypts a random nonce.
std::string NewServerNonce(QuicRandom* rand, QuicWallTime now) const;
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 649120d..52c177e 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -23,6 +23,7 @@
#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;
@@ -243,6 +244,12 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id,
<< 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_));
+
if (!is_server_) {
// Pacing will be enabled if the client negotiates it.
sent_packet_manager_.MaybeEnablePacing();
@@ -364,6 +371,10 @@ 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.
@@ -479,6 +490,9 @@ 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);
@@ -487,6 +501,9 @@ 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();
+ }
}
}
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 257bea4b..62601d8 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -49,6 +49,7 @@ class QuicConnection;
class QuicDecrypter;
class QuicEncrypter;
class QuicFecGroup;
+class QuicFlowController;
class QuicRandom;
namespace test {
@@ -266,6 +267,8 @@ 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();
@@ -742,6 +745,9 @@ class NET_EXPORT_PRIVATE QuicConnection
// 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_test.cc b/net/quic/quic_connection_test.cc
index 3a0c172..9b775f8 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -601,7 +601,7 @@ class QuicConnectionTest : public ::testing::TestWithParam<QuicVersion> {
// Simplify tests by not sending feedback unless specifically configured.
SetFeedback(NULL);
EXPECT_CALL(
- *send_algorithm_, TimeUntilSend(_, _)).WillRepeatedly(Return(
+ *send_algorithm_, TimeUntilSend(_, _, _)).WillRepeatedly(Return(
QuicTime::Delta::Zero()));
EXPECT_CALL(*receive_algorithm_,
RecordIncomingPacket(_, _, _)).Times(AnyNumber());
@@ -1023,7 +1023,8 @@ TEST_P(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) {
// awaiting' is 4. The connection should then realize 1 will not be
// retransmitted, and will remove it from the missing list.
creator_.set_sequence_number(5);
- QuicAckFrame frame = InitAckFrame(0, 4);
+ QuicAckFrame frame = InitAckFrame(1, 4);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _));
ProcessAckPacket(&frame);
// Force an ack to be sent.
@@ -1077,10 +1078,7 @@ TEST_P(QuicConnectionTest, TruncatedAck) {
.WillOnce(Return(lost_packets));
EXPECT_CALL(entropy_calculator_,
EntropyHash(511)).WillOnce(testing::Return(0));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(256);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(255);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(255);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
ProcessAckPacket(&frame);
QuicReceivedPacketManager* received_packet_manager =
@@ -1095,8 +1093,7 @@ TEST_P(QuicConnectionTest, TruncatedAck) {
// 192 has already been declared lost, so it doesn't register as an ack.
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(SequenceNumberSet()));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
ProcessAckPacket(&frame);
EXPECT_EQ(num_packets,
received_packet_manager->peer_largest_observed_packet());
@@ -1108,14 +1105,14 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSendBadEntropy) {
ProcessPacket(1);
// Delay sending, then queue up an ack.
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillOnce(
+ TimeUntilSend(_, _, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
QuicConnectionPeer::SendAck(&connection_);
// Process an ack with a least unacked of the received ack.
// This causes an ack to be sent when TimeUntilSend returns 0.
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillRepeatedly(
+ TimeUntilSend(_, _, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
// Skip a packet and then record an ack.
creator_.set_sequence_number(2);
@@ -1159,9 +1156,7 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) {
lost_packets.insert(1);
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
QuicPacketSequenceNumber retransmission;
EXPECT_CALL(*send_algorithm_,
OnPacketSent(_, _, packet_size - kQuicVersionSize, _))
@@ -1171,8 +1166,7 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) {
QuicAckFrame frame2 = InitAckFrame(retransmission, 1);
NackPacket(original, &frame2);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(SequenceNumberSet()));
ProcessAckPacket(&frame2);
@@ -1262,8 +1256,7 @@ TEST_P(QuicConnectionTest, LargestObservedLower) {
SendStreamDataToPeer(1, "foo", 0, !kFin, NULL);
SendStreamDataToPeer(1, "bar", 3, !kFin, NULL);
SendStreamDataToPeer(1, "eep", 6, !kFin, NULL);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(2);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
// Start out saying the largest observed is 2.
QuicAckFrame frame1 = InitAckFrame(1, 0);
@@ -1409,8 +1402,7 @@ TEST_P(QuicConnectionTest, BasicSending) {
SendAckPacketToPeer(); // Packet 5
EXPECT_EQ(1u, least_unacked());
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(3);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
// Peer acks up to packet 3.
QuicAckFrame frame = InitAckFrame(3, 0);
@@ -1421,8 +1413,7 @@ TEST_P(QuicConnectionTest, BasicSending) {
// ack for 4.
EXPECT_EQ(4u, least_unacked());
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(3);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
// Peer acks up to packet 4, the last packet.
QuicAckFrame frame2 = InitAckFrame(6, 0);
@@ -1446,9 +1437,6 @@ TEST_P(QuicConnectionTest, BasicSending) {
}
TEST_P(QuicConnectionTest, FECSending) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
// All packets carry version info till version is negotiated.
size_t payload_length;
connection_.options()->max_packet_length =
@@ -1468,9 +1456,6 @@ TEST_P(QuicConnectionTest, FECSending) {
}
TEST_P(QuicConnectionTest, FECQueueing) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
// All packets carry version info till version is negotiated.
size_t payload_length;
connection_.options()->max_packet_length =
@@ -1490,9 +1475,6 @@ TEST_P(QuicConnectionTest, FECQueueing) {
}
TEST_P(QuicConnectionTest, AbandonFECFromCongestionWindow) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
connection_.options()->max_packets_per_fec_group = 1;
// 1 Data and 1 FEC packet.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(2);
@@ -1510,9 +1492,6 @@ TEST_P(QuicConnectionTest, AbandonFECFromCongestionWindow) {
}
TEST_P(QuicConnectionTest, DontAbandonAckedFEC) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
connection_.options()->max_packets_per_fec_group = 1;
@@ -1528,9 +1507,7 @@ TEST_P(QuicConnectionTest, DontAbandonAckedFEC) {
// TODO(ianswett): Note that this is not a sensible ack, since if the FEC was
// received, it would cause the covered packet to be acked as well.
NackPacket(1, &ack_fec);
-
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
ProcessAckPacket(&ack_fec);
clock_.AdvanceTime(DefaultRetransmissionTime());
@@ -1542,9 +1519,6 @@ TEST_P(QuicConnectionTest, DontAbandonAckedFEC) {
}
TEST_P(QuicConnectionTest, AbandonAllFEC) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
connection_.options()->max_packets_per_fec_group = 1;
@@ -1567,10 +1541,7 @@ TEST_P(QuicConnectionTest, AbandonAllFEC) {
lost_packets.insert(2);
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(3);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _));
- EXPECT_CALL(*send_algorithm_, OnPacketLost(2, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
ProcessAckPacket(&ack_fec);
clock_.AdvanceTime(DefaultRetransmissionTime().Subtract(
@@ -1809,7 +1780,7 @@ TEST_P(QuicConnectionTest, OnCanWrite) {
&TestConnection::SendStreamData5))));
EXPECT_CALL(visitor_, HasPendingWrites()).WillOnce(Return(true));
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillRepeatedly(
+ TimeUntilSend(_, _, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
connection_.OnCanWrite();
@@ -1833,8 +1804,7 @@ TEST_P(QuicConnectionTest, RetransmitOnNack) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Don't lose a packet on an ack, and nothing is retransmitted.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
QuicAckFrame ack_one = InitAckFrame(1, 0);
ProcessAckPacket(&ack_one);
@@ -1845,10 +1815,7 @@ TEST_P(QuicConnectionTest, RetransmitOnNack) {
lost_packets.insert(2);
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(3, _));
- EXPECT_CALL(*send_algorithm_, OnPacketLost(2, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
EXPECT_CALL(*send_algorithm_,
OnPacketSent(_, _, second_packet_size - kQuicVersionSize, _)).
Times(1);
@@ -1873,10 +1840,7 @@ TEST_P(QuicConnectionTest, DiscardRetransmit) {
lost_packets.insert(2);
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(2);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(2, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
ProcessAckPacket(&nack_two);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -1914,9 +1878,7 @@ TEST_P(QuicConnectionTest, RetransmitNackedLargestObserved) {
lost_packets.insert(1);
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
EXPECT_CALL(*send_algorithm_,
OnPacketSent(_, _, packet_size - kQuicVersionSize, _));
ProcessAckPacket(&frame);
@@ -1989,8 +1951,8 @@ TEST_P(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) {
// Ack the sent packet before the callback returns, which happens in
// rare circumstances with write blocked sockets.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
QuicAckFrame ack = InitAckFrame(1, 0);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
ProcessAckPacket(&ack);
connection_.OnPacketSent(WriteResult(WRITE_STATUS_OK, 0));
@@ -2037,10 +1999,7 @@ TEST_P(QuicConnectionTest, NoLimitPacketsPerNack) {
// the retransmission rate in the case of burst losses.
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(15, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(14);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(14);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(14);
ProcessAckPacket(&nack);
}
@@ -2061,23 +2020,19 @@ TEST_P(QuicConnectionTest, MultipleAcks) {
EXPECT_EQ(6u, last_packet);
// Client will ack packets 1, 2, [!3], 4, 5.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(4);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
QuicAckFrame frame1 = InitAckFrame(5, 0);
NackPacket(3, &frame1);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessAckPacket(&frame1);
// Now the client implicitly acks 3, and explicitly acks 6.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(2);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
QuicAckFrame frame2 = InitAckFrame(6, 0);
ProcessAckPacket(&frame2);
}
TEST_P(QuicConnectionTest, DontLatchUnackedPacket) {
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1);
SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); // Packet 1;
// From now on, we send acks, so the send algorithm won't mark them pending.
ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _))
@@ -2085,6 +2040,7 @@ TEST_P(QuicConnectionTest, DontLatchUnackedPacket) {
SendAckPacketToPeer(); // Packet 2
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
QuicAckFrame frame = InitAckFrame(1, 0);
ProcessAckPacket(&frame);
@@ -2092,7 +2048,7 @@ TEST_P(QuicConnectionTest, DontLatchUnackedPacket) {
// waiting for a potential ack for 2.
EXPECT_EQ(2u, outgoing_ack()->sent_info.least_unacked);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
frame = InitAckFrame(2, 0);
ProcessAckPacket(&frame);
EXPECT_EQ(3u, outgoing_ack()->sent_info.least_unacked);
@@ -2107,7 +2063,7 @@ TEST_P(QuicConnectionTest, DontLatchUnackedPacket) {
EXPECT_EQ(3u, least_unacked());
// Ack the ack, which updates the rtt and raises the least unacked.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
frame = InitAckFrame(3, 0);
ProcessAckPacket(&frame);
@@ -2127,8 +2083,7 @@ TEST_P(QuicConnectionTest, DontLatchUnackedPacket) {
SendStreamDataToPeer(1, "bar", 6, false, NULL); // Packet 6
SendStreamDataToPeer(1, "bar", 9, false, NULL); // Packet 7
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(2);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
frame = InitAckFrame(7, 0);
NackPacket(5, &frame);
NackPacket(6, &frame);
@@ -2335,7 +2290,7 @@ TEST_P(QuicConnectionTest, SendHandshakeMessages) {
// Attempt to send a handshake message and have the socket block.
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillRepeatedly(
+ TimeUntilSend(_, _, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
BlockOnNextWrite();
connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL);
@@ -2391,9 +2346,7 @@ TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
SendStreamDataToPeer(2, "bar", 0, !kFin, NULL);
-
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(1);
connection_.RetransmitUnackedPackets(INITIAL_ENCRYPTION_ONLY);
}
@@ -2490,10 +2443,7 @@ TEST_P(QuicConnectionTest, RetransmissionCountCalculation) {
lost_packets.insert(rto_sequence_number);
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(rto_sequence_number, _)).Times(1);
- EXPECT_CALL(*send_algorithm_,
- OnPacketAbandoned(rto_sequence_number, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
QuicPacketSequenceNumber nack_sequence_number = 0;
// Ack packets might generate some other packets, which are not
// retransmissions. (More ack packets).
@@ -2542,8 +2492,7 @@ TEST_P(QuicConnectionTest, DelayRTOWithAckReceipt) {
// Advance the time right before the RTO, then receive an ack for the first
// packet to delay the RTO.
clock_.AdvanceTime(DefaultRetransmissionTime());
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
QuicAckFrame ack = InitAckFrame(1, 0);
ProcessAckPacket(&ack);
EXPECT_TRUE(retransmission_alarm->IsSet());
@@ -2681,8 +2630,7 @@ TEST_P(QuicConnectionTest, PingAfterSend) {
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
QuicAckFrame frame = InitAckFrame(1, 0);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
ProcessAckPacket(&frame);
EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
EXPECT_EQ(clock_.ApproximateNow().Add(QuicTime::Delta::FromSeconds(15)),
@@ -2748,7 +2696,7 @@ TEST_P(QuicConnectionTest, SendScheduler) {
// Test that if we send a packet without delay, it is not queued.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillOnce(
+ TimeUntilSend(_, _, _)).WillOnce(
testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _));
connection_.SendPacket(
@@ -2760,7 +2708,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelay) {
// Test that if we send a packet with a delay, it ends up queued.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillOnce(
+ TimeUntilSend(_, _, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, _)).Times(0);
connection_.SendPacket(
@@ -2772,7 +2720,7 @@ TEST_P(QuicConnectionTest, SendSchedulerEAGAIN) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
BlockOnNextWrite();
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillOnce(
+ TimeUntilSend(_, _, _)).WillOnce(
testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, _)).Times(0);
connection_.SendPacket(
@@ -2784,7 +2732,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenSend) {
// Test that if we send a packet with a delay, it ends up queued.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillOnce(
+ TimeUntilSend(_, _, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
connection_.SendPacket(
ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
@@ -2793,7 +2741,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenSend) {
// Advance the clock to fire the alarm, and configure the scheduler
// to permit the packet to be sent.
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillRepeatedly(
+ TimeUntilSend(_, _, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _));
@@ -2802,7 +2750,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenSend) {
}
TEST_P(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _))
.WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, _));
connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL);
@@ -2813,7 +2761,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
// sent packet manager, but not yet serialized.
EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillOnce(
+ TimeUntilSend(_, _, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
connection_.GetRetransmissionAlarm()->Fire();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -2821,7 +2769,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
// Advance the clock to fire the alarm, and configure the scheduler
// to permit the packet to be sent.
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).Times(3).
+ TimeUntilSend(_, _, _)).Times(3).
WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
// Ensure the scheduler is notified this is a retransmit.
@@ -2834,7 +2782,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
TEST_P(QuicConnectionTest, SendSchedulerDelayAndQueue) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillOnce(
+ TimeUntilSend(_, _, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
connection_.SendPacket(
ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
@@ -2851,7 +2799,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillOnce(
+ TimeUntilSend(_, _, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(10)));
connection_.SendPacket(
ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
@@ -2861,7 +2809,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
// retransmit 3. The far end should stop waiting for it.
QuicAckFrame frame = InitAckFrame(0, 1);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillRepeatedly(
+ TimeUntilSend(_, _, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_,
OnPacketSent(_, _, _, _));
@@ -2876,7 +2824,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillOnce(
+ TimeUntilSend(_, _, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(10)));
connection_.SendPacket(
ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
@@ -2886,7 +2834,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
// retransmit 3. The far end should stop waiting for it.
QuicAckFrame frame = InitAckFrame(0, 1);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillOnce(
+ TimeUntilSend(_, _, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(1)));
ProcessAckPacket(&frame);
@@ -2898,7 +2846,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) {
// new data if the send algorithm said not to.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillOnce(
+ TimeUntilSend(_, _, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(10)));
connection_.SendPacket(
ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
@@ -2920,7 +2868,7 @@ TEST_P(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
// Queue the first packet.
EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _)).WillOnce(
+ TimeUntilSend(_, _, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(10)));
const string payload(payload_length, 'a');
EXPECT_EQ(0u,
@@ -3078,10 +3026,7 @@ TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) {
lost_packets.insert(1);
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(2, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
ProcessAckPacket(&ack);
EXPECT_EQ(1u, writer_->frame_count());
EXPECT_EQ(1u, writer_->stream_frames().size());
@@ -3093,8 +3038,7 @@ TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) {
NackPacket(1, &ack);
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(SequenceNumberSet()));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(3, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
ProcessAckPacket(&ack);
// Check that no packet is sent and the ack alarm isn't set.
@@ -3126,10 +3070,9 @@ TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) {
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
}
-TEST_P(QuicConnectionTest, NoAckForClose) {
+TEST_P(QuicConnectionTest, NoAckSentForClose) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(0);
EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, true));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(0);
ProcessClosePacket(2, 0);
@@ -3542,7 +3485,6 @@ TEST_P(QuicConnectionTest, CheckSendStats) {
// 2 retransmissions due to rto, 1 due to explicit nack.
EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(3);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(1);
// Retransmit due to RTO.
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
@@ -3557,9 +3499,7 @@ TEST_P(QuicConnectionTest, CheckSendStats) {
lost_packets.insert(3);
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(4, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(2);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
EXPECT_CALL(visitor_, OnCanWrite()).Times(2);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessAckPacket(&nack_three);
@@ -3724,8 +3664,7 @@ TEST_P(QuicConnectionTest, AckNotifierTriggerCallback) {
connection_.SendStreamDataWithString(1, "foo", 0, !kFin, delegate.get());
// Process an ACK from the server which should trigger the callback.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
QuicAckFrame frame = InitAckFrame(1, 0);
ProcessAckPacket(&frame);
}
@@ -3737,9 +3676,6 @@ TEST_P(QuicConnectionTest, AckNotifierFailToTriggerCallback) {
scoped_refptr<MockAckNotifierDelegate> delegate(new MockAckNotifierDelegate);
EXPECT_CALL(*delegate, OnAckNotification(_, _, _, _, _)).Times(0);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(2);
-
// Send some data, which will register the delegate to be notified. This will
// not be ACKed and so the delegate should never be called.
connection_.SendStreamDataWithString(1, "foo", 0, !kFin, delegate.get());
@@ -3756,8 +3692,7 @@ TEST_P(QuicConnectionTest, AckNotifierFailToTriggerCallback) {
lost_packets.insert(1);
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
ProcessAckPacket(&frame);
}
@@ -3781,10 +3716,7 @@ TEST_P(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) {
lost_packets.insert(2);
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(3);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(2, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _));
ProcessAckPacket(&frame);
@@ -3792,8 +3724,7 @@ TEST_P(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) {
// trigger the callback.
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillRepeatedly(Return(SequenceNumberSet()));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(5, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
QuicAckFrame second_ack_frame = InitAckFrame(5, 0);
ProcessAckPacket(&second_ack_frame);
}
@@ -3827,14 +3758,13 @@ TEST_P(QuicConnectionTest, AckNotifierCallbackForAckAfterRTO) {
// Ack the original packet.
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
EXPECT_CALL(*delegate, OnAckNotification(1, _, 1, _, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
QuicAckFrame ack_frame = InitAckFrame(1, 0);
ProcessAckPacket(&ack_frame);
// Delegate is not notified again when the retransmit is acked.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(2, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
QuicAckFrame second_ack_frame = InitAckFrame(2, 0);
ProcessAckPacket(&second_ack_frame);
}
@@ -3861,14 +3791,9 @@ TEST_P(QuicConnectionTest, AckNotifierCallbackForAckOfNackedPacket) {
SequenceNumberSet lost_packets;
lost_packets.insert(2);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(3, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(4, _));
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnPacketLost(2, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _));
ProcessAckPacket(&frame);
@@ -3882,18 +3807,14 @@ TEST_P(QuicConnectionTest, AckNotifierCallbackForAckOfNackedPacket) {
// Verify that the delegate is not notified again when the
// retransmit is acked.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(5, _));
EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _))
.WillOnce(Return(no_lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
QuicAckFrame third_ack_frame = InitAckFrame(5, 0);
ProcessAckPacket(&third_ack_frame);
}
TEST_P(QuicConnectionTest, AckNotifierFECTriggerCallback) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Create a delegate which we expect to be called.
@@ -3907,8 +3828,7 @@ TEST_P(QuicConnectionTest, AckNotifierFECTriggerCallback) {
// Process an ACK from the server with a revived packet, which should trigger
// the callback.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
QuicAckFrame frame = InitAckFrame(2, 0);
NackPacket(1, &frame);
frame.received_info.revived_packets.insert(1);
@@ -3918,9 +3838,6 @@ TEST_P(QuicConnectionTest, AckNotifierFECTriggerCallback) {
}
TEST_P(QuicConnectionTest, AckNotifierCallbackAfterFECRecovery) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(visitor_, OnCanWrite());
@@ -3929,8 +3846,7 @@ TEST_P(QuicConnectionTest, AckNotifierCallbackAfterFECRecovery) {
EXPECT_CALL(*delegate, OnAckNotification(_, _, _, _, _)).Times(1);
// Expect ACKs for 1 packet.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
// Send one packet, and register to be notified on ACK.
connection_.SendStreamDataWithString(1, "foo", 0, !kFin, delegate.get());
diff --git a/net/quic/quic_data_stream_test.cc b/net/quic/quic_data_stream_test.cc
index ca6d99b..b3c0f4c 100644
--- a/net/quic/quic_data_stream_test.cc
+++ b/net/quic/quic_data_stream_test.cc
@@ -413,6 +413,62 @@ TEST_P(QuicDataStreamTest, StreamFlowControlWindowUpdate) {
stream_->flow_controller()));
}
+TEST_P(QuicDataStreamTest, ConnectionFlowControlWindowUpdate) {
+ // Tests that on receipt of data, the connection updates its receive window
+ // offset appropriately, and sends WINDOW_UPDATE frames when its receive
+ // window drops too low.
+ if (GetParam() < QUIC_VERSION_19) {
+ return;
+ }
+ ValueRestore<bool> old_flag2(&FLAGS_enable_quic_stream_flow_control_2, true);
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control, true);
+
+ Initialize(kShouldProcessData);
+
+ // Set a small flow control limit for streams and connection.
+ const uint64 kWindow = 36;
+ QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
+ kWindow);
+ QuicFlowControllerPeer::SetMaxReceiveWindow(stream_->flow_controller(),
+ kWindow);
+ QuicFlowControllerPeer::SetReceiveWindowOffset(stream2_->flow_controller(),
+ kWindow);
+ QuicFlowControllerPeer::SetMaxReceiveWindow(stream2_->flow_controller(),
+ kWindow);
+ QuicFlowControllerPeer::SetReceiveWindowOffset(connection_->flow_controller(),
+ kWindow);
+ QuicFlowControllerPeer::SetMaxReceiveWindow(connection_->flow_controller(),
+ kWindow);
+
+ // Supply headers to both streams so that they are happy to receive data.
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ stream2_->OnStreamHeaders(headers);
+ stream2_->OnStreamHeadersComplete(false, headers.size());
+
+ // Each stream gets a quarter window of data. This should not trigger a
+ // WINDOW_UPDATE for either stream, nor for the connection.
+ string body;
+ GenerateBody(&body, kWindow / 4);
+ QuicStreamFrame frame1(kStreamId, false, 0, MakeIOVector(body));
+ stream_->OnStreamFrame(frame1);
+ QuicStreamFrame frame2(kStreamId + 2, false, 0, MakeIOVector(body));
+ stream2_->OnStreamFrame(frame2);
+
+ // Now receive a further single byte on one stream - again this does not
+ // trigger a stream WINDOW_UPDATE, but now the connection flow control window
+ // is over half full and thus a connection WINDOW_UPDATE is sent.
+ EXPECT_CALL(*connection_, SendWindowUpdate(kStreamId, _)).Times(0);
+ EXPECT_CALL(*connection_, SendWindowUpdate(kStreamId + 2, _)).Times(0);
+ EXPECT_CALL(*connection_,
+ SendWindowUpdate(0, QuicFlowControllerPeer::ReceiveWindowOffset(
+ connection_->flow_controller()) +
+ 1 + kWindow / 2));
+ QuicStreamFrame frame3(kStreamId, false, (kWindow / 4), MakeIOVector("a"));
+ stream_->OnStreamFrame(frame3);
+}
+
TEST_P(QuicDataStreamTest, StreamFlowControlViolation) {
// Tests that on if the peer sends too much data (i.e. violates the flow
// control protocol), then we terminate the connection.
@@ -443,6 +499,43 @@ TEST_P(QuicDataStreamTest, StreamFlowControlViolation) {
stream_->OnStreamFrame(frame);
}
+TEST_P(QuicDataStreamTest, ConnectionFlowControlViolation) {
+ // Tests that on if the peer sends too much data (i.e. violates the flow
+ // control protocol), at the connection level (rather than the stream level)
+ // then we terminate the connection.
+ if (GetParam() < QUIC_VERSION_19) {
+ return;
+ }
+ ValueRestore<bool> old_flag2(&FLAGS_enable_quic_stream_flow_control_2, true);
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_connection_flow_control, true);
+
+ // Stream should not process data, so that data gets buffered in the
+ // sequencer, triggering flow control limits.
+ Initialize(!kShouldProcessData);
+
+ // Set a small flow control window on streams, and connection.
+ const uint64 kStreamWindow = 50;
+ const uint64 kConnectionWindow = 10;
+ QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
+ kStreamWindow);
+ QuicFlowControllerPeer::SetReceiveWindowOffset(connection_->flow_controller(),
+ kConnectionWindow);
+
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(headers);
+ EXPECT_EQ(headers, stream_->data());
+ stream_->OnStreamHeadersComplete(false, headers.size());
+
+ // Send enough data to overflow the connection level flow control window.
+ string body;
+ GenerateBody(&body, kConnectionWindow + 1);
+ EXPECT_LT(body.size(), kStreamWindow);
+ QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body));
+
+ EXPECT_CALL(*connection_, SendConnectionClose(QUIC_FLOW_CONTROL_ERROR));
+ stream_->OnStreamFrame(frame);
+}
+
TEST_P(QuicDataStreamTest, StreamFlowControlFinNotBlocked) {
// An attempt to write a FIN with no data should not be flow control blocked,
// even if the send window is 0.
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index 2d73d1d..c42afb6 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -21,8 +21,17 @@ bool FLAGS_enable_quic_pacing = true;
// Do not remove this flag until b/11792453 is marked as Fixed.
// If true, turns on stream flow control in QUIC.
+// If this is disabled, all in flight QUIC connections talking QUIC_VERSION_17
+// or higher will timeout. New connections will be fine.
+// If disabling this flag, also disable enable_quic_connection_flow_control.
bool FLAGS_enable_quic_stream_flow_control_2 = true;
+// Do not remove this flag until b/11792453 is marked as Fixed.
+// If true, turns on connection level flow control in QUIC.
+// If this is disabled, all in flight QUIC connections talking QUIC_VERSION_19
+// or higher will timeout. New connections will be fine.
+bool FLAGS_enable_quic_connection_flow_control = true;
+
bool FLAGS_quic_allow_oversized_packets_for_test = false;
// When true, the use time based loss detection instead of nack.
bool FLAGS_quic_use_time_loss_detection = false;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index 2bf963a..31585d3 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -10,6 +10,7 @@
NET_EXPORT_PRIVATE extern bool FLAGS_track_retransmission_history;
NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_pacing;
NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_stream_flow_control_2;
+NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_connection_flow_control;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_oversized_packets_for_test;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_time_loss_detection;
diff --git a/net/quic/quic_flow_controller.cc b/net/quic/quic_flow_controller.cc
index d169648..412f250 100644
--- a/net/quic/quic_flow_controller.cc
+++ b/net/quic/quic_flow_controller.cc
@@ -82,9 +82,9 @@ void QuicFlowController::AddBytesSent(uint64 bytes_sent) {
}
if (bytes_sent_ + bytes_sent > send_window_offset_) {
- LOG(DFATAL) << "Trying to send an extra " << bytes_sent
- << " bytes, when bytes_sent = " << bytes_sent_
- << ", and send_window = " << send_window_offset_;
+ LOG(DFATAL) << ENDPOINT << "Stream " << id_ << " Trying to send an extra "
+ << bytes_sent << " bytes, when bytes_sent = " << bytes_sent_
+ << ", and send_window_offset_ = " << send_window_offset_;
bytes_sent_ = send_window_offset_;
return;
}
@@ -180,7 +180,14 @@ void QuicFlowController::Disable() {
}
bool QuicFlowController::IsEnabled() const {
- return FLAGS_enable_quic_stream_flow_control_2 && is_enabled_;
+ bool connection_flow_control_enabled =
+ (id_ == kConnectionLevelId &&
+ FLAGS_enable_quic_connection_flow_control);
+ bool stream_flow_control_enabled =
+ (id_ != kConnectionLevelId &&
+ FLAGS_enable_quic_stream_flow_control_2);
+ return (connection_flow_control_enabled || stream_flow_control_enabled) &&
+ is_enabled_;
}
bool QuicFlowController::IsBlocked() const {
diff --git a/net/quic/quic_flow_controller.h b/net/quic/quic_flow_controller.h
index 99a9d6f..3125b81 100644
--- a/net/quic/quic_flow_controller.h
+++ b/net/quic/quic_flow_controller.h
@@ -17,6 +17,8 @@ class QuicFlowControllerPeer;
class QuicConnection;
+const QuicStreamId kConnectionLevelId = 0;
+
// QuicFlowController allows a QUIC stream or connection to perform flow
// control. The stream/connection owns a QuicFlowController which keeps track of
// bytes sent/received, can tell the owner if it is flow control blocked, and
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index f54d3d1..47c8a1e 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -189,7 +189,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> {
Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, GetCongestionWindow()).WillRepeatedly(
Return(kMaxPacketSize));
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _)).
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)).
WillRepeatedly(Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillRepeatedly(
Return(QuicBandwidth::Zero()));
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index facb15f..32c5c31 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -162,6 +162,8 @@ QuicTag QuicVersionToQuicTag(const QuicVersion version) {
return MakeQuicTag('Q', '0', '1', '7');
case QUIC_VERSION_18:
return MakeQuicTag('Q', '0', '1', '8');
+ case QUIC_VERSION_19:
+ return MakeQuicTag('Q', '0', '1', '9');
default:
// This shold be an ERROR because we should never attempt to convert an
// invalid QuicVersion to be written to the wire.
@@ -192,6 +194,7 @@ string QuicVersionToString(const QuicVersion version) {
RETURN_STRING_LITERAL(QUIC_VERSION_16);
RETURN_STRING_LITERAL(QUIC_VERSION_17);
RETURN_STRING_LITERAL(QUIC_VERSION_18);
+ RETURN_STRING_LITERAL(QUIC_VERSION_19);
default:
return "QUIC_VERSION_UNSUPPORTED";
}
@@ -733,6 +736,44 @@ ostream& operator<<(ostream& os, const QuicEncryptedPacket& s) {
return os;
}
+TransmissionInfo::TransmissionInfo()
+ : retransmittable_frames(NULL),
+ sequence_number_length(PACKET_1BYTE_SEQUENCE_NUMBER),
+ sent_time(QuicTime::Zero()),
+ bytes_sent(0),
+ nack_count(0),
+ all_transmissions(NULL),
+ pending(false) { }
+
+TransmissionInfo::TransmissionInfo(
+ RetransmittableFrames* retransmittable_frames,
+ QuicPacketSequenceNumber sequence_number,
+ QuicSequenceNumberLength sequence_number_length)
+ : retransmittable_frames(retransmittable_frames),
+ sequence_number_length(sequence_number_length),
+ sent_time(QuicTime::Zero()),
+ bytes_sent(0),
+ nack_count(0),
+ all_transmissions(new SequenceNumberSet),
+ pending(false) {
+ all_transmissions->insert(sequence_number);
+}
+
+TransmissionInfo::TransmissionInfo(
+ RetransmittableFrames* retransmittable_frames,
+ QuicPacketSequenceNumber sequence_number,
+ QuicSequenceNumberLength sequence_number_length,
+ SequenceNumberSet* all_transmissions)
+ : retransmittable_frames(retransmittable_frames),
+ sequence_number_length(sequence_number_length),
+ sent_time(QuicTime::Zero()),
+ bytes_sent(0),
+ nack_count(0),
+ all_transmissions(all_transmissions),
+ pending(false) {
+ all_transmissions->insert(sequence_number);
+}
+
QuicConsumedData::QuicConsumedData(size_t bytes_consumed,
bool fin_consumed)
: bytes_consumed(bytes_consumed),
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index f6dc181..1a14201 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -264,7 +264,8 @@ enum QuicVersion {
QUIC_VERSION_15 = 15,
QUIC_VERSION_16 = 16,
QUIC_VERSION_17 = 17,
- QUIC_VERSION_18 = 18, // Current version.
+ QUIC_VERSION_18 = 18,
+ QUIC_VERSION_19 = 19, // Current version.
};
// This vector contains QUIC versions which we currently support.
@@ -1005,6 +1006,37 @@ struct NET_EXPORT_PRIVATE SerializedPacket {
std::set<QuicAckNotifier*> notifiers;
};
+struct NET_EXPORT_PRIVATE TransmissionInfo {
+ // Used by STL when assigning into a map.
+ TransmissionInfo();
+
+ // Constructs a Transmission with a new all_tranmissions set
+ // containing |sequence_number|.
+ TransmissionInfo(RetransmittableFrames* retransmittable_frames,
+ QuicPacketSequenceNumber sequence_number,
+ QuicSequenceNumberLength sequence_number_length);
+
+ // Constructs a Transmission with the specified |all_tranmissions| set
+ // and inserts |sequence_number| into it.
+ TransmissionInfo(RetransmittableFrames* retransmittable_frames,
+ QuicPacketSequenceNumber sequence_number,
+ QuicSequenceNumberLength sequence_number_length,
+ SequenceNumberSet* all_transmissions);
+
+ RetransmittableFrames* retransmittable_frames;
+ QuicSequenceNumberLength sequence_number_length;
+ // Zero when the packet is serialized, non-zero once it's sent.
+ QuicTime sent_time;
+ // Zero when the packet is serialized, non-zero once it's sent.
+ QuicByteCount bytes_sent;
+ size_t nack_count;
+ // Stores the sequence numbers of all transmissions of this packet.
+ // Can never be null.
+ SequenceNumberSet* all_transmissions;
+ // Pending packets have not been abandoned or lost.
+ bool pending;
+};
+
// A struct for functions which consume data payloads and fins.
struct NET_EXPORT_PRIVATE QuicConsumedData {
QuicConsumedData(size_t bytes_consumed, bool fin_consumed);
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 6e103d3..88017c4 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -38,8 +38,7 @@ static const size_t kMinHandshakeTimeoutMs = 10;
static const size_t kDefaultMaxTailLossProbes = 2;
static const int64 kMinTailLossProbeTimeoutMs = 10;
-bool HasCryptoHandshake(
- const QuicUnackedPacketMap::TransmissionInfo& transmission_info) {
+bool HasCryptoHandshake(const TransmissionInfo& transmission_info) {
if (transmission_info.retransmittable_frames == NULL) {
return false;
}
@@ -120,13 +119,15 @@ void QuicSentPacketManager::OnRetransmittedPacket(
void QuicSentPacketManager::OnIncomingAck(
const ReceivedPacketInfo& received_info,
QuicTime ack_receive_time) {
+ QuicByteCount bytes_in_flight = unacked_packets_.bytes_in_flight();
+
// We rely on delta_time_largest_observed to compute an RTT estimate, so
// we only update rtt when the largest observed gets acked.
largest_observed_ = received_info.largest_observed;
- bool largest_observed_acked = unacked_packets_.IsUnacked(largest_observed_);
- MaybeUpdateRTT(received_info, ack_receive_time);
+ bool largest_observed_acked = MaybeUpdateRTT(received_info, ack_receive_time);
HandleAckForSentPackets(received_info);
MaybeRetransmitOnAckFrame(received_info, ack_receive_time);
+ MaybeInvokeCongestionEvent(largest_observed_acked, bytes_in_flight);
// Anytime we are making forward progress and have a new RTT estimate, reset
// the backoff counters.
@@ -138,10 +139,20 @@ void QuicSentPacketManager::OnIncomingAck(
}
}
+void QuicSentPacketManager::MaybeInvokeCongestionEvent(
+ bool rtt_updated, QuicByteCount bytes_in_flight) {
+ if (rtt_updated || !packets_acked_.empty() ||
+ !packets_lost_.empty()) {
+ send_algorithm_->OnCongestionEvent(
+ rtt_updated, bytes_in_flight, packets_acked_, packets_lost_);
+ packets_acked_.clear();
+ packets_lost_.clear();
+ }
+}
+
void QuicSentPacketManager::DiscardUnackedPacket(
QuicPacketSequenceNumber sequence_number) {
- MarkPacketHandled(sequence_number, QuicTime::Delta::Zero(),
- NOT_RECEIVED_BY_PEER);
+ MarkPacketHandled(sequence_number, QuicTime::Delta::Zero());
}
void QuicSentPacketManager::HandleAckForSentPackets(
@@ -162,8 +173,7 @@ void QuicSentPacketManager::HandleAckForSentPackets(
// 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)) {
- it = MarkPacketHandled(sequence_number, delta_largest_observed,
- NOT_RECEIVED_BY_PEER);
+ it = MarkPacketHandled(sequence_number, delta_largest_observed);
} else {
++it;
}
@@ -171,11 +181,13 @@ void QuicSentPacketManager::HandleAckForSentPackets(
}
// Packet was acked, so remove it from our unacked packet list.
- DVLOG(1) << ENDPOINT <<"Got an ack for packet " << sequence_number;
+ DVLOG(1) << ENDPOINT << "Got an ack for packet " << sequence_number;
// If data is associated with the most recent transmission of this
// packet, then inform the caller.
- it = MarkPacketHandled(sequence_number, delta_largest_observed,
- RECEIVED_BY_PEER);
+ if (it->second.pending) {
+ packets_acked_[sequence_number] = it->second;
+ }
+ it = MarkPacketHandled(sequence_number, delta_largest_observed);
}
// Discard any retransmittable frames associated with revived packets.
@@ -209,8 +221,8 @@ void QuicSentPacketManager::RetransmitUnackedPackets(
// pending retransmissions which would be cleared.
if (frames == NULL && unacked_it->second.all_transmissions->size() == 1 &&
retransmission_type == ALL_PACKETS) {
- unacked_it = MarkPacketHandled(unacked_it->first, QuicTime::Delta::Zero(),
- NOT_RECEIVED_BY_PEER);
+ unacked_it = MarkPacketHandled(unacked_it->first,
+ QuicTime::Delta::Zero());
continue;
}
// If it had no other transmissions, we handle it above. If it has
@@ -221,7 +233,7 @@ void QuicSentPacketManager::RetransmitUnackedPackets(
// numbers with no connection to the previous ones.
if (frames != NULL && (retransmission_type == ALL_PACKETS ||
frames->encryption_level() == ENCRYPTION_INITIAL)) {
- OnPacketAbandoned(unacked_it->first);
+ unacked_packets_.SetNotPending(unacked_it->first);
MarkForRetransmission(unacked_it->first, ALL_UNACKED_RETRANSMISSION);
}
++unacked_it;
@@ -240,7 +252,7 @@ void QuicSentPacketManager::NeuterUnencryptedPackets() {
// control perspective.
pending_retransmissions_.erase(unacked_it->first);
unacked_packets_.NeuterPacket(unacked_it->first);
- OnPacketAbandoned(unacked_it->first);
+ unacked_packets_.SetNotPending(unacked_it->first);
}
++unacked_it;
}
@@ -249,7 +261,7 @@ void QuicSentPacketManager::NeuterUnencryptedPackets() {
void QuicSentPacketManager::MarkForRetransmission(
QuicPacketSequenceNumber sequence_number,
TransmissionType transmission_type) {
- const QuicUnackedPacketMap::TransmissionInfo& transmission_info =
+ const TransmissionInfo& transmission_info =
unacked_packets_.GetTransmissionInfo(sequence_number);
LOG_IF(DFATAL, transmission_info.retransmittable_frames == NULL);
// TODO(ianswett): Currently the RTO can fire while there are pending NACK
@@ -276,8 +288,7 @@ QuicSentPacketManager::PendingRetransmission
PendingRetransmissionMap::const_iterator it =
pending_retransmissions_.begin();
do {
- if (HasCryptoHandshake(
- unacked_packets_.GetTransmissionInfo(it->first))) {
+ if (HasCryptoHandshake(unacked_packets_.GetTransmissionInfo(it->first))) {
sequence_number = it->first;
transmission_type = it->second;
break;
@@ -286,7 +297,7 @@ QuicSentPacketManager::PendingRetransmission
} while (it != pending_retransmissions_.end());
}
DCHECK(unacked_packets_.IsUnacked(sequence_number));
- const QuicUnackedPacketMap::TransmissionInfo& transmission_info =
+ const TransmissionInfo& transmission_info =
unacked_packets_.GetTransmissionInfo(sequence_number);
DCHECK(transmission_info.retransmittable_frames);
@@ -306,7 +317,7 @@ void QuicSentPacketManager::MarkPacketRevived(
// retransmit it, do not retransmit it anymore.
pending_retransmissions_.erase(sequence_number);
- const QuicUnackedPacketMap::TransmissionInfo& transmission_info =
+ const TransmissionInfo& transmission_info =
unacked_packets_.GetTransmissionInfo(sequence_number);
// The AckNotifierManager needs to be notified for revived packets,
// since it indicates the packet arrived from the appliction's perspective.
@@ -324,23 +335,15 @@ void QuicSentPacketManager::MarkPacketRevived(
QuicUnackedPacketMap::const_iterator QuicSentPacketManager::MarkPacketHandled(
QuicPacketSequenceNumber sequence_number,
- QuicTime::Delta delta_largest_observed, ReceivedByPeer received_by_peer) {
+ QuicTime::Delta delta_largest_observed) {
if (!unacked_packets_.IsUnacked(sequence_number)) {
LOG(DFATAL) << "Packet is not unacked: " << sequence_number;
return unacked_packets_.end();
}
- const QuicUnackedPacketMap::TransmissionInfo& transmission_info =
+ const TransmissionInfo& transmission_info =
unacked_packets_.GetTransmissionInfo(sequence_number);
// If this packet is pending, remove it and inform the send algorithm.
if (transmission_info.pending) {
- if (received_by_peer == RECEIVED_BY_PEER) {
- send_algorithm_->OnPacketAcked(sequence_number,
- transmission_info.bytes_sent);
- } else {
- // It's been abandoned.
- send_algorithm_->OnPacketAbandoned(sequence_number,
- transmission_info.bytes_sent);
- }
unacked_packets_.SetNotPending(sequence_number);
}
@@ -362,7 +365,7 @@ QuicUnackedPacketMap::const_iterator QuicSentPacketManager::MarkPacketHandled(
unacked_packets_.GetTransmissionInfo(newest_transmission));
while (all_transmissions_it != all_transmissions.rend()) {
QuicPacketSequenceNumber previous_transmission = *all_transmissions_it;
- const QuicUnackedPacketMap::TransmissionInfo& transmission_info =
+ const TransmissionInfo& transmission_info =
unacked_packets_.GetTransmissionInfo(previous_transmission);
// If this packet was marked for retransmission, don't bother retransmitting
// it anymore.
@@ -370,9 +373,6 @@ QuicUnackedPacketMap::const_iterator QuicSentPacketManager::MarkPacketHandled(
if (has_crypto_handshake) {
// If it's a crypto handshake packet, discard it and all retransmissions,
// since they won't be acked now that one has been processed.
- if (transmission_info.pending) {
- OnPacketAbandoned(previous_transmission);
- }
unacked_packets_.SetNotPending(previous_transmission);
}
if (!transmission_info.pending) {
@@ -448,10 +448,13 @@ void QuicSentPacketManager::OnRetransmissionTimeout() {
++stats_->crypto_retransmit_count;
RetransmitCryptoPackets();
return;
- case LOSS_MODE:
+ case LOSS_MODE: {
++stats_->loss_timeout_count;
+ QuicByteCount bytes_in_flight = unacked_packets_.bytes_in_flight();
InvokeLossDetection(clock_->Now());
+ MaybeInvokeCongestionEvent(false, bytes_in_flight);
return;
+ }
case TLP_MODE:
// If no tail loss probe can be sent, because there are no retransmittable
// packets, execute a conventional RTO to abandon old packets.
@@ -484,7 +487,7 @@ void QuicSentPacketManager::RetransmitCryptoPackets() {
packet_retransmitted = true;
MarkForRetransmission(sequence_number, HANDSHAKE_RETRANSMISSION);
// Abandon all the crypto retransmissions now so they're not lost later.
- OnPacketAbandoned(sequence_number);
+ unacked_packets_.SetNotPending(sequence_number);
}
DCHECK(packet_retransmitted) << "No crypto packets found to retransmit.";
}
@@ -552,18 +555,6 @@ QuicSentPacketManager::RetransmissionTimeoutMode
return RTO_MODE;
}
-void QuicSentPacketManager::OnPacketAbandoned(
- QuicPacketSequenceNumber sequence_number) {
- const QuicUnackedPacketMap::TransmissionInfo& transmission_info =
- unacked_packets_.GetTransmissionInfo(sequence_number);
- if (transmission_info.pending) {
- LOG_IF(DFATAL, transmission_info.bytes_sent == 0);
- send_algorithm_->OnPacketAbandoned(sequence_number,
- transmission_info.bytes_sent);
- unacked_packets_.SetNotPending(sequence_number);
- }
-}
-
void QuicSentPacketManager::OnIncomingQuicCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame,
const QuicTime& feedback_receive_time) {
@@ -575,6 +566,8 @@ void QuicSentPacketManager::MaybeRetransmitOnAckFrame(
const ReceivedPacketInfo& received_info,
const QuicTime& ack_receive_time) {
// Go through all pending packets up to the largest observed and count nacks.
+ // TODO(ianswett): Now that the SendAlgorithmInterface has changed, it may
+ // make sense to merge this with HandleAckForSentPackets.
for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
it != unacked_packets_.end() &&
it->first <= received_info.largest_observed; ++it) {
@@ -610,14 +603,16 @@ void QuicSentPacketManager::InvokeLossDetection(QuicTime time) {
for (SequenceNumberSet::const_iterator it = lost_packets.begin();
it != lost_packets.end(); ++it) {
QuicPacketSequenceNumber sequence_number = *it;
+ const TransmissionInfo& transmission_info =
+ unacked_packets_.GetTransmissionInfo(sequence_number);
// TODO(ianswett): If it's expected the FEC packet may repair the loss, it
// should be recorded as a loss to the send algorithm, but not retransmitted
// until it's known whether the FEC packet arrived.
++stats_->packets_lost;
- send_algorithm_->OnPacketLost(sequence_number, time);
- OnPacketAbandoned(sequence_number);
+ packets_lost_[sequence_number] = transmission_info;
+ unacked_packets_.SetNotPending(sequence_number);
- if (unacked_packets_.HasRetransmittableFrames(sequence_number)) {
+ if (transmission_info.retransmittable_frames != NULL) {
MarkForRetransmission(sequence_number, LOSS_RETRANSMISSION);
} else {
// Since we will not retransmit this, we need to remove it from
@@ -629,26 +624,26 @@ void QuicSentPacketManager::InvokeLossDetection(QuicTime time) {
}
}
-void QuicSentPacketManager::MaybeUpdateRTT(
+bool QuicSentPacketManager::MaybeUpdateRTT(
const ReceivedPacketInfo& received_info,
const QuicTime& ack_receive_time) {
if (!unacked_packets_.IsUnacked(received_info.largest_observed)) {
- return;
+ return false;
}
// We calculate the RTT based on the highest ACKed sequence number, the lower
// sequence numbers will include the ACK aggregation delay.
- const QuicUnackedPacketMap::TransmissionInfo& transmission_info =
+ const TransmissionInfo& transmission_info =
unacked_packets_.GetTransmissionInfo(received_info.largest_observed);
// Don't update the RTT if it hasn't been sent.
if (transmission_info.sent_time == QuicTime::Zero()) {
- return;
+ return false;
}
QuicTime::Delta send_delta =
ack_receive_time.Subtract(transmission_info.sent_time);
rtt_stats_.UpdateRtt(
send_delta, received_info.delta_time_largest_observed, ack_receive_time);
- send_algorithm_->OnRttUpdated(received_info.largest_observed);
+ return true;
}
QuicTime::Delta QuicSentPacketManager::TimeUntilSend(
@@ -660,7 +655,8 @@ QuicTime::Delta QuicSentPacketManager::TimeUntilSend(
if (transmission_type == TLP_RETRANSMISSION) {
return QuicTime::Delta::Zero();
}
- return send_algorithm_->TimeUntilSend(now, retransmittable);
+ return send_algorithm_->TimeUntilSend(
+ now, unacked_packets_.bytes_in_flight(), retransmittable);
}
// Ensures that the Delayed Ack timer is always set to a value lesser
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index 4530349..fd01eee 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -170,11 +170,6 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
friend class test::QuicConnectionPeer;
friend class test::QuicSentPacketManagerPeer;
- enum ReceivedByPeer {
- RECEIVED_BY_PEER,
- NOT_RECEIVED_BY_PEER,
- };
-
// The retransmission timer is a single timer which switches modes depending
// upon connection state.
enum RetransmissionTimeoutMode {
@@ -195,10 +190,6 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
// Process the incoming ack looking for newly ack'd data packets.
void HandleAckForSentPackets(const ReceivedPacketInfo& received_info);
- // Called when a packet is timed out, such as an RTO. Removes the bytes from
- // the congestion manager, but does not change the congestion window size.
- void OnPacketAbandoned(QuicPacketSequenceNumber sequence_number);
-
// Returns the current retransmission mode.
RetransmissionTimeoutMode GetRetransmissionMode() const;
@@ -221,7 +212,8 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
const QuicTime::Delta GetRetransmissionDelay() const;
// Update the RTT if the ack is for the largest acked sequence number.
- void MaybeUpdateRTT(const ReceivedPacketInfo& received_info,
+ // Returns true if the rtt was updated.
+ bool MaybeUpdateRTT(const ReceivedPacketInfo& received_info,
const QuicTime& ack_receive_time);
// Chooses whether to nack retransmit any packets based on the receipt info.
@@ -233,6 +225,13 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
// necessary.
void InvokeLossDetection(QuicTime time);
+ // Invokes OnCongestionEvent if |rtt_updated| is true, there are pending acks,
+ // or pending losses. Clears pending acks and pending losses afterwards.
+ // |bytes_in_flight| is the number of bytes in flight before the losses or
+ // acks.
+ void MaybeInvokeCongestionEvent(bool rtt_updated,
+ QuicByteCount bytes_in_flight);
+
// Marks |sequence_number| as having been revived by the peer, but not
// received, so the packet remains pending if it is and the congestion control
// does not consider the packet acked.
@@ -244,8 +243,7 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
// iterator to the next remaining unacked packet.
QuicUnackedPacketMap::const_iterator MarkPacketHandled(
QuicPacketSequenceNumber sequence_number,
- QuicTime::Delta delta_largest_observed,
- ReceivedByPeer received_by_peer);
+ QuicTime::Delta delta_largest_observed);
// Request that |sequence_number| be retransmitted after the other pending
// retransmissions. Does not add it to the retransmissions if it's already
@@ -291,6 +289,10 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
size_t max_tail_loss_probes_;
bool using_pacing_;
+ // Sets of packets acked and lost as a result of the last congestion event.
+ SendAlgorithmInterface::CongestionMap packets_acked_;
+ SendAlgorithmInterface::CongestionMap packets_lost_;
+
DISALLOW_COPY_AND_ASSIGN(QuicSentPacketManager);
};
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index 517ea92..9f4d084 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -13,6 +13,9 @@
using std::vector;
using testing::_;
+using testing::ElementsAre;
+using testing::Pair;
+using testing::Pointwise;
using testing::Return;
using testing::StrictMock;
@@ -20,6 +23,10 @@ namespace net {
namespace test {
namespace {
+MATCHER(KeyEq, "") {
+ return std::tr1::get<0>(arg).first == std::tr1::get<1>(arg);
+}
+
class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
protected:
QuicSentPacketManagerTest()
@@ -72,6 +79,44 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
EXPECT_EQ(num_packets, num_retransmittable);
}
+ void ExpectAck(QuicPacketSequenceNumber largest_observed) {
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(
+ true, _, ElementsAre(Pair(largest_observed, _)), _));
+ }
+
+ void ExpectUpdatedRtt(QuicPacketSequenceNumber largest_observed) {
+ EXPECT_CALL(*send_algorithm_,
+ OnCongestionEvent(true, _, _, _));
+ }
+
+ void ExpectAckAndLoss(bool rtt_updated,
+ QuicPacketSequenceNumber largest_observed,
+ QuicPacketSequenceNumber lost_packet) {
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(
+ rtt_updated, _, ElementsAre(Pair(largest_observed, _)),
+ ElementsAre(Pair(lost_packet, _))));
+ }
+
+ // |packets_acked| and |packets_lost| should be in sequence number order.
+ void ExpectAcksAndLosses(bool rtt_updated,
+ QuicPacketSequenceNumber* packets_acked,
+ size_t num_packets_acked,
+ QuicPacketSequenceNumber* packets_lost,
+ size_t num_packets_lost) {
+ vector<QuicPacketSequenceNumber> ack_vector;
+ for (size_t i = 0; i < num_packets_acked; ++i) {
+ ack_vector.push_back(packets_acked[i]);
+ }
+ vector<QuicPacketSequenceNumber> lost_vector;
+ for (size_t i = 0; i < num_packets_lost; ++i) {
+ lost_vector.push_back(packets_lost[i]);
+ }
+ EXPECT_CALL(*send_algorithm_,
+ OnCongestionEvent(rtt_updated, _,
+ Pointwise(KeyEq(), ack_vector),
+ Pointwise(KeyEq(), lost_vector)));
+ }
+
void RetransmitPacket(QuicPacketSequenceNumber old_sequence_number,
QuicPacketSequenceNumber new_sequence_number) {
QuicSentPacketManagerPeer::MarkForRetransmission(
@@ -219,8 +264,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitThenAck) {
ReceivedPacketInfo received_info;
received_info.largest_observed = 2;
received_info.missing_packets.insert(1);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(2, _)).Times(1);
+ ExpectAck(2);
manager_.OnIncomingAck(received_info, clock_.Now());
// Packet 1 is unacked, pending, but not retransmittable.
@@ -239,8 +283,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitThenAckBeforeSend) {
// Ack 1.
ReceivedPacketInfo received_info;
received_info.largest_observed = 1;
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _)).Times(1);
+ ExpectAck(1);
manager_.OnIncomingAck(received_info, clock_.Now());
// There should no longer be a pending retransmission.
@@ -259,8 +302,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitThenAckPrevious) {
clock_.AdvanceTime(rtt);
// Ack 1 but not 2.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(1));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _));
+ ExpectAck(1);
ReceivedPacketInfo received_info;
received_info.largest_observed = 1;
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
@@ -283,8 +325,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitAndSendThenAckPrevious) {
clock_.AdvanceTime(rtt);
// Ack 1 but not 2.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(1));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _));
+ ExpectAck(1);
ReceivedPacketInfo received_info;
received_info.largest_observed = 1;
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
@@ -309,8 +350,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) {
clock_.AdvanceTime(rtt);
// First, ACK packet 1 which makes packet 2 non-retransmittable.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(1));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _));
+ ExpectAck(1);
ReceivedPacketInfo received_info;
received_info.largest_observed = 1;
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
@@ -323,20 +363,15 @@ TEST_F(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) {
// Next, NACK packet 2 three times.
received_info.largest_observed = 3;
received_info.missing_packets.insert(2);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(3));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(3, _));
+ ExpectAck(3);
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
received_info.largest_observed = 4;
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(4));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(4, _));
+ ExpectAck(4);
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
received_info.largest_observed = 5;
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(5));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(5, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _));
- EXPECT_CALL(*send_algorithm_, OnPacketLost(2, _));
+ ExpectAckAndLoss(true, 5, 2);
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
// No packets remain unacked.
@@ -363,7 +398,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckPreviousBeforeSend) {
// send algorithm is not informed that it has been ACK'd.
ReceivedPacketInfo received_info;
received_info.largest_observed = 1;
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(1));
+ ExpectUpdatedRtt(1);
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
// Since 2 was marked for retransmit, when 1 is acked, 2 is discarded.
@@ -384,8 +419,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) {
clock_.AdvanceTime(rtt);
// Ack 1 but not 2 or 3.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(1));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _));
+ ExpectAck(1);
ReceivedPacketInfo received_info;
received_info.largest_observed = 1;
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
@@ -400,9 +434,8 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) {
SendDataPacket(4);
received_info.largest_observed = 4;
received_info.missing_packets.insert(2);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(4));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(3, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(4, _));
+ QuicPacketSequenceNumber acked[] = { 3, 4 };
+ ExpectAcksAndLosses(true, acked, arraysize(acked), NULL, 0);
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
QuicPacketSequenceNumber unacked2[] = { 2 };
@@ -411,10 +444,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) {
SendDataPacket(5);
received_info.largest_observed = 5;
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(5));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(5, _));
- EXPECT_CALL(*send_algorithm_, OnPacketLost(2, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _));
+ ExpectAckAndLoss(true, 5, 2);
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
VerifyUnackedPackets(NULL, 0);
@@ -433,8 +463,8 @@ TEST_F(QuicSentPacketManagerTest, LoseButDontRetransmitRevivedPacket) {
received_info.largest_observed = 3;
received_info.missing_packets.insert(1);
received_info.revived_packets.insert(1);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(2);
+ QuicPacketSequenceNumber acked[] = { 2, 3 };
+ ExpectAcksAndLosses(true, acked, arraysize(acked), NULL, 0);
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
EXPECT_FALSE(manager_.HasPendingRetransmissions());
@@ -446,10 +476,7 @@ TEST_F(QuicSentPacketManagerTest, LoseButDontRetransmitRevivedPacket) {
// Ack the 4th packet and expect the 1st to be considered lost.
received_info.largest_observed = 4;
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(4, _));
+ ExpectAckAndLoss(true, 4, 1);
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
EXPECT_FALSE(manager_.HasPendingRetransmissions());
@@ -467,10 +494,9 @@ TEST_F(QuicSentPacketManagerTest, MarkLostThenReviveAndDontRetransmitPacket) {
ReceivedPacketInfo received_info;
received_info.largest_observed = 4;
received_info.missing_packets.insert(1);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(3);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _));
+ QuicPacketSequenceNumber acked[] = { 2, 3, 4 };
+ QuicPacketSequenceNumber lost[] = { 1 };
+ ExpectAcksAndLosses(true, acked, arraysize(acked), lost, arraysize(lost));
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
EXPECT_TRUE(manager_.HasPendingRetransmissions());
@@ -483,8 +509,7 @@ TEST_F(QuicSentPacketManagerTest, MarkLostThenReviveAndDontRetransmitPacket) {
// removed from pending retransmissions map.
received_info.largest_observed = 5;
received_info.revived_packets.insert(1);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(5, _));
+ ExpectAck(5);
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
EXPECT_FALSE(manager_.HasPendingRetransmissions());
@@ -506,9 +531,9 @@ TEST_F(QuicSentPacketManagerTest, TruncatedAck) {
received_info.missing_packets.insert(3);
received_info.missing_packets.insert(4);
received_info.is_truncated = true;
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _));
+
+ QuicPacketSequenceNumber lost[] = { 1 };
+ ExpectAcksAndLosses(true, NULL, 0, lost, arraysize(lost));
manager_.OnIncomingAck(received_info, clock_.Now());
// High water mark will be raised.
@@ -534,8 +559,7 @@ TEST_F(QuicSentPacketManagerTest, AckPreviousTransmissionThenTruncatedAck) {
ReceivedPacketInfo received_info;
received_info.largest_observed = 2;
received_info.missing_packets.insert(1);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(2, _));
+ ExpectAck(2);
manager_.OnIncomingAck(received_info, clock_.Now());
EXPECT_TRUE(manager_.IsUnacked(4));
}
@@ -549,9 +573,7 @@ TEST_F(QuicSentPacketManagerTest, AckPreviousTransmissionThenTruncatedAck) {
received_info.missing_packets.insert(5);
received_info.missing_packets.insert(6);
received_info.is_truncated = true;
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _));
- EXPECT_CALL(*send_algorithm_, OnPacketLost(3, _));
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(3, _));
+ ExpectAckAndLoss(false, 1, 3);
manager_.OnIncomingAck(received_info, clock_.Now());
}
@@ -610,7 +632,7 @@ TEST_F(QuicSentPacketManagerTest, GetLeastUnackedPacketAndDiscard) {
manager_.DiscardUnackedPacket(1);
EXPECT_EQ(2u, manager_.GetLeastUnackedSentPacket());
- // Ack 2.
+ // Ack 2, which has never been sent, so there's no rtt update.
ReceivedPacketInfo received_info;
received_info.largest_observed = 2;
manager_.OnIncomingAck(received_info, clock_.Now());
@@ -650,82 +672,6 @@ TEST_F(QuicSentPacketManagerTest, GetSentTime) {
EXPECT_EQ(sent_time, QuicSentPacketManagerPeer::GetSentTime(&manager_, 2));
}
-TEST_F(QuicSentPacketManagerTest, FackRetransmit17Packets) {
- const size_t kNumSentPackets = 25;
- // Transmit 25 packets.
- for (QuicPacketSequenceNumber i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
-
- // Nack the first 19 packets 3 times, which does not trigger early retransmit.
- const size_t kLargestObserved = 20;
- ReceivedPacketInfo received_info;
- received_info.largest_observed = kLargestObserved;
- received_info.delta_time_largest_observed =
- QuicTime::Delta::FromMilliseconds(5);
- for (size_t i = 1; i < kLargestObserved; ++i) {
- received_info.missing_packets.insert(i);
- }
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_,
- OnPacketAcked(kLargestObserved, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(17);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(17);
- manager_.OnIncomingAck(received_info, clock_.Now());
- EXPECT_EQ(
- 17u, QuicSentPacketManagerPeer::GetPendingRetransmissionCount(&manager_));
- for (size_t i = 1; i < kLargestObserved; ++i) {
- EXPECT_EQ(kLargestObserved - i,
- QuicSentPacketManagerPeer::GetNackCount(&manager_, i));
- }
-
- // Now receive the second packet, out of order, which should lose and
- // retransmit nothing, because it does not increase the largest observed.
- // No acks are registered, because the packet was already lost.
- received_info.missing_packets.erase(2);
- manager_.OnIncomingAck(received_info, clock_.Now());
-}
-
-TEST_F(QuicSentPacketManagerTest, FackRetransmit14PacketsAlternateAcks) {
- const size_t kNumSentPackets = 30;
- // Transmit 15 packets of data and 15 ack packets. The send algorithm returns
- // false to inform the sent packet manager not to count acks as pending.
- for (QuicPacketSequenceNumber i = 1; i <= kNumSentPackets; ++i) {
- if (i % 2 == 0) {
- SendAckPacket(i);
- } else {
- SendDataPacket(i);
- }
- }
-
- // Nack the first 29 packets 3 times.
- ReceivedPacketInfo received_info;
- received_info.largest_observed = kNumSentPackets;
- received_info.delta_time_largest_observed =
- QuicTime::Delta::FromMilliseconds(5);
- for (size_t i = 1; i < kNumSentPackets; ++i) {
- received_info.missing_packets.insert(i);
- }
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(14);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(14);
- manager_.OnIncomingAck(received_info, clock_.Now());
- ASSERT_EQ(
- 14u, QuicSentPacketManagerPeer::GetPendingRetransmissionCount(&manager_));
- // Only non-ack packets have a nack count.
- for (size_t i = 1; i < kNumSentPackets; i += 2) {
- EXPECT_EQ(kNumSentPackets - i,
- QuicSentPacketManagerPeer::GetNackCount(&manager_, i));
- }
-
- // Ensure only the odd packets were retransmitted, since the others were not
- // retransmittable(ie: acks).
- for (size_t i = 0; i < 13; ++i) {
- EXPECT_EQ(1 + 2 * i, manager_.NextPendingRetransmission().sequence_number);
- manager_.OnRetransmittedPacket(1 + 2 * i, kNumSentPackets + 1 + i);
- }
-}
-
TEST_F(QuicSentPacketManagerTest, AckAckAndUpdateRtt) {
SendDataPacket(1);
SendAckPacket(2);
@@ -736,16 +682,14 @@ TEST_F(QuicSentPacketManagerTest, AckAckAndUpdateRtt) {
received_info.delta_time_largest_observed =
QuicTime::Delta::FromMilliseconds(5);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _)).Times(1);
+ ExpectAck(1);
manager_.OnIncomingAck(received_info, clock_.Now());
SendAckPacket(3);
// Now ack the ack and expect only an RTT update.
received_info.largest_observed = 3;
-
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
+ ExpectUpdatedRtt(3);
manager_.OnIncomingAck(received_info, clock_.Now());
}
@@ -755,9 +699,7 @@ TEST_F(QuicSentPacketManagerTest, Rtt) {
SendDataPacket(sequence_number);
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(sequence_number));
- EXPECT_CALL(*send_algorithm_,
- OnPacketAcked(sequence_number, _)).Times(1);
+ ExpectAck(sequence_number);
ReceivedPacketInfo received_info;
received_info.largest_observed = sequence_number;
received_info.delta_time_largest_observed =
@@ -776,9 +718,7 @@ TEST_F(QuicSentPacketManagerTest, RttWithInvalidDelta) {
SendDataPacket(sequence_number);
clock_.AdvanceTime(expected_rtt);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(sequence_number));
- EXPECT_CALL(*send_algorithm_,
- OnPacketAcked(sequence_number, _)).Times(1);
+ ExpectAck(sequence_number);
ReceivedPacketInfo received_info;
received_info.largest_observed = sequence_number;
received_info.delta_time_largest_observed =
@@ -796,9 +736,7 @@ TEST_F(QuicSentPacketManagerTest, RttWithInfiniteDelta) {
SendDataPacket(sequence_number);
clock_.AdvanceTime(expected_rtt);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(sequence_number));
- EXPECT_CALL(*send_algorithm_,
- OnPacketAcked(sequence_number, _)).Times(1);
+ ExpectAck(sequence_number);
ReceivedPacketInfo received_info;
received_info.largest_observed = sequence_number;
received_info.delta_time_largest_observed = QuicTime::Delta::Infinite();
@@ -815,9 +753,7 @@ TEST_F(QuicSentPacketManagerTest, RttZeroDelta) {
SendDataPacket(sequence_number);
clock_.AdvanceTime(expected_rtt);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(sequence_number));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(sequence_number, _))
- .Times(1);
+ ExpectAck(sequence_number);
ReceivedPacketInfo received_info;
received_info.largest_observed = sequence_number;
received_info.delta_time_largest_observed = QuicTime::Delta::Zero();
@@ -844,8 +780,7 @@ TEST_F(QuicSentPacketManagerTest, TailLossProbeTimeout) {
EXPECT_FALSE(manager_.HasPendingRetransmissions());
// Ack the third and ensure the first two are still pending.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(3, _));
+ ExpectAck(3);
ReceivedPacketInfo received_info;
received_info.largest_observed = 3;
received_info.missing_packets.insert(1);
@@ -856,8 +791,8 @@ TEST_F(QuicSentPacketManagerTest, TailLossProbeTimeout) {
// Acking two more packets will lose both of them due to nacks.
received_info.largest_observed = 5;
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(2);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(2);
+ QuicPacketSequenceNumber lost[] = { 1, 2 };
+ ExpectAcksAndLosses(false, NULL, 0, lost, arraysize(lost));
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
EXPECT_FALSE(manager_.HasPendingRetransmissions());
@@ -909,7 +844,6 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeout) {
EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
// The first retransmits 2 packets.
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(2);
manager_.OnRetransmissionTimeout();
RetransmitNextPacket(6);
RetransmitNextPacket(7);
@@ -917,7 +851,6 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeout) {
EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
// The second retransmits 2 packets.
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(2);
manager_.OnRetransmissionTimeout();
RetransmitNextPacket(8);
RetransmitNextPacket(9);
@@ -926,8 +859,8 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeout) {
// Now ack the two crypto packets and the speculatively encrypted request,
// and ensure the first four crypto packets get abandoned, but not lost.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(5);
+ QuicPacketSequenceNumber acked[] = { 3, 4, 5, 8, 9 };
+ ExpectAcksAndLosses(true, acked, arraysize(acked), NULL, 0);
ReceivedPacketInfo received_info;
received_info.largest_observed = 9;
received_info.missing_packets.insert(1);
@@ -952,7 +885,6 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) {
EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
// The first retransmission timeout retransmits 2 crypto packets.
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(2);
manager_.OnRetransmissionTimeout();
RetransmitNextPacket(6);
RetransmitNextPacket(7);
@@ -961,7 +893,6 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) {
// Now act like a version negotiation packet arrived, which would cause all
// unacked packets to be retransmitted.
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(5);
manager_.RetransmitUnackedPackets(ALL_PACKETS);
// Ensure the first two pending packets are the crypto retransmits.
@@ -980,19 +911,16 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) {
EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
// Retransmit the crypto packet as 2.
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(1);
manager_.OnRetransmissionTimeout();
RetransmitNextPacket(2);
// Retransmit the crypto packet as 3.
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(1);
manager_.OnRetransmissionTimeout();
RetransmitNextPacket(3);
// Now ack the first crypto packet, and ensure the second gets abandoned and
// removed from unacked_packets.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(1);
+ ExpectUpdatedRtt(2);
ReceivedPacketInfo received_info;
received_info.largest_observed = 2;
received_info.missing_packets.insert(1);
@@ -1013,7 +941,6 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) {
EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
// Retransmit 2 crypto packets, but not the serialized packet.
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(2);
manager_.OnRetransmissionTimeout();
RetransmitNextPacket(6);
RetransmitNextPacket(7);
@@ -1028,13 +955,11 @@ TEST_F(QuicSentPacketManagerTest,
EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
// Retransmit the crypto packet as 2.
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(1);
manager_.OnRetransmissionTimeout();
RetransmitNextPacket(2);
// Now retransmit all the unacked packets, which occurs when there is a
// version negotiation.
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(1);
manager_.RetransmitUnackedPackets(ALL_PACKETS);
QuicPacketSequenceNumber unacked[] = { 1, 2 };
VerifyUnackedPackets(unacked, arraysize(unacked));
@@ -1094,7 +1019,6 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeCryptoHandshake) {
// Retransmit the packet by invoking the retransmission timeout.
clock_.AdvanceTime(srtt.Multiply(1.5));
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _));
manager_.OnRetransmissionTimeout();
RetransmitNextPacket(2);
@@ -1163,7 +1087,7 @@ TEST_F(QuicSentPacketManagerTest, GetTransmissionTimeRTO) {
ReceivedPacketInfo received_info;
received_info.largest_observed = 2;
received_info.missing_packets.insert(1);
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
+ ExpectUpdatedRtt(2);
manager_.OnIncomingAck(received_info, clock_.ApproximateNow());
expected_time = clock_.Now().Add(expected_rto_delay);
@@ -1224,8 +1148,7 @@ TEST_F(QuicSentPacketManagerTest, GetLossDelay) {
// Handle an ack which causes the loss algorithm to be evaluated and
// set the loss timeout.
- EXPECT_CALL(*send_algorithm_, OnRttUpdated(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(2, _));
+ ExpectAck(2);
EXPECT_CALL(*loss_algorithm, DetectLostPackets(_, _, _, _))
.WillOnce(Return(SequenceNumberSet()));
ReceivedPacketInfo received_info;
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index ba20d50..6d749ec 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -7,6 +7,7 @@
#include "base/stl_util.h"
#include "net/quic/crypto/proof_verifier.h"
#include "net/quic/quic_connection.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_headers_stream.h"
#include "net/ssl/ssl_info.h"
@@ -216,6 +217,7 @@ void QuicSession::OnConnectionClosed(QuicErrorCode error, bool from_peer) {
void QuicSession::OnWindowUpdateFrames(
const vector<QuicWindowUpdateFrame>& frames) {
+ bool connection_window_updated = false;
for (size_t i = 0; i < frames.size(); ++i) {
// Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
// assume that it still exists.
@@ -223,10 +225,14 @@ void QuicSession::OnWindowUpdateFrames(
if (stream_id == 0) {
// This is a window update that applies to the connection, rather than an
// individual stream.
- // TODO(rjshade): Adjust connection level flow control window.
DVLOG(1) << ENDPOINT
<< "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)) {
+ connection_window_updated = true;
+ }
continue;
}
@@ -235,6 +241,12 @@ void QuicSession::OnWindowUpdateFrames(
stream->OnWindowUpdateFrame(frames[i]);
}
}
+
+ // Connection level flow control window has increased, so blocked streams can
+ // write again.
+ if (connection_window_updated) {
+ OnCanWrite();
+ }
}
void QuicSession::OnBlockedFrames(const vector<QuicBlockedFrame>& frames) {
@@ -260,7 +272,7 @@ void QuicSession::OnCanWrite() {
connection_.get(), QuicConnection::NO_ACK);
for (size_t i = 0; i < num_writes; ++i) {
if (!write_blocked_streams_.HasWriteBlockedStreams()) {
- // Writing one stream removed another?! Something's broken.
+ // Writing one stream removed another!? Something's broken.
LOG(DFATAL) << "WriteBlockedStream is missing";
connection_->CloseConnection(QUIC_INTERNAL_ERROR, false);
return;
@@ -385,6 +397,10 @@ void QuicSession::OnConfigNegotiated() {
new_flow_control_send_window);
it++;
}
+
+ // Update connection level window.
+ connection()->flow_controller()->UpdateSendWindowOffset(
+ new_flow_control_send_window);
}
}
@@ -554,10 +570,6 @@ void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) {
#ifndef NDEBUG
ReliableQuicStream* stream = GetStream(id);
if (stream != NULL) {
- if (stream->flow_controller()->IsBlocked()) {
- LOG(DFATAL) << ENDPOINT << "Stream " << id
- << " is flow control blocked and write blocked!";
- }
LOG_IF(DFATAL, priority != stream->EffectivePriority())
<< ENDPOINT << "Stream " << id
<< "Priorities do not match. Got: " << priority
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index 019e27b..25545ca 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -366,7 +366,7 @@ TEST_P(QuicSessionTest, OnCanWriteBundlesStreams) {
session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority);
- EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _)).WillRepeatedly(
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillRepeatedly(
Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm, GetCongestionWindow()).WillOnce(
Return(kMaxPacketSize * 10));
@@ -402,13 +402,13 @@ TEST_P(QuicSessionTest, OnCanWriteCongestionControlBlocks) {
session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority);
StreamBlocker stream2_blocker(&session_, stream2->id());
- EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _)).WillOnce(Return(
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillOnce(Return(
QuicTime::Delta::Zero()));
EXPECT_CALL(*stream2, OnCanWrite());
- EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _)).WillOnce(Return(
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillOnce(Return(
QuicTime::Delta::Zero()));
EXPECT_CALL(*stream6, OnCanWrite());
- EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _)).WillOnce(Return(
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillOnce(Return(
QuicTime::Delta::Infinite()));
// stream4->OnCanWrite is not called.
@@ -416,14 +416,14 @@ TEST_P(QuicSessionTest, OnCanWriteCongestionControlBlocks) {
EXPECT_TRUE(session_.HasPendingWrites());
// Still congestion-control blocked.
- EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _)).WillOnce(Return(
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillOnce(Return(
QuicTime::Delta::Infinite()));
session_.OnCanWrite();
EXPECT_TRUE(session_.HasPendingWrites());
// stream4->OnCanWrite is called once the connection stops being
// congestion-control blocked.
- EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _)).WillOnce(Return(
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _, _)).WillOnce(Return(
QuicTime::Delta::Zero()));
EXPECT_CALL(*stream4, OnCanWrite());
session_.OnCanWrite();
diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc
index 8f59064..61b4f7c 100644
--- a/net/quic/quic_stream_sequencer.cc
+++ b/net/quic/quic_stream_sequencer.cc
@@ -67,7 +67,7 @@ bool QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) {
data.iovec()[i].iov_len);
}
num_bytes_consumed_ += bytes_consumed;
- stream_->flow_controller()->AddBytesConsumed(bytes_consumed);
+ stream_->AddBytesConsumed(bytes_consumed);
stream_->MaybeSendWindowUpdate();
if (MaybeCloseStream()) {
@@ -95,7 +95,7 @@ bool QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) {
byte_offset, string(static_cast<char*>(iov.iov_base), iov.iov_len)));
byte_offset += iov.iov_len;
num_bytes_buffered_ += iov.iov_len;
- stream_->flow_controller()->AddBytesBuffered(iov.iov_len);
+ stream_->AddBytesBuffered(iov.iov_len);
}
return true;
}
@@ -247,8 +247,8 @@ void QuicStreamSequencer::RecordBytesConsumed(size_t bytes_consumed) {
num_bytes_consumed_ += bytes_consumed;
num_bytes_buffered_ -= bytes_consumed;
- stream_->flow_controller()->AddBytesConsumed(bytes_consumed);
- stream_->flow_controller()->RemoveBytesBuffered(bytes_consumed);
+ stream_->AddBytesConsumed(bytes_consumed);
+ stream_->RemoveBytesBuffered(bytes_consumed);
stream_->MaybeSendWindowUpdate();
}
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc
index 8d0a4b7..ddf30ec 100644
--- a/net/quic/quic_unacked_packet_map.cc
+++ b/net/quic/quic_unacked_packet_map.cc
@@ -13,44 +13,6 @@ using std::max;
namespace net {
-QuicUnackedPacketMap::TransmissionInfo::TransmissionInfo()
- : retransmittable_frames(NULL),
- sequence_number_length(PACKET_1BYTE_SEQUENCE_NUMBER),
- sent_time(QuicTime::Zero()),
- bytes_sent(0),
- nack_count(0),
- all_transmissions(NULL),
- pending(false) { }
-
-QuicUnackedPacketMap::TransmissionInfo::TransmissionInfo(
- RetransmittableFrames* retransmittable_frames,
- QuicPacketSequenceNumber sequence_number,
- QuicSequenceNumberLength sequence_number_length)
- : retransmittable_frames(retransmittable_frames),
- sequence_number_length(sequence_number_length),
- sent_time(QuicTime::Zero()),
- bytes_sent(0),
- nack_count(0),
- all_transmissions(new SequenceNumberSet),
- pending(false) {
- all_transmissions->insert(sequence_number);
-}
-
-QuicUnackedPacketMap::TransmissionInfo::TransmissionInfo(
- RetransmittableFrames* retransmittable_frames,
- QuicPacketSequenceNumber sequence_number,
- QuicSequenceNumberLength sequence_number_length,
- SequenceNumberSet* all_transmissions)
- : retransmittable_frames(retransmittable_frames),
- sequence_number_length(sequence_number_length),
- sent_time(QuicTime::Zero()),
- bytes_sent(0),
- nack_count(0),
- all_transmissions(all_transmissions),
- pending(false) {
- all_transmissions->insert(sequence_number);
-}
-
QuicUnackedPacketMap::QuicUnackedPacketMap()
: largest_sent_packet_(0),
bytes_in_flight_(0),
@@ -176,6 +138,7 @@ void QuicUnackedPacketMap::RemovePacket(
}
delete transmission_info.retransmittable_frames;
}
+ DCHECK(!transmission_info.pending);
unacked_packets_.erase(it);
}
@@ -251,9 +214,8 @@ bool QuicUnackedPacketMap::HasPendingPackets() const {
return false;
}
-const QuicUnackedPacketMap::TransmissionInfo&
- QuicUnackedPacketMap::GetTransmissionInfo(
- QuicPacketSequenceNumber sequence_number) const {
+const TransmissionInfo& QuicUnackedPacketMap::GetTransmissionInfo(
+ QuicPacketSequenceNumber sequence_number) const {
return unacked_packets_.find(sequence_number)->second;
}
diff --git a/net/quic/quic_unacked_packet_map.h b/net/quic/quic_unacked_packet_map.h
index 552c0d6..eab4f36 100644
--- a/net/quic/quic_unacked_packet_map.h
+++ b/net/quic/quic_unacked_packet_map.h
@@ -15,37 +15,6 @@ namespace net {
// contain the same data (via retransmissions)
class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
public:
- struct NET_EXPORT_PRIVATE TransmissionInfo {
- // Used by STL when assigning into a map.
- TransmissionInfo();
-
- // Constructs a Transmission with a new all_tranmissions set
- // containing |sequence_number|.
- TransmissionInfo(RetransmittableFrames* retransmittable_frames,
- QuicPacketSequenceNumber sequence_number,
- QuicSequenceNumberLength sequence_number_length);
-
- // Constructs a Transmission with the specified |all_tranmissions| set
- // and inserts |sequence_number| into it.
- TransmissionInfo(RetransmittableFrames* retransmittable_frames,
- QuicPacketSequenceNumber sequence_number,
- QuicSequenceNumberLength sequence_number_length,
- SequenceNumberSet* all_transmissions);
-
- RetransmittableFrames* retransmittable_frames;
- QuicSequenceNumberLength sequence_number_length;
- // Zero when the packet is serialized, non-zero once it's sent.
- QuicTime sent_time;
- // Zero when the packet is serialized, non-zero once it's sent.
- QuicByteCount bytes_sent;
- size_t nack_count;
- // Stores the sequence numbers of all transmissions of this packet.
- // Can never be null.
- SequenceNumberSet* all_transmissions;
- // Pending packets have not been abandoned or lost.
- bool pending;
- };
-
QuicUnackedPacketMap();
~QuicUnackedPacketMap();
@@ -94,6 +63,11 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
return largest_sent_packet_;
}
+ // Returns the sum of the bytes in all pending packets.
+ QuicByteCount bytes_in_flight() const {
+ return bytes_in_flight_;
+ }
+
// Returns the smallest sequence number of a serialized packet which has not
// been acked by the peer. If there are no unacked packets, returns 0.
QuicPacketSequenceNumber GetLeastUnackedSentPacket() const;
diff --git a/net/quic/quic_write_blocked_list.h b/net/quic/quic_write_blocked_list.h
index 1e58e40..cddd58f 100644
--- a/net/quic/quic_write_blocked_list.h
+++ b/net/quic/quic_write_blocked_list.h
@@ -5,6 +5,8 @@
#ifndef NET_QUIC_QUIC_WRITE_BLOCKED_LIST_H_
#define NET_QUIC_QUIC_WRITE_BLOCKED_LIST_H_
+#include <set>
+
#include "net/base/net_export.h"
#include "net/quic/quic_protocol.h"
#include "net/spdy/write_blocked_list.h"
@@ -47,14 +49,18 @@ class NET_EXPORT_PRIVATE QuicWriteBlockedList {
if (crypto_stream_blocked_) {
crypto_stream_blocked_ = false;
return kCryptoStreamId;
- } else if (headers_stream_blocked_) {
+ }
+
+ if (headers_stream_blocked_) {
headers_stream_blocked_ = false;
return kHeadersStreamId;
- } else {
- SpdyPriority priority =
- base_write_blocked_list_.GetHighestPriorityWriteBlockedList();
- return base_write_blocked_list_.PopFront(priority);
}
+
+ SpdyPriority priority =
+ base_write_blocked_list_.GetHighestPriorityWriteBlockedList();
+ QuicStreamId id = base_write_blocked_list_.PopFront(priority);
+ blocked_streams_.erase(id);
+ return id;
}
void PushBack(QuicStreamId stream_id, QuicPriority priority) {
@@ -62,14 +68,25 @@ class NET_EXPORT_PRIVATE QuicWriteBlockedList {
DCHECK_EQ(kHighestPriority, priority);
// TODO(avd) Add DCHECK(!crypto_stream_blocked_)
crypto_stream_blocked_ = true;
- } else if (stream_id == kHeadersStreamId) {
+ return;
+ }
+
+ if (stream_id == kHeadersStreamId) {
DCHECK_EQ(kHighestPriority, priority);
// TODO(avd) Add DCHECK(!headers_stream_blocked_);
headers_stream_blocked_ = true;
- } else {
- base_write_blocked_list_.PushBack(
- stream_id, static_cast<SpdyPriority>(priority));
+ return;
+ }
+
+ if (blocked_streams_.find(stream_id) != blocked_streams_.end()) {
+ DVLOG(1) << "Stream " << stream_id << " already in write blocked list.";
+ return;
}
+
+ base_write_blocked_list_.PushBack(
+ stream_id, static_cast<SpdyPriority>(priority));
+ blocked_streams_.insert(stream_id);
+ return;
}
private:
@@ -77,6 +94,11 @@ class NET_EXPORT_PRIVATE QuicWriteBlockedList {
bool crypto_stream_blocked_;
bool headers_stream_blocked_;
+ // Keep track of write blocked streams in a set for faster membership checking
+ // than iterating over the base_write_blocked_list_. The contents of this set
+ // should mirror the contents of base_write_blocked_list_.
+ std::set<QuicStreamId> blocked_streams_;
+
DISALLOW_COPY_AND_ASSIGN(QuicWriteBlockedList);
};
diff --git a/net/quic/quic_write_blocked_list_test.cc b/net/quic/quic_write_blocked_list_test.cc
index d8633ea..6f6bba6 100644
--- a/net/quic/quic_write_blocked_list_test.cc
+++ b/net/quic/quic_write_blocked_list_test.cc
@@ -83,6 +83,30 @@ TEST(QuicWriteBlockedListTest, VerifyHeadersStream) {
EXPECT_FALSE(write_blocked_list.HasWriteBlockedStreams());
}
+TEST(QuicWriteBlockedListTest, NoDuplicateEntries) {
+ // Test that QuicWriteBlockedList doesn't allow duplicate entries.
+ QuicWriteBlockedList write_blocked_list;
+
+ // Try to add a stream to the write blocked list multiple times at the same
+ // priority.
+ const QuicStreamId kBlockedId = 5;
+ write_blocked_list.PushBack(kBlockedId,
+ QuicWriteBlockedList::kHighestPriority);
+ write_blocked_list.PushBack(kBlockedId,
+ QuicWriteBlockedList::kHighestPriority);
+ write_blocked_list.PushBack(kBlockedId,
+ QuicWriteBlockedList::kHighestPriority);
+
+ // This should only result in one blocked stream being added.
+ EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedStreams());
+
+ // 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());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index c19dcbf..218bb09 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -131,7 +131,8 @@ ReliableQuicStream::ReliableQuicStream(QuicStreamId id, QuicSession* session)
session_->config()->ReceivedInitialFlowControlWindowBytes() :
kDefaultFlowControlSendWindow,
session_->connection()->max_flow_control_receive_window_bytes(),
- session_->connection()->max_flow_control_receive_window_bytes()) {
+ session_->connection()->max_flow_control_receive_window_bytes()),
+ connection_flow_controller_(session_->connection()->flow_controller()) {
}
ReliableQuicStream::~ReliableQuicStream() {
@@ -154,7 +155,8 @@ bool ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
bool accepted = sequencer_.OnStreamFrame(frame);
- if (flow_controller_.FlowControlViolation()) {
+ if (flow_controller_.FlowControlViolation() ||
+ connection_flow_controller_->FlowControlViolation()) {
session_->connection()->SendConnectionClose(QUIC_FLOW_CONTROL_ERROR);
return false;
}
@@ -165,6 +167,7 @@ bool ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
void ReliableQuicStream::MaybeSendWindowUpdate() {
flow_controller_.MaybeSendWindowUpdate(session()->connection());
+ connection_flow_controller_->MaybeSendWindowUpdate(session()->connection());
}
int ReliableQuicStream::num_frames_received() const {
@@ -294,6 +297,18 @@ void ReliableQuicStream::OnCanWrite() {
}
}
+void ReliableQuicStream::MaybeSendBlocked() {
+ flow_controller_.MaybeSendBlocked(session()->connection());
+ connection_flow_controller_->MaybeSendBlocked(session()->connection());
+ // If we are connection level flow control blocked, then add the stream
+ // to the write blocked list. It will be given a chance to write when a
+ // connection level WINDOW_UPDATE arrives.
+ if (connection_flow_controller_->IsBlocked() &&
+ !flow_controller_.IsBlocked()) {
+ session_->MarkWriteBlocked(id(), EffectivePriority());
+ }
+}
+
QuicConsumedData ReliableQuicStream::WritevData(
const struct iovec* iov,
int iov_count,
@@ -312,11 +327,15 @@ QuicConsumedData ReliableQuicStream::WritevData(
if (flow_controller_.IsEnabled()) {
// How much data we are allowed to write from flow control.
- size_t send_window = flow_controller_.SendWindowSize();
+ uint64 send_window = flow_controller_.SendWindowSize();
+ if (connection_flow_controller_->IsEnabled()) {
+ send_window =
+ min(send_window, connection_flow_controller_->SendWindowSize());
+ }
if (send_window == 0 && !fin_with_zero_data) {
// Quick return if we can't send anything.
- flow_controller_.MaybeSendBlocked(session()->connection());
+ MaybeSendBlocked();
return QuicConsumedData(0, false);
}
@@ -337,11 +356,11 @@ QuicConsumedData ReliableQuicStream::WritevData(
id(), data, stream_bytes_written_, fin, ack_notifier_delegate);
stream_bytes_written_ += consumed_data.bytes_consumed;
- flow_controller_.AddBytesSent(consumed_data.bytes_consumed);
+ AddBytesSent(consumed_data.bytes_consumed);
if (consumed_data.bytes_consumed == write_length) {
if (!fin_with_zero_data) {
- flow_controller_.MaybeSendBlocked(session()->connection());
+ MaybeSendBlocked();
}
if (fin && consumed_data.fin_consumed) {
fin_sent_ = true;
@@ -412,8 +431,42 @@ void ReliableQuicStream::OnWindowUpdateFrame(
// TODO(rjshade): This does not respect priorities (e.g. multiple
// outstanding POSTs are unblocked on arrival of
// SHLO with initial window).
+ // As long as the connection is not flow control blocked, we can write!
OnCanWrite();
}
}
+void ReliableQuicStream::AddBytesBuffered(uint64 bytes) {
+ if (flow_controller_.IsEnabled()) {
+ flow_controller_.AddBytesBuffered(bytes);
+ connection_flow_controller_->AddBytesBuffered(bytes);
+ }
+}
+
+void ReliableQuicStream::RemoveBytesBuffered(uint64 bytes) {
+ if (flow_controller_.IsEnabled()) {
+ flow_controller_.RemoveBytesBuffered(bytes);
+ connection_flow_controller_->RemoveBytesBuffered(bytes);
+ }
+}
+
+void ReliableQuicStream::AddBytesSent(uint64 bytes) {
+ if (flow_controller_.IsEnabled()) {
+ flow_controller_.AddBytesSent(bytes);
+ connection_flow_controller_->AddBytesSent(bytes);
+ }
+}
+
+void ReliableQuicStream::AddBytesConsumed(uint64 bytes) {
+ if (flow_controller_.IsEnabled()) {
+ flow_controller_.AddBytesConsumed(bytes);
+ connection_flow_controller_->AddBytesConsumed(bytes);
+ }
+}
+
+bool ReliableQuicStream::IsFlowControlBlocked() {
+ return flow_controller_.IsBlocked() ||
+ connection_flow_controller_->IsBlocked();
+}
+
} // namespace net
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 3776865..90cdac44 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -103,6 +103,19 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
QuicFlowController* flow_controller() { return &flow_controller_; }
+ // Called by the stream sequeuncer as bytes are added to the buffer.
+ void AddBytesBuffered(uint64 bytes);
+ // Called by the stream sequeuncer as bytes are removed from the buffer.
+ void RemoveBytesBuffered(uint64 bytes);
+ // Called when bytese are sent to the peer.
+ void AddBytesSent(uint64 bytes);
+ // Called by the stream sequeuncer as bytes are consumed from the buffer.
+ void AddBytesConsumed(uint64 bytes);
+
+ // Returns true if the stream is flow control blocked, by the stream flow
+ // control window or the connection flow control window.
+ bool IsFlowControlBlocked();
+
protected:
// Sends as much of 'data' to the connection as the connection will consume,
// and then buffers any remaining data in queued_data_.
@@ -164,6 +177,11 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
// Calculates and returns total number of bytes this stream has received.
uint64 TotalReceivedBytes() const;
+ // Calls MaybeSendBlocked on our flow controller, and connection level flow
+ // controller. If we are flow control blocked, marks this stream as write
+ // blocked.
+ void MaybeSendBlocked();
+
std::list<PendingData> queued_data_;
QuicStreamSequencer sequencer_;
@@ -199,6 +217,9 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
QuicFlowController flow_controller_;
+ // The connection level flow controller. Not owned.
+ QuicFlowController* connection_flow_controller_;
+
DISALLOW_COPY_AND_ASSIGN(ReliableQuicStream);
};
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index 4d71ca2..d1ad909 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -394,6 +394,9 @@ 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);
+ }
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
@@ -446,6 +449,9 @@ 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);
+ }
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 620dfe9..f4074a5 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -400,16 +400,16 @@ class MockSendAlgorithm : public SendAlgorithmInterface {
MOCK_METHOD2(OnIncomingQuicCongestionFeedbackFrame,
void(const QuicCongestionFeedbackFrame&,
QuicTime feedback_receive_time));
- MOCK_METHOD2(OnPacketAcked,
- void(QuicPacketSequenceNumber, QuicByteCount));
- MOCK_METHOD2(OnPacketLost, void(QuicPacketSequenceNumber, QuicTime));
+ MOCK_METHOD4(OnCongestionEvent, void(bool rtt_updated,
+ QuicByteCount bytes_in_flight,
+ const CongestionMap& acked_packets,
+ const CongestionMap& lost_packets));
MOCK_METHOD4(OnPacketSent,
bool(QuicTime sent_time, QuicPacketSequenceNumber, QuicByteCount,
HasRetransmittableData));
MOCK_METHOD1(OnRetransmissionTimeout, void(bool));
- MOCK_METHOD2(OnPacketAbandoned, void(QuicPacketSequenceNumber sequence_number,
- QuicByteCount abandoned_bytes));
- MOCK_METHOD2(TimeUntilSend, QuicTime::Delta(QuicTime now,
+ MOCK_METHOD3(TimeUntilSend, QuicTime::Delta(QuicTime now,
+ QuicByteCount bytes_in_flight,
HasRetransmittableData));
MOCK_CONST_METHOD0(BandwidthEstimate, QuicBandwidth(void));
MOCK_METHOD1(OnRttUpdated, void(QuicPacketSequenceNumber));
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 3daf8bc..ef394b9 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -166,6 +166,9 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
if (negotiated_version_ >= QUIC_VERSION_17) {
FLAGS_enable_quic_stream_flow_control_2 = true;
}
+ if (negotiated_version_ >= QUIC_VERSION_19) {
+ FLAGS_enable_quic_connection_flow_control = true;
+ }
VLOG(1) << "Using Configuration: " << GetParam();
client_config_.SetDefaults();
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index c06eb60..b074a5d 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -170,6 +170,7 @@ QuicDispatcher::QuicDispatcher(const QuicConfig& config,
helper_(new QuicEpollConnectionHelper(epoll_server_)),
supported_versions_(supported_versions),
supported_versions_no_flow_control_(supported_versions),
+ supported_versions_no_connection_flow_control_(supported_versions),
current_packet_(NULL),
framer_(supported_versions, /*unused*/ QuicTime::Zero(), true),
framer_visitor_(new QuicFramerVisitor(this)),
@@ -197,6 +198,18 @@ void QuicDispatcher::Initialize(int fd) {
supported_versions_no_flow_control_.begin(), it + 1);
}
CHECK(!supported_versions_no_flow_control_.empty());
+
+ // Remove all versions > QUIC_VERSION_18 from the
+ // supported_versions_no_connection_flow_control_ vector.
+ QuicVersionVector::iterator connection_it = find(
+ supported_versions_no_connection_flow_control_.begin(),
+ supported_versions_no_connection_flow_control_.end(), QUIC_VERSION_19);
+ if (connection_it != supported_versions_no_connection_flow_control_.end()) {
+ supported_versions_no_connection_flow_control_.erase(
+ supported_versions_no_connection_flow_control_.begin(),
+ connection_it + 1);
+ }
+ CHECK(!supported_versions_no_connection_flow_control_.empty());
}
void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address,
@@ -381,20 +394,29 @@ QuicConnection* QuicDispatcher::CreateQuicConnection(
const IPEndPoint& server_address,
const IPEndPoint& client_address,
uint32 initial_flow_control_window) {
- // If we have disabled per-stream flow control, then don't allow new
- // connections to talk QUIC_VERSION_17 or higher.
- if (FLAGS_enable_quic_stream_flow_control_2) {
+ 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_);
- } else {
- DVLOG(1)
- << "Flow control disabled, creating QuicDispatcher WITHOUT version 17";
+ }
+
+ if (FLAGS_enable_quic_stream_flow_control_2 &&
+ !FLAGS_enable_quic_connection_flow_control) {
+ DLOG(INFO) << "Connection flow control disabled, creating QuicDispatcher "
+ << "WITHOUT version 19 or higher.";
return new QuicConnection(connection_id, client_address, helper_.get(),
writer_.get(), true,
- supported_versions_no_flow_control_,
+ supported_versions_no_connection_flow_control_,
initial_flow_control_window_bytes_);
}
+
+ 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_);
}
QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() {
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h
index aaed3ab..fbb2f40 100644
--- a/net/tools/quic/quic_dispatcher.h
+++ b/net/tools/quic/quic_dispatcher.h
@@ -143,6 +143,11 @@ class QuicDispatcher : public QuicServerSessionVisitor {
return supported_versions_no_flow_control_;
}
+ const QuicVersionVector& supported_versions_no_connection_flow_control()
+ const {
+ return supported_versions_no_connection_flow_control_;
+ }
+
const IPEndPoint& current_server_address() {
return current_server_address_;
}
@@ -219,6 +224,13 @@ class QuicDispatcher : public QuicServerSessionVisitor {
// TODO(rjshade): Remove this when
// FLAGS_enable_quic_stream_flow_control_2 is removed.
QuicVersionVector supported_versions_no_flow_control_;
+ // Versions which do not support *connection* flow control (introduced in
+ // QUIC_VERSION_19).
+ // This is used to construct new QuicConnections when connection flow control
+ // is disabled via flag.
+ // TODO(rjshade): Remove this when
+ // FLAGS_enable_quic_connection_flow_control is removed.
+ QuicVersionVector supported_versions_no_connection_flow_control_;
// Information about the packet currently being handled.
IPEndPoint current_client_address_;