summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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_;