diff options
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_; |