From 9bb57c7152c7b430c2338c7f1c7a5404e421774f Mon Sep 17 00:00:00 2001 From: "rtenneti@chromium.org" Date: Mon, 31 Mar 2014 20:36:04 +0000 Subject: [PATCH] Land Recent QUIC Changes Remove a LOG_IF(DFATAL) for retransmitting packets which were never given a sent time. This DCHECK was firing on Chrome when Windows buffered a packet and before the callback for the packet being sent, Chrome received a server reject and had to change crypto context and retransmit all unacked packets. Merge internal change: 63686840 https://codereview.chromium.org/214413009/ Rename of QUIC flow control member variables to be more explicit (prefix flow_control) and more descriptive ("max" instead of "initial"). Merge internal change: 63599012 https://codereview.chromium.org/215423003/ Change comment in QuicSessionTest to be more accurate, and add another expectation to ensure stream is not flow control blocked before sending any data. Merge internal change: 63604321 Fixed compilation warnings in quic_sent_packet_manager_test.cc. https://codereview.chromium.org/214823010/ Added UseWriter changes to QuicTestClient while porting internal code that handles the client side of unwinding UDP proxied QUIC changes. Merge internal change: 63542972 https://codereview.chromium.org/214083003/ Change to QUIC's SendAlgorithmInterface to remove IsHandshake from TimeUntilSend. Changed QuicSentPacketManager to ensure it always retransmitted crypto handshake packets before other retransmissions. Merge internal change: 63540663 https://codereview.chromium.org/214923003/ Removing TransmissionType from QUIC's TimeUntilSend method. The only real user was was TcpCubicSender for tail loss probe, and TLP is better fully contained within the SentPacketManager. Merge internal change: 63501475 https://codereview.chromium.org/214083002/ Removed unnecessary transmission_type from Quic's send algorithm interface. The few remaining uses were improper, so there is a minor change in behavior. Merge internal change: 63480011 https://codereview.chromium.org/211693004/ Introduce QUIC_VERSION_17: per-stream flow control. Default send window is 16 KB, and the client/server can specify higher values in their CHLO/SHLO messages. WINDOW_UPDATE frames are sent when the receiver has consumed more than half of their receive window (behavior copied from SPDY), and BLOCKED frames are sent if a write is attempted while flow control blocked. Protected behind FLAGS_enable_quic_stream_flow_control. Merge internal change: 63474251 https://codereview.chromium.org/211743005/ Adding an accessor to quic dispatcher. Merge internal change: 63470311 https://codereview.chromium.org/208273008/ R=rch@chromium.org Review URL: https://codereview.chromium.org/215663002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@260637 0039d316-1c4b-4281-b951-d872f2087c98 --- net/net.gyp | 2 + net/quic/congestion_control/channel_estimator.cc | 2 +- net/quic/congestion_control/fix_rate_sender.cc | 15 +- net/quic/congestion_control/fix_rate_sender.h | 7 +- net/quic/congestion_control/fix_rate_test.cc | 34 ++- .../inter_arrival_bitrate_ramp_up.cc | 12 +- .../inter_arrival_overuse_detector.cc | 44 ++-- net/quic/congestion_control/inter_arrival_probe.cc | 4 +- .../congestion_control/inter_arrival_sender.cc | 43 ++-- net/quic/congestion_control/inter_arrival_sender.h | 5 +- .../inter_arrival_sender_test.cc | 172 +++++++------- net/quic/congestion_control/pacing_sender.cc | 10 +- net/quic/congestion_control/pacing_sender.h | 5 +- net/quic/congestion_control/pacing_sender_test.cc | 53 ++--- .../congestion_control/send_algorithm_interface.h | 5 +- net/quic/congestion_control/tcp_cubic_sender.cc | 15 +- net/quic/congestion_control/tcp_cubic_sender.h | 5 +- .../congestion_control/tcp_cubic_sender_test.cc | 87 +++---- net/quic/crypto/crypto_server_test.cc | 35 ++- net/quic/crypto/quic_crypto_client_config.cc | 4 + net/quic/crypto/quic_crypto_client_config.h | 4 + net/quic/crypto/quic_crypto_client_config_test.cc | 35 ++- net/quic/crypto/quic_crypto_server_config.cc | 5 + net/quic/crypto/quic_crypto_server_config.h | 3 + net/quic/quic_client_session.cc | 4 +- net/quic/quic_config.cc | 8 +- net/quic/quic_config.h | 10 +- net/quic/quic_config_test.cc | 24 +- net/quic/quic_connection.cc | 24 +- net/quic/quic_connection.h | 10 +- net/quic/quic_connection_test.cc | 255 ++++++++++----------- net/quic/quic_crypto_client_stream.cc | 1 + net/quic/quic_crypto_client_stream_test.cc | 1 + net/quic/quic_crypto_server_stream.cc | 1 + net/quic/quic_crypto_stream.cc | 4 + net/quic/quic_crypto_stream.h | 3 + net/quic/quic_crypto_stream_test.cc | 6 + net/quic/quic_data_stream.cc | 6 +- net/quic/quic_data_stream.h | 4 +- net/quic/quic_data_stream_test.cc | 191 +++++++++++++++ net/quic/quic_end_to_end_unittest.cc | 4 +- net/quic/quic_flags.cc | 26 +++ net/quic/quic_flags.h | 15 ++ net/quic/quic_framer.cc | 3 +- net/quic/quic_headers_stream.cc | 4 + net/quic/quic_headers_stream.h | 3 + net/quic/quic_headers_stream_test.cc | 6 + net/quic/quic_http_stream_test.cc | 6 +- net/quic/quic_protocol.cc | 3 + net/quic/quic_protocol.h | 9 +- net/quic/quic_received_packet_manager.cc | 8 +- net/quic/quic_sent_packet_manager.cc | 46 ++-- net/quic/quic_sent_packet_manager.h | 6 +- net/quic/quic_sent_packet_manager_test.cc | 53 ++++- net/quic/quic_session.cc | 38 ++- net/quic/quic_session.h | 1 + net/quic/quic_session_test.cc | 136 ++++++++++- net/quic/quic_stream_factory.cc | 10 +- net/quic/quic_stream_sequencer.cc | 4 + net/quic/quic_stream_sequencer.h | 5 +- net/quic/quic_stream_sequencer_test.cc | 3 + net/quic/reliable_quic_stream.cc | 158 ++++++++++++- net/quic/reliable_quic_stream.h | 40 ++++ net/quic/reliable_quic_stream_test.cc | 50 +++- net/quic/test_tools/quic_test_utils.cc | 20 +- net/quic/test_tools/quic_test_utils.h | 12 +- net/quic/test_tools/reliable_quic_stream_peer.cc | 59 +++++ net/quic/test_tools/reliable_quic_stream_peer.h | 13 ++ net/tools/quic/end_to_end_test.cc | 104 +++++++-- net/tools/quic/quic_client.cc | 15 +- net/tools/quic/quic_client.h | 9 +- net/tools/quic/quic_client_bin.cc | 9 +- net/tools/quic/quic_dispatcher.cc | 43 +++- net/tools/quic/quic_dispatcher.h | 20 +- net/tools/quic/quic_dispatcher_test.cc | 128 ++++++++--- net/tools/quic/quic_server.cc | 18 +- net/tools/quic/quic_server.h | 7 +- net/tools/quic/quic_spdy_client_stream_test.cc | 5 + net/tools/quic/quic_spdy_server_stream_test.cc | 6 + net/tools/quic/test_tools/mock_quic_dispatcher.cc | 10 +- net/tools/quic/test_tools/quic_dispatcher_peer.cc | 13 ++ net/tools/quic/test_tools/quic_dispatcher_peer.h | 9 + net/tools/quic/test_tools/quic_test_client.cc | 55 +++-- net/tools/quic/test_tools/quic_test_client.h | 3 +- net/tools/quic/test_tools/quic_test_utils.cc | 13 +- net/tools/quic/test_tools/quic_test_utils.h | 1 + net/tools/quic/test_tools/server_thread.cc | 7 +- net/tools/quic/test_tools/server_thread.h | 3 +- 88 files changed, 1724 insertions(+), 653 deletions(-) create mode 100644 net/quic/quic_flags.cc create mode 100644 net/quic/quic_flags.h diff --git a/net/net.gyp b/net/net.gyp index 28dcd4d7fce7..4d7a7800b206 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -911,6 +911,8 @@ 'quic/quic_default_packet_writer.h', 'quic/quic_fec_group.cc', 'quic/quic_fec_group.h', + 'quic/quic_flags.cc', + 'quic/quic_flags.h', 'quic/quic_framer.cc', 'quic/quic_framer.h', 'quic/quic_headers_stream.cc', diff --git a/net/quic/congestion_control/channel_estimator.cc b/net/quic/congestion_control/channel_estimator.cc index a012b666a39c..02e5904b635c 100644 --- a/net/quic/congestion_control/channel_estimator.cc +++ b/net/quic/congestion_control/channel_estimator.cc @@ -89,7 +89,7 @@ ChannelEstimateState ChannelEstimator::GetChannelEstimate( } *estimate = median_bitrate; DVLOG(1) << "Channel estimate is:" - << median_bitrate.ToKBitsPerSecond() << " Kbit/s"; + << median_bitrate.ToKBitsPerSecond() << " Kbit/s"; // If the bitrates in our 25th to 75th percentile window varies more than // 25% of the median bitrate we consider the estimate to be uncertain. if (bitrate_75th_percentile.Subtract(bitrate_25th_percentile) > diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc index c84828043e1c..9d7871e37048 100644 --- a/net/quic/congestion_control/fix_rate_sender.cc +++ b/net/quic/congestion_control/fix_rate_sender.cc @@ -52,6 +52,7 @@ void FixRateSender::OnIncomingQuicCongestionFeedbackFrame( void FixRateSender::OnPacketAcked( QuicPacketSequenceNumber /*acked_sequence_number*/, QuicByteCount bytes_acked) { + DCHECK_GE(data_in_flight_, bytes_acked); data_in_flight_ -= bytes_acked; } @@ -64,13 +65,11 @@ bool FixRateSender::OnPacketSent( QuicTime sent_time, QuicPacketSequenceNumber /*sequence_number*/, QuicByteCount bytes, - TransmissionType transmission_type, HasRetransmittableData /*has_retransmittable_data*/) { fix_rate_leaky_bucket_.Add(sent_time, bytes); paced_sender_.OnPacketSent(sent_time, bytes); - if (transmission_type == NOT_RETRANSMISSION) { - data_in_flight_ += bytes; - } + data_in_flight_ += bytes; + return true; } @@ -78,14 +77,14 @@ void FixRateSender::OnRetransmissionTimeout(bool packets_retransmitted) { } void FixRateSender::OnPacketAbandoned( QuicPacketSequenceNumber /*sequence_number*/, - QuicByteCount /*abandoned_bytes*/) { + QuicByteCount bytes_abandoned) { + DCHECK_GE(data_in_flight_, bytes_abandoned); + data_in_flight_ -= bytes_abandoned; } QuicTime::Delta FixRateSender::TimeUntilSend( QuicTime now, - TransmissionType /* transmission_type */, - HasRetransmittableData /*has_retransmittable_data*/, - IsHandshake /*handshake*/) { + HasRetransmittableData /*has_retransmittable_data*/) { if (CongestionWindow() > fix_rate_leaky_bucket_.BytesPending(now)) { if (CongestionWindow() <= data_in_flight_) { // We need an ack before we send more. diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h index 4a56da01ab5c..9dca2e1d23cb 100644 --- a/net/quic/congestion_control/fix_rate_sender.h +++ b/net/quic/congestion_control/fix_rate_sender.h @@ -37,16 +37,13 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface { QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data) OVERRIDE; virtual void OnRetransmissionTimeout(bool packets_retransmitted) OVERRIDE; virtual void OnPacketAbandoned(QuicPacketSequenceNumber sequence_number, - QuicByteCount abandoned_bytes) OVERRIDE; + QuicByteCount bytes_abandoned) OVERRIDE; virtual QuicTime::Delta TimeUntilSend( QuicTime now, - TransmissionType transmission_type, - HasRetransmittableData has_retransmittable_data, - IsHandshake handshake) OVERRIDE; + HasRetransmittableData has_retransmittable_data) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() const OVERRIDE; virtual void UpdateRtt(QuicTime::Delta rtt_sample) OVERRIDE; virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE; diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc index 16e8a5ebfb4b..f9c7722b7429 100644 --- a/net/quic/congestion_control/fix_rate_test.cc +++ b/net/quic/congestion_control/fix_rate_test.cc @@ -58,27 +58,27 @@ TEST_F(FixRateTest, SenderAPI) { sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now()); EXPECT_EQ(300000, sender_->BandwidthEstimate().ToBytesPerSecond()); EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); + sender_->OnPacketSent(clock_.Now(), 1, kDefaultMaxPacketSize, - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); + HAS_RETRANSMITTABLE_DATA); EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); sender_->OnPacketSent(clock_.Now(), 2, kDefaultMaxPacketSize, - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); - sender_->OnPacketSent(clock_.Now(), 3, 600, NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA); + sender_->OnPacketSent(clock_.Now(), 3, 600, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), - sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + sender_->TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA)); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2)); - EXPECT_EQ(QuicTime::Delta::Infinite(), sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + EXPECT_EQ(QuicTime::Delta::Infinite(), + sender_->TimeUntilSend(clock_.Now(), 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(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); } TEST_F(FixRateTest, FixRatePacing) { @@ -93,17 +93,15 @@ TEST_F(FixRateTest, FixRatePacing) { QuicPacketSequenceNumber sequence_number = 0; for (int i = 0; i < num_packets; i += 2) { EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); sender_->OnPacketSent(clock_.Now(), sequence_number++, packet_size, - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); + HAS_RETRANSMITTABLE_DATA); EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); sender_->OnPacketSent(clock_.Now(), sequence_number++, packet_size, - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); - QuicTime::Delta advance_time = sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + HAS_RETRANSMITTABLE_DATA); + QuicTime::Delta advance_time = + sender_->TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA); clock_.AdvanceTime(advance_time); sender_->OnPacketAcked(sequence_number - 1, packet_size); sender_->OnPacketAcked(sequence_number - 2, packet_size); diff --git a/net/quic/congestion_control/inter_arrival_bitrate_ramp_up.cc b/net/quic/congestion_control/inter_arrival_bitrate_ramp_up.cc index 39ee58570477..801a52668da2 100644 --- a/net/quic/congestion_control/inter_arrival_bitrate_ramp_up.cc +++ b/net/quic/congestion_control/inter_arrival_bitrate_ramp_up.cc @@ -78,7 +78,7 @@ void InterArrivalBitrateRampUp::UpdateChannelEstimate( halfway_point_ = available_channel_estimate_.Add( (channel_estimate_.Subtract(available_channel_estimate_).Scale(0.5f))); DVLOG(1) << "UpdateChannelEstimate; first usable value:" - << channel_estimate.ToKBitsPerSecond() << " Kbits/s"; + << channel_estimate.ToKBitsPerSecond() << " Kbits/s"; return; } if (current_rate_ < halfway_point_) { @@ -96,7 +96,7 @@ void InterArrivalBitrateRampUp::UpdateChannelEstimate( CalcuateTimeToOriginPoint(channel_estimate_.Subtract(current_rate_)); DVLOG(1) << "UpdateChannelEstimate; time to origin point:" - << time_to_origin_point_; + << time_to_origin_point_; } QuicBandwidth InterArrivalBitrateRampUp::GetNewBitrate( @@ -118,9 +118,9 @@ QuicBandwidth InterArrivalBitrateRampUp::GetNewBitrate( // We need to update the epoch to reflect this state. epoch_ = epoch_.Add(time_from_last_update); DVLOG(1) << "Don't increase; our sent bitrate is:" - << sent_bitrate.ToKBitsPerSecond() << " Kbits/s" - << " current target rate is:" - << current_rate_.ToKBitsPerSecond() << " Kbits/s"; + << sent_bitrate.ToKBitsPerSecond() << " Kbits/s" + << " current target rate is:" + << current_rate_.ToKBitsPerSecond() << " Kbits/s"; return current_rate_; } QuicTime::Delta time_from_epoch = current_time.Subtract(epoch_); @@ -155,7 +155,7 @@ QuicBandwidth InterArrivalBitrateRampUp::GetNewBitrate( CalcuateTimeToOriginPoint(channel_estimate_.Subtract(current_rate)); } DVLOG(1) << "Passed the halfway point; time to origin point:" - << time_to_origin_point_; + << time_to_origin_point_; } current_rate_ = current_rate; } else { diff --git a/net/quic/congestion_control/inter_arrival_overuse_detector.cc b/net/quic/congestion_control/inter_arrival_overuse_detector.cc index e397c1ed2004..f3f0250e80aa 100644 --- a/net/quic/congestion_control/inter_arrival_overuse_detector.cc +++ b/net/quic/congestion_control/inter_arrival_overuse_detector.cc @@ -157,7 +157,7 @@ void InterArrivalOveruseDetector::DetectDrift(int64 sigma_delta) { accumulated_deltas_.ToMicroseconds() > kThresholdAccumulatedDeltasUs) { if (delta_estimate_ != kBandwidthDraining) { DVLOG(1) << "Bandwidth estimate drift: Draining buffer(s) " - << accumulated_deltas_.ToMilliseconds() << " ms"; + << accumulated_deltas_.ToMilliseconds() << " ms"; delta_estimate_ = kBandwidthDraining; } return; @@ -168,11 +168,11 @@ void InterArrivalOveruseDetector::DetectDrift(int64 sigma_delta) { std::abs(accumulated_deltas_.ToMicroseconds()))) { if (delta_estimate_ != kBandwidthSteady) { DVLOG(1) << "Bandwidth estimate drift: Steady" - << " mean:" << delta_mean_ - << " sigma:" << sigma_delta - << " offset:" << send_receive_offset_.ToMicroseconds() - << " delta:" << estimated_congestion_delay_.ToMicroseconds() - << " drift:" << accumulated_deltas_.ToMicroseconds(); + << " mean:" << delta_mean_ + << " sigma:" << sigma_delta + << " offset:" << send_receive_offset_.ToMicroseconds() + << " delta:" << estimated_congestion_delay_.ToMicroseconds() + << " drift:" << accumulated_deltas_.ToMicroseconds(); delta_estimate_ = kBandwidthSteady; // Reset drift counter. accumulated_deltas_ = QuicTime::Delta::Zero(); @@ -184,22 +184,22 @@ void InterArrivalOveruseDetector::DetectDrift(int64 sigma_delta) { if (delta_estimate_ != kBandwidthOverUsing) { ++delta_overuse_counter_; DVLOG(1) << "Bandwidth estimate drift: Over using" - << " mean:" << delta_mean_ - << " sigma:" << sigma_delta - << " offset:" << send_receive_offset_.ToMicroseconds() - << " delta:" << estimated_congestion_delay_.ToMicroseconds() - << " drift:" << accumulated_deltas_.ToMicroseconds(); + << " mean:" << delta_mean_ + << " sigma:" << sigma_delta + << " offset:" << send_receive_offset_.ToMicroseconds() + << " delta:" << estimated_congestion_delay_.ToMicroseconds() + << " drift:" << accumulated_deltas_.ToMicroseconds(); delta_estimate_ = kBandwidthOverUsing; } } else { if (delta_estimate_ != kBandwidthUnderUsing) { --delta_overuse_counter_; DVLOG(1) << "Bandwidth estimate drift: Under using" - << " mean:" << delta_mean_ - << " sigma:" << sigma_delta - << " offset:" << send_receive_offset_.ToMicroseconds() - << " delta:" << estimated_congestion_delay_.ToMicroseconds() - << " drift:" << accumulated_deltas_.ToMicroseconds(); + << " mean:" << delta_mean_ + << " sigma:" << sigma_delta + << " offset:" << send_receive_offset_.ToMicroseconds() + << " delta:" << estimated_congestion_delay_.ToMicroseconds() + << " drift:" << accumulated_deltas_.ToMicroseconds(); delta_estimate_ = kBandwidthUnderUsing; } // Adding decay of negative accumulated_deltas_ since it could be caused by @@ -227,8 +227,8 @@ void InterArrivalOveruseDetector::DetectSlope(int64 sigma_delta) { if (sigma_delta > abs(delta_mean_) * kDetectSlopeFactor) { if (slope_estimate_ != kBandwidthSteady) { DVLOG(1) << "Bandwidth estimate slope: Steady" - << " mean:" << delta_mean_ - << " sigma:" << sigma_delta; + << " mean:" << delta_mean_ + << " sigma:" << sigma_delta; slope_overuse_counter_ = 0; slope_estimate_ = kBandwidthSteady; } @@ -238,16 +238,16 @@ void InterArrivalOveruseDetector::DetectSlope(int64 sigma_delta) { if (slope_estimate_ != kBandwidthOverUsing) { ++slope_overuse_counter_; DVLOG(1) << "Bandwidth estimate slope: Over using" - << " mean:" << delta_mean_ - << " sigma:" << sigma_delta; + << " mean:" << delta_mean_ + << " sigma:" << sigma_delta; slope_estimate_ = kBandwidthOverUsing; } } else { if (slope_estimate_ != kBandwidthUnderUsing) { --slope_overuse_counter_; DVLOG(1) << "Bandwidth estimate slope: Under using" - << " mean:" << delta_mean_ - << " sigma:" << sigma_delta; + << " mean:" << delta_mean_ + << " sigma:" << sigma_delta; slope_estimate_ = kBandwidthUnderUsing; } } diff --git a/net/quic/congestion_control/inter_arrival_probe.cc b/net/quic/congestion_control/inter_arrival_probe.cc index 694c3d7e0dee..f9a036271b2a 100644 --- a/net/quic/congestion_control/inter_arrival_probe.cc +++ b/net/quic/congestion_control/inter_arrival_probe.cc @@ -121,8 +121,8 @@ void InterArrivalProbe::OnIncomingFeedback( estimate_available_ = true; available_channel_estimator_.reset(NULL); DVLOG(1) << "Probe estimate:" - << available_channel_estimate_.ToKBitsPerSecond() - << " Kbits/s"; + << available_channel_estimate_.ToKBitsPerSecond() + << " Kbits/s"; } } // namespace net diff --git a/net/quic/congestion_control/inter_arrival_sender.cc b/net/quic/congestion_control/inter_arrival_sender.cc index 1b46455de53d..864db7d5b15a 100644 --- a/net/quic/congestion_control/inter_arrival_sender.cc +++ b/net/quic/congestion_control/inter_arrival_sender.cc @@ -111,7 +111,7 @@ void InterArrivalSender::OnIncomingQuicCongestionFeedbackFrame( if (sent_it == packet_history_map_.end()) { // Too old data; ignore and move forward. DVLOG(1) << "Too old feedback move forward, sequence_number:" - << sequence_number; + << sequence_number; continue; } QuicTime time_received = received_it->second; @@ -187,11 +187,11 @@ bool InterArrivalSender::ProbingPhase(QuicTime feedback_receive_time) { current_bandwidth_ = new_rate; paced_sender_->UpdateBandwidthEstimate(feedback_receive_time, new_rate); DVLOG(1) << "Probe result; new rate:" - << new_rate.ToKBitsPerSecond() << " Kbits/s " - << " available estimate:" - << available_channel_estimate.ToKBitsPerSecond() << " Kbits/s " - << " channel estimate:" - << channel_estimate.ToKBitsPerSecond() << " Kbits/s "; + << new_rate.ToKBitsPerSecond() << " Kbits/s " + << " available estimate:" + << available_channel_estimate.ToKBitsPerSecond() << " Kbits/s " + << " channel estimate:" + << channel_estimate.ToKBitsPerSecond() << " Kbits/s "; return false; } @@ -221,7 +221,6 @@ bool InterArrivalSender::OnPacketSent( QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - TransmissionType /*transmission_type*/, HasRetransmittableData /*has_retransmittable_data*/) { if (probing_) { probe_->OnPacketSent(bytes); @@ -252,9 +251,7 @@ void InterArrivalSender::OnPacketAbandoned( QuicTime::Delta InterArrivalSender::TimeUntilSend( QuicTime now, - TransmissionType /*transmission_type*/, - HasRetransmittableData has_retransmittable_data, - IsHandshake /*handshake*/) { + HasRetransmittableData has_retransmittable_data) { // TODO(pwestin): implement outer_congestion_window_ logic. QuicTime::Delta outer_window = QuicTime::Delta::Zero(); @@ -337,8 +334,8 @@ void InterArrivalSender::EstimateNewBandwidth(QuicTime feedback_receive_time, paced_sender_->UpdateBandwidthEstimate(feedback_receive_time, current_bandwidth_); DVLOG(1) << "New bandwidth estimate in steady state:" - << current_bandwidth_.ToKBitsPerSecond() - << " Kbits/s"; + << current_bandwidth_.ToKBitsPerSecond() + << " Kbits/s"; } // Did we drain the network buffers in our expected pace? @@ -385,15 +382,15 @@ void InterArrivalSender::EstimateNewBandwidthAfterDraining( current_bandwidth_.Add(draining_rate).Scale( 1.0f - kMinBitrateReduction)); DVLOG(1) << "Draining calculation; current rate:" - << current_bandwidth_.ToKBitsPerSecond() << " Kbits/s " - << "draining rate:" - << draining_rate.ToKBitsPerSecond() << " Kbits/s " - << "new estimate:" - << new_estimate.ToKBitsPerSecond() << " Kbits/s " - << " buffer reduction:" - << buffer_reduction.ToMicroseconds() << " us " - << " elapsed time:" - << elapsed_time.ToMicroseconds() << " us "; + << current_bandwidth_.ToKBitsPerSecond() << " Kbits/s " + << "draining rate:" + << draining_rate.ToKBitsPerSecond() << " Kbits/s " + << "new estimate:" + << new_estimate.ToKBitsPerSecond() << " Kbits/s " + << " buffer reduction:" + << buffer_reduction.ToMicroseconds() << " us " + << " elapsed time:" + << elapsed_time.ToMicroseconds() << " us "; } } if (new_estimate == current_bandwidth_) { @@ -421,7 +418,7 @@ void InterArrivalSender::EstimateNewBandwidthAfterDraining( paced_sender_->UpdateBandwidthEstimate(feedback_receive_time, new_estimate); current_bandwidth_ = new_estimate; DVLOG(1) << "New bandwidth estimate after draining:" - << new_estimate.ToKBitsPerSecond() << " Kbits/s"; + << new_estimate.ToKBitsPerSecond() << " Kbits/s"; } void InterArrivalSender::EstimateBandwidthAfterDelayEvent( @@ -464,7 +461,7 @@ void InterArrivalSender::EstimateBandwidthAfterLossEvent( ResetCurrentBandwidth(feedback_receive_time, current_bandwidth_.Scale(kPacketLossBitrateReduction)); DVLOG(1) << "New bandwidth estimate after loss event:" - << current_bandwidth_.ToKBitsPerSecond() << " Kbits/s"; + << current_bandwidth_.ToKBitsPerSecond() << " Kbits/s"; } void InterArrivalSender::ResetCurrentBandwidth(QuicTime feedback_receive_time, diff --git a/net/quic/congestion_control/inter_arrival_sender.h b/net/quic/congestion_control/inter_arrival_sender.h index 2de370d7293d..e0812f1111e1 100644 --- a/net/quic/congestion_control/inter_arrival_sender.h +++ b/net/quic/congestion_control/inter_arrival_sender.h @@ -40,16 +40,13 @@ class NET_EXPORT_PRIVATE InterArrivalSender : public SendAlgorithmInterface { QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data) OVERRIDE; virtual void OnRetransmissionTimeout(bool packets_retransmitted) OVERRIDE; virtual void OnPacketAbandoned(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes) OVERRIDE; virtual QuicTime::Delta TimeUntilSend( QuicTime now, - TransmissionType transmission_type, - HasRetransmittableData has_retransmittable_data, - IsHandshake handshake) OVERRIDE; + HasRetransmittableData has_retransmittable_data) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() const OVERRIDE; virtual void UpdateRtt(QuicTime::Delta rtt_sample) OVERRIDE; virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE; diff --git a/net/quic/congestion_control/inter_arrival_sender_test.cc b/net/quic/congestion_control/inter_arrival_sender_test.cc index 048cbb04144a..c3335fcd3862 100644 --- a/net/quic/congestion_control/inter_arrival_sender_test.cc +++ b/net/quic/congestion_control/inter_arrival_sender_test.cc @@ -36,14 +36,14 @@ class InterArrivalSenderTest : public ::testing::Test { void SendAvailableCongestionWindow() { while (sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()) { + HAS_RETRANSMITTABLE_DATA).IsZero()) { QuicByteCount bytes_in_packet = kDefaultMaxPacketSize; sender_.OnPacketSent(send_clock_.Now(), sequence_number_, bytes_in_packet, - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); + HAS_RETRANSMITTABLE_DATA); sequence_number_++; } EXPECT_FALSE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); } void AckNPackets(int n) { @@ -114,28 +114,28 @@ TEST_F(InterArrivalSenderTest, ProbeFollowedByFullRampUpCycle) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); // Send 5 bursts. for (int i = 0; i < 4; ++i) { SendAvailableCongestionWindow(); send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + HAS_RETRANSMITTABLE_DATA)); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); } SendAvailableCongestionWindow(); // We have now sent our probe. - EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsInfinite()); + EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), + HAS_RETRANSMITTABLE_DATA).IsInfinite()); AckNPackets(10); SendFeedbackMessageNPackets(10, one_ms_, nine_ms_); send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + HAS_RETRANSMITTABLE_DATA)); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); // We should now have our probe rate. QuicTime::Delta acc_arrival_time = QuicTime::Delta::FromMilliseconds(41); @@ -147,11 +147,11 @@ TEST_F(InterArrivalSenderTest, ProbeFollowedByFullRampUpCycle) { // Send 50 bursts, make sure that we move fast in the beginning. for (int i = 0; i < 50; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); } @@ -162,11 +162,11 @@ TEST_F(InterArrivalSenderTest, ProbeFollowedByFullRampUpCycle) { // Send 50 bursts, make sure that we slow down towards the probe rate. for (int i = 0; i < 50; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); } @@ -177,11 +177,11 @@ TEST_F(InterArrivalSenderTest, ProbeFollowedByFullRampUpCycle) { // Send 50 bursts, make sure that we move very slow close to the probe rate. for (int i = 0; i < 50; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); } @@ -193,11 +193,11 @@ TEST_F(InterArrivalSenderTest, ProbeFollowedByFullRampUpCycle) { // Send 50 bursts, make sure that we move very slow close to the probe rate. for (int i = 0; i < 50; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); } @@ -209,11 +209,11 @@ TEST_F(InterArrivalSenderTest, ProbeFollowedByFullRampUpCycle) { // Send 50 bursts, make sure that we move very slow close to the probe rate. for (int i = 0; i < 50; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); } @@ -224,11 +224,11 @@ TEST_F(InterArrivalSenderTest, ProbeFollowedByFullRampUpCycle) { // Send 50 bursts, make sure that we accelerate after the probe rate. for (int i = 0; i < 50; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); } @@ -239,11 +239,11 @@ TEST_F(InterArrivalSenderTest, ProbeFollowedByFullRampUpCycle) { // Send 50 bursts, make sure that we accelerate after the probe rate. for (int i = 0; i < 50; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); } @@ -259,11 +259,11 @@ TEST_F(InterArrivalSenderTest, ProbeFollowedByFullRampUpCycle) { // Send until we reach halfway point. for (int i = 0; i < 570; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); } @@ -275,11 +275,11 @@ TEST_F(InterArrivalSenderTest, ProbeFollowedByFullRampUpCycle) { // Send until we reach max channel capacity. for (int i = 0; i < 1500; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); +HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); } @@ -292,28 +292,28 @@ TEST_F(InterArrivalSenderTest, DelaySpikeFollowedBySlowDrain) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); // Send 5 bursts. for (int i = 0; i < 4; ++i) { SendAvailableCongestionWindow(); send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + HAS_RETRANSMITTABLE_DATA)); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); } SendAvailableCongestionWindow(); // We have now sent our probe. - EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsInfinite()); + EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), + HAS_RETRANSMITTABLE_DATA).IsInfinite()); AckNPackets(10); SendFeedbackMessageNPackets(10, one_ms_, nine_ms_); - send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + send_clock_.AdvanceTime( + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA)); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); // We should now have our probe rate. QuicTime::Delta acc_arrival_time = QuicTime::Delta::FromMilliseconds(41); @@ -325,11 +325,11 @@ TEST_F(InterArrivalSenderTest, DelaySpikeFollowedBySlowDrain) { // Send 50 bursts, make sure that we move fast in the beginning. for (int i = 0; i < 50; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); } @@ -338,10 +338,10 @@ TEST_F(InterArrivalSenderTest, DelaySpikeFollowedBySlowDrain) { EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 600, 10); SendAvailableCongestionWindow(); - send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + send_clock_.AdvanceTime( + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA)); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); int64 rate_at_introduced_delay_spike = 0.875f * probe_rate; @@ -357,9 +357,9 @@ TEST_F(InterArrivalSenderTest, DelaySpikeFollowedBySlowDrain) { while (send_clock_.Now() < receive_clock_.Now()) { SendAvailableCongestionWindow(); send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + HAS_RETRANSMITTABLE_DATA)); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); SendFeedbackMessageNPackets(2, one_ms_, one_ms_); } @@ -372,11 +372,11 @@ TEST_F(InterArrivalSenderTest, DelaySpikeFollowedBySlowDrain) { // before the spike. for (int i = 0; i < 100; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); } @@ -389,28 +389,29 @@ TEST_F(InterArrivalSenderTest, DelaySpikeFollowedByImmediateDrain) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); // Send 5 bursts. for (int i = 0; i < 4; ++i) { SendAvailableCongestionWindow(); send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); - EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA)); + EXPECT_TRUE( + sender_.TimeUntilSend(send_clock_.Now(), + HAS_RETRANSMITTABLE_DATA).IsZero()); } SendAvailableCongestionWindow(); // We have now sent our probe. - EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsInfinite()); + EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), + HAS_RETRANSMITTABLE_DATA).IsInfinite()); AckNPackets(10); SendFeedbackMessageNPackets(10, one_ms_, nine_ms_); send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + HAS_RETRANSMITTABLE_DATA)); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); // We should now have our probe rate. QuicTime::Delta acc_arrival_time = QuicTime::Delta::FromMilliseconds(41); @@ -422,11 +423,11 @@ TEST_F(InterArrivalSenderTest, DelaySpikeFollowedByImmediateDrain) { // Send 50 bursts, make sure that we move fast in the beginning. for (int i = 0; i < 50; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); } @@ -436,9 +437,9 @@ TEST_F(InterArrivalSenderTest, DelaySpikeFollowedByImmediateDrain) { SendAvailableCongestionWindow(); send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + HAS_RETRANSMITTABLE_DATA)); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); AckNPackets(2); int64 rate_at_introduced_delay_spike = 0.875f * probe_rate; @@ -469,15 +470,14 @@ TEST_F(InterArrivalSenderTest, MinBitrateDueToDelay) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); - + HAS_RETRANSMITTABLE_DATA).IsZero()); // Send 5 bursts. for (int i = 0; i < 4; ++i) { SendAvailableCongestionWindow(); send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + HAS_RETRANSMITTABLE_DATA)); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); } SendAvailableCongestionWindow(); @@ -487,9 +487,9 @@ TEST_F(InterArrivalSenderTest, MinBitrateDueToDelay) { // our minimum bitrate. SendFeedbackMessageNPackets(10, one_s_, one_s_); send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + HAS_RETRANSMITTABLE_DATA)); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); EXPECT_EQ(expected_min_bitrate, sender_.BandwidthEstimate()); } @@ -499,24 +499,24 @@ TEST_F(InterArrivalSenderTest, MinBitrateDueToLoss) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); // Send 5 bursts. for (int i = 0; i < 4; ++i) { SendAvailableCongestionWindow(); send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + HAS_RETRANSMITTABLE_DATA)); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); } SendAvailableCongestionWindow(); AckNPackets(10); SendFeedbackMessageNPackets(10, nine_ms_, nine_ms_); send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); + HAS_RETRANSMITTABLE_DATA)); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); QuicTime::Delta acc_arrival_time = QuicTime::Delta::FromMilliseconds(81); int64 probe_rate = kDefaultMaxPacketSize * 9 * kNumMicrosPerSecond / @@ -526,11 +526,11 @@ TEST_F(InterArrivalSenderTest, MinBitrateDueToLoss) { for (int i = 0; i < 15; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); sender_.OnPacketLost(acked_sequence_number_ - 1, send_clock_.Now()); sender_.OnPacketAcked(acked_sequence_number_, kDefaultMaxPacketSize); acked_sequence_number_ += 2; // Create a loss by not acking both packets. @@ -541,11 +541,11 @@ TEST_F(InterArrivalSenderTest, MinBitrateDueToLoss) { for (int i = 0; i < 50; ++i) { SendAvailableCongestionWindow(); - QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + QuicTime::Delta time_until_send = + sender_.TimeUntilSend(send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); send_clock_.AdvanceTime(time_until_send); EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); sender_.OnPacketLost(acked_sequence_number_ - 1, send_clock_.Now()); sender_.OnPacketAcked(acked_sequence_number_, kDefaultMaxPacketSize); acked_sequence_number_ += 2; // Create a loss by not acking both packets. diff --git a/net/quic/congestion_control/pacing_sender.cc b/net/quic/congestion_control/pacing_sender.cc index 3a166670ccd9..ffbb6fe461f0 100644 --- a/net/quic/congestion_control/pacing_sender.cc +++ b/net/quic/congestion_control/pacing_sender.cc @@ -43,7 +43,6 @@ bool PacingSender::OnPacketSent( QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - TransmissionType transmission_type, HasRetransmittableData has_retransmittable_data) { // Only pace data packets once we have an updated RTT. if (has_retransmittable_data == HAS_RETRANSMITTABLE_DATA && updated_rtt_) { @@ -57,7 +56,7 @@ bool PacingSender::OnPacketSent( next_packet_send_time_ = next_packet_send_time_.Add(delay); } return sender_->OnPacketSent(sent_time, sequence_number, bytes, - transmission_type, has_retransmittable_data); + has_retransmittable_data); } void PacingSender::OnRetransmissionTimeout(bool packets_retransmitted) { @@ -71,12 +70,9 @@ void PacingSender::OnPacketAbandoned(QuicPacketSequenceNumber sequence_number, QuicTime::Delta PacingSender::TimeUntilSend( QuicTime now, - TransmissionType transmission_type, - HasRetransmittableData has_retransmittable_data, - IsHandshake handshake) { + HasRetransmittableData has_retransmittable_data) { QuicTime::Delta time_until_send = - sender_->TimeUntilSend(now, transmission_type, - has_retransmittable_data, handshake); + sender_->TimeUntilSend(now, has_retransmittable_data); if (!updated_rtt_) { // Don't pace if we don't have an updated RTT estimate. return time_until_send; diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h index 9fa4eb6654d1..498ad8055039 100644 --- a/net/quic/congestion_control/pacing_sender.h +++ b/net/quic/congestion_control/pacing_sender.h @@ -41,16 +41,13 @@ class NET_EXPORT_PRIVATE PacingSender : public SendAlgorithmInterface { virtual bool OnPacketSent(QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - TransmissionType transmission_type, 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, - TransmissionType transmission_type, - HasRetransmittableData has_retransmittable_data, - IsHandshake handshake) OVERRIDE; + HasRetransmittableData has_retransmittable_data) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() const OVERRIDE; virtual void UpdateRtt(QuicTime::Delta rtt_sample) OVERRIDE; virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE; diff --git a/net/quic/congestion_control/pacing_sender_test.cc b/net/quic/congestion_control/pacing_sender_test.cc index 087427323cbc..853e9df11715 100644 --- a/net/quic/congestion_control/pacing_sender_test.cc +++ b/net/quic/congestion_control/pacing_sender_test.cc @@ -36,22 +36,19 @@ 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(), - NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)) + HAS_RETRANSMITTABLE_DATA)) .WillOnce(Return(zero_time_)); // Verify that the packet can be sent immediately. EXPECT_EQ(zero_time_, - pacing_sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)); + pacing_sender_->TimeUntilSend(clock_.Now(), + HAS_RETRANSMITTABLE_DATA)); // Actually send the packet. EXPECT_CALL(*mock_sender_, OnPacketSent(clock_.Now(), sequence_number_, kMaxPacketSize, - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA)); + HAS_RETRANSMITTABLE_DATA)); pacing_sender_->OnPacketSent(clock_.Now(), sequence_number_++, - kMaxPacketSize, NOT_RETRANSMISSION, + kMaxPacketSize, HAS_RETRANSMITTABLE_DATA); } @@ -59,22 +56,19 @@ class PacingSenderTest : public ::testing::Test { // 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(), - NOT_RETRANSMISSION, - NO_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)) + NO_RETRANSMITTABLE_DATA)) .WillOnce(Return(zero_time_)); // Verify that the ACK can be sent immediately. EXPECT_EQ(zero_time_, - pacing_sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, - NO_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)); + pacing_sender_->TimeUntilSend(clock_.Now(), + NO_RETRANSMITTABLE_DATA)); // Actually send the packet. EXPECT_CALL(*mock_sender_, OnPacketSent(clock_.Now(), sequence_number_, kMaxPacketSize, - NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA)); + NO_RETRANSMITTABLE_DATA)); pacing_sender_->OnPacketSent(clock_.Now(), sequence_number_++, - kMaxPacketSize, NOT_RETRANSMISSION, + kMaxPacketSize, NO_RETRANSMITTABLE_DATA); } @@ -82,15 +76,12 @@ 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(), - NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)) + HAS_RETRANSMITTABLE_DATA)) .WillOnce(Return(zero_time_)); // Verify that the packet is delayed. EXPECT_EQ(delay.ToMicroseconds(), - pacing_sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE).ToMicroseconds()); + pacing_sender_->TimeUntilSend( + clock_.Now(), HAS_RETRANSMITTABLE_DATA).ToMicroseconds()); } const QuicTime::Delta zero_time_; @@ -103,26 +94,20 @@ class PacingSenderTest : public ::testing::Test { TEST_F(PacingSenderTest, NoSend) { EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)) + HAS_RETRANSMITTABLE_DATA)) .WillOnce(Return(infinite_time_)); EXPECT_EQ(infinite_time_, - pacing_sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)); + pacing_sender_->TimeUntilSend(clock_.Now(), + HAS_RETRANSMITTABLE_DATA)); } TEST_F(PacingSenderTest, SendNow) { EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)) + HAS_RETRANSMITTABLE_DATA)) .WillOnce(Return(zero_time_)); EXPECT_EQ(zero_time_, - pacing_sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE)); + pacing_sender_->TimeUntilSend(clock_.Now(), + HAS_RETRANSMITTABLE_DATA)); } TEST_F(PacingSenderTest, VariousSending) { diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h index afd52580a104..d239f66d20a6 100644 --- a/net/quic/congestion_control/send_algorithm_interface.h +++ b/net/quic/congestion_control/send_algorithm_interface.h @@ -56,7 +56,6 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface { virtual bool OnPacketSent(QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - TransmissionType transmission_type, HasRetransmittableData is_retransmittable) = 0; // Called when the retransmission timeout fires. Neither OnPacketAbandoned @@ -70,9 +69,7 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface { // Calculate the time until we can send the next packet. virtual QuicTime::Delta TimeUntilSend( QuicTime now, - TransmissionType transmission_type, - HasRetransmittableData has_retransmittable_data, - IsHandshake handshake) = 0; + HasRetransmittableData has_retransmittable_data) = 0; // What's the current estimated bandwidth in bytes per second. // Returns 0 when it does not have an estimate. diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc index 89c240b832ac..835be60e6642 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.cc +++ b/net/quic/congestion_control/tcp_cubic_sender.cc @@ -132,7 +132,6 @@ void TcpCubicSender::OnPacketLost(QuicPacketSequenceNumber sequence_number, bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - TransmissionType transmission_type, HasRetransmittableData is_retransmittable) { // Only update bytes_in_flight_ for data packets. if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) { @@ -146,7 +145,7 @@ bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/, // DCHECK_LT(largest_sent_sequence_number_, sequence_number); largest_sent_sequence_number_ = sequence_number; } - if (transmission_type == NOT_RETRANSMISSION && update_end_sequence_number_) { + if (update_end_sequence_number_) { end_sequence_number_ = sequence_number; if (AvailableSendWindow() == 0) { update_end_sequence_number_ = false; @@ -164,17 +163,9 @@ void TcpCubicSender::OnPacketAbandoned(QuicPacketSequenceNumber sequence_number, QuicTime::Delta TcpCubicSender::TimeUntilSend( QuicTime /* now */, - TransmissionType transmission_type, - HasRetransmittableData has_retransmittable_data, - IsHandshake handshake) { - if (transmission_type == TLP_RETRANSMISSION || - transmission_type == HANDSHAKE_RETRANSMISSION || - has_retransmittable_data == NO_RETRANSMITTABLE_DATA || - handshake == IS_HANDSHAKE) { + HasRetransmittableData has_retransmittable_data) { + if (has_retransmittable_data == NO_RETRANSMITTABLE_DATA) { // For TCP we can always send an ACK immediately. - // We also immediately send any handshake packet (CHLO, etc.). We provide - // this special dispensation for handshake messages in QUIC, although the - // concept is not present in TCP. // We also allow tail loss probes to be sent immediately, in keeping with // tail loss probe (draft-dukkipati-tcpm-tcp-loss-probe-01). 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 89e9bd63ab87..93204d47e507 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.h +++ b/net/quic/congestion_control/tcp_cubic_sender.h @@ -52,16 +52,13 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { virtual bool OnPacketSent(QuicTime sent_time, QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, - TransmissionType transmission_type, 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, - TransmissionType transmission_type, - HasRetransmittableData has_retransmittable_data, - IsHandshake handshake) OVERRIDE; + HasRetransmittableData has_retransmittable_data) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() const OVERRIDE; virtual void UpdateRtt(QuicTime::Delta rtt_sample) OVERRIDE; virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE; diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc index 1df3b3665269..c4cbfafb5472 100644 --- a/net/quic/congestion_control/tcp_cubic_sender_test.cc +++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc @@ -58,15 +58,13 @@ class TcpCubicSenderTest : public ::testing::Test { // Send as long as TimeUntilSend returns Zero. int packets_sent = 0; bool can_send = sender_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero(); + clock_.Now(), HAS_RETRANSMITTABLE_DATA).IsZero(); while (can_send) { sender_->OnPacketSent(clock_.Now(), sequence_number_++, kDefaultTCPMSS, - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); + HAS_RETRANSMITTABLE_DATA); ++packets_sent; can_send = sender_->TimeUntilSend( - clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero(); + clock_.Now(), HAS_RETRANSMITTABLE_DATA).IsZero(); } return packets_sent; } @@ -109,41 +107,26 @@ TEST_F(TcpCubicSenderTest, SimpleSender) { EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + 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(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); // And that window is un-affected. EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableSendWindow()); EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); - // A retransmit should always return 0. - for (int i = FIRST_TRANSMISSION_TYPE; i <= LAST_TRANSMISSION_TYPE; ++i) { - TransmissionType type = static_cast(i); - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - type, - HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE).IsZero()) - << QuicUtils::TransmissionTypeToString(type); - } + // 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 still - // send handshake and TLP packets. + // Fill the send window with data, then verify that we can't send. SendAvailableSendWindow(); - for (int i = FIRST_TRANSMISSION_TYPE; i <= LAST_TRANSMISSION_TYPE; ++i) { - TransmissionType type = static_cast(i); - bool expect_can_send = (type == HANDSHAKE_RETRANSMISSION || - type == TLP_RETRANSMISSION); - EXPECT_EQ(expect_can_send, - sender_->TimeUntilSend(clock_.Now(), - type, - HAS_RETRANSMITTABLE_DATA, - NOT_HANDSHAKE).IsZero()) - << QuicUtils::TransmissionTypeToString(type); - } + EXPECT_FALSE(sender_->TimeUntilSend(clock_.Now(), + HAS_RETRANSMITTABLE_DATA).IsZero()); } TEST_F(TcpCubicSenderTest, ExponentialSlowStart) { @@ -151,13 +134,13 @@ TEST_F(TcpCubicSenderTest, ExponentialSlowStart) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + 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(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); for (int i = 0; i < kNumberOfAcks; ++i) { // Send our full send window. @@ -179,13 +162,13 @@ TEST_F(TcpCubicSenderTest, SlowStartAckTrain) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + 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(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); for (int i = 0; i < kNumberOfAcks; ++i) { // Send our full send window. @@ -217,13 +200,13 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + 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(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); const int kNumberOfAcks = 10; for (int i = 0; i < kNumberOfAcks; ++i) { @@ -240,8 +223,8 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) { ++acked_sequence_number_; // Make sure that we can send right now due to limited transmit. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), + HAS_RETRANSMITTABLE_DATA).IsZero()); // We should now have fallen out of slow start. // We expect window to be cut in half by Reno. @@ -280,7 +263,7 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLossPRR) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); // Get default QuicCongestionFeedbackFrame from receiver. ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now()); @@ -305,8 +288,8 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLossPRR) { EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); // Send 1 packet to simulate limited transmit. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), + HAS_RETRANSMITTABLE_DATA).IsZero()); EXPECT_EQ(1, SendAvailableSendWindow()); // Testing TCP proportional rate reduction. @@ -319,8 +302,7 @@ 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(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + clock_.Now(), HAS_RETRANSMITTABLE_DATA).IsZero()); EXPECT_EQ(0u, sender_->AvailableSendWindow()); EXPECT_EQ(1, SendAvailableSendWindow()); EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); @@ -350,7 +332,7 @@ TEST_F(TcpCubicSenderTest, SlowStartBurstPacketLossPRR) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); // Get default QuicCongestionFeedbackFrame from receiver. ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now()); @@ -466,13 +448,13 @@ TEST_F(TcpCubicSenderTest, SlowStartMaxSendWindow) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + 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(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); for (int i = 0; i < kNumberOfAcks; ++i) { // Send our full send window. @@ -493,13 +475,14 @@ TEST_F(TcpCubicSenderTest, TcpRenoMaxCongestionWindow) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + 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(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); + SendAvailableSendWindow(); AckNPackets(2); @@ -528,13 +511,13 @@ TEST_F(TcpCubicSenderTest, TcpCubicMaxCongestionWindow) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + 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(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + HAS_RETRANSMITTABLE_DATA).IsZero()); SendAvailableSendWindow(); AckNPackets(2); @@ -575,13 +558,13 @@ TEST_F(TcpCubicSenderTest, SendWindowNotAffectedByAcks) { // window doesn't change. QuicByteCount bytes_in_packet = min(kDefaultTCPMSS, send_window); sender_->OnPacketSent(clock_.Now(), sequence_number_++, bytes_in_packet, - NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA); + 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, - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); + HAS_RETRANSMITTABLE_DATA); EXPECT_GT(send_window, sender_->AvailableSendWindow()); } @@ -601,7 +584,7 @@ TEST_F(TcpCubicSenderTest, CongestionAvoidanceAtEndOfRecovery) { QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); + 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/crypto_server_test.cc b/net/quic/crypto/crypto_server_test.cc index f1892d3b6ac7..f3738ffea424 100644 --- a/net/quic/crypto/crypto_server_test.cc +++ b/net/quic/crypto/crypto_server_test.cc @@ -182,8 +182,9 @@ class CryptoServerTest : public ::testing::Test { string error_details; QuicErrorCode error = config_.ProcessClientHello( result, 1 /* ConnectionId */, client_address_, - supported_versions_.front(), supported_versions_, &clock_, rand_, - ¶ms_, &out_, &error_details); + supported_versions_.front(), supported_versions_, + kInitialFlowControlWindowForTest, &clock_, rand_, ¶ms_, &out_, + &error_details); if (should_succeed) { ASSERT_EQ(error, QUIC_NO_ERROR) @@ -522,5 +523,35 @@ TEST_F(AsyncStrikeServerVerificationTest, AsyncReplayProtection) { EXPECT_EQ(kREJ, out_.tag()); } +TEST_F(CryptoServerTest, InitialFlowControlWindow) { + // Test that the SHLO contains a value for initial flow control window. + CryptoHandshakeMessage msg = CryptoTestUtils::Message( + "CHLO", + "AEAD", "AESG", + "KEXS", "C255", + "SCID", scid_hex_.c_str(), + "#004b5453", srct_hex_.c_str(), + "PUBS", pub_hex_.c_str(), + "NONC", nonce_hex_.c_str(), + "VER\0", client_version_.data(), + "$padding", static_cast(kClientHelloMinimumSize), + NULL); + ShouldSucceed(msg); + // The message should be rejected because the strike-register is still + // quiescent. + ASSERT_EQ(kREJ, out_.tag()); + config_.set_replay_protection(false); + + // The message should be accepted now. + ShouldSucceed(msg); + ASSERT_EQ(kSHLO, out_.tag()); + CheckServerHello(out_); + + // Ensure that the kIFCW tag is populated correctly. + QuicTag ifcw; + EXPECT_EQ(QUIC_NO_ERROR, out_.GetUint32(kIFCW, &ifcw)); + EXPECT_EQ(kInitialFlowControlWindowForTest, ifcw); +} + } // namespace test } // namespace net diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc index 8f34745cd140..b802005293d0 100644 --- a/net/quic/crypto/quic_crypto_client_config.cc +++ b/net/quic/crypto/quic_crypto_client_config.cc @@ -325,6 +325,7 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello( const QuicSessionKey& server_key, QuicConnectionId connection_id, const QuicVersion preferred_version, + uint32 initial_flow_control_window_bytes, const CachedState* cached, QuicWallTime now, QuicRandom* rand, @@ -336,6 +337,9 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello( FillInchoateClientHello(server_key, preferred_version, cached, out_params, out); + // Set initial receive window for flow control. + out->SetValue(kIFCW, initial_flow_control_window_bytes); + const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); if (!scfg) { // This should never happen as our caller should have checked diff --git a/net/quic/crypto/quic_crypto_client_config.h b/net/quic/crypto/quic_crypto_client_config.h index d6ce2e4c4ad4..b18e503f94f2 100644 --- a/net/quic/crypto/quic_crypto_client_config.h +++ b/net/quic/crypto/quic_crypto_client_config.h @@ -154,6 +154,9 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { // the server's hostname in order to perform a handshake. This can be checked // with the |IsComplete| member of |CachedState|. // + // |initial_flow_control_window_bytes| is the size of the initial flow + // control window this client will use for new streams. + // // |clock| and |rand| are used to generate the nonce and |out_params| is // filled with the results of the handshake that the server is expected to // accept. |preferred_version| is the version of the QUIC protocol that this @@ -162,6 +165,7 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { QuicErrorCode FillClientHello(const QuicSessionKey& server_key, QuicConnectionId connection_id, const QuicVersion preferred_version, + uint32 initial_flow_control_window_bytes, const CachedState* cached, QuicWallTime now, QuicRandom* rand, diff --git a/net/quic/crypto/quic_crypto_client_config_test.cc b/net/quic/crypto/quic_crypto_client_config_test.cc index b74a37a921e5..79829d81db3f 100644 --- a/net/quic/crypto/quic_crypto_client_config_test.cc +++ b/net/quic/crypto/quic_crypto_client_config_test.cc @@ -6,6 +6,7 @@ #include "net/quic/crypto/proof_verifier.h" #include "net/quic/quic_session_key.h" +#include "net/quic/test_tools/mock_random.h" #include "net/quic/test_tools/quic_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -65,13 +66,35 @@ TEST(QuicCryptoClientConfigTest, InchoateChlo) { EXPECT_EQ(QuicVersionToQuicTag(QuicVersionMax()), cver); } -TEST(QuicCryptoClientConfigTest, PreferAesGcm) { +TEST(QuicCryptoClientConfigTest, FillClientHello) { + QuicCryptoClientConfig::CachedState state; QuicCryptoClientConfig config; - config.SetDefaults(); - if (config.aead.size() > 1) - EXPECT_NE(kAESG, config.aead[0]); - config.PreferAesGcm(); - EXPECT_EQ(kAESG, config.aead[0]); + QuicCryptoNegotiatedParameters params; + QuicConnectionId kConnectionId = 1234; + uint32 kInitialFlowControlWindow = 5678; + string error_details; + MockRandom rand; + CryptoHandshakeMessage chlo; + QuicSessionKey server_key("www.google.com", 80, false, kPrivacyModeDisabled); + config.FillClientHello(server_key, + kConnectionId, + QuicVersionMax(), + kInitialFlowControlWindow, + &state, + QuicWallTime::Zero(), + &rand, + ¶ms, + &chlo, + &error_details); + + // Verify that certain QuicTags have been set correctly in the CHLO. + QuicTag cver; + EXPECT_EQ(QUIC_NO_ERROR, chlo.GetUint32(kVER, &cver)); + EXPECT_EQ(QuicVersionToQuicTag(QuicVersionMax()), cver); + + QuicTag ifcw; + EXPECT_EQ(QUIC_NO_ERROR, chlo.GetUint32(kIFCW, &ifcw)); + EXPECT_EQ(kInitialFlowControlWindow, ifcw); } TEST(QuicCryptoClientConfigTest, InchoateChloSecure) { diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc index 9d60c5f7d942..24623a7b71c7 100644 --- a/net/quic/crypto/quic_crypto_server_config.cc +++ b/net/quic/crypto/quic_crypto_server_config.cc @@ -471,6 +471,7 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( IPEndPoint client_address, QuicVersion version, const QuicVersionVector& supported_versions, + uint32 initial_flow_control_window_bytes, const QuicClock* clock, QuicRandom* rand, QuicCryptoNegotiatedParameters *params, @@ -720,6 +721,10 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello( QuicSocketAddressCoder address_coder(client_address); out->SetStringPiece(kCADR, address_coder.Encode()); out->SetStringPiece(kPUBS, forward_secure_public_value); + + // Set initial receive window for flow control. + out->SetValue(kIFCW, initial_flow_control_window_bytes); + return QUIC_NO_ERROR; } diff --git a/net/quic/crypto/quic_crypto_server_config.h b/net/quic/crypto/quic_crypto_server_config.h index 7c9ed4285867..90d55d2e10ad 100644 --- a/net/quic/crypto/quic_crypto_server_config.h +++ b/net/quic/crypto/quic_crypto_server_config.h @@ -186,6 +186,8 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { // version: version of the QUIC protocol in use for this connection // supported_versions: versions of the QUIC protocol that this server // supports. + // initial_flow_control_window: size of initial flow control window this + // server uses for new streams. // clock: used to validate client nonces and ephemeral keys. // rand: an entropy source // params: the state of the handshake. This may be updated with a server @@ -199,6 +201,7 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig { IPEndPoint client_address, QuicVersion version, const QuicVersionVector& supported_versions, + uint32 initial_flow_control_window_bytes, const QuicClock* clock, QuicRandom* rand, QuicCryptoNegotiatedParameters* params, diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc index 7dd913545dbb..5b14c7dce6de 100644 --- a/net/quic/quic_client_session.cc +++ b/net/quic/quic_client_session.cc @@ -298,12 +298,12 @@ QuicReliableClientStream* QuicClientSession::CreateOutgoingDataStream() { } if (GetNumOpenStreams() >= get_max_open_streams()) { DVLOG(1) << "Failed to create a new outgoing stream. " - << "Already " << GetNumOpenStreams() << " open."; + << "Already " << GetNumOpenStreams() << " open."; return NULL; } if (goaway_received()) { DVLOG(1) << "Failed to create a new outgoing stream. " - << "Already received goaway."; + << "Already received goaway."; return NULL; } if (going_away_) { diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc index 78b25863e69f..121268dadca9 100644 --- a/net/quic/quic_config.cc +++ b/net/quic/quic_config.cc @@ -9,6 +9,7 @@ #include "base/logging.h" #include "net/quic/crypto/crypto_handshake_message.h" #include "net/quic/crypto/crypto_protocol.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_sent_packet_manager.h" #include "net/quic/quic_utils.h" @@ -303,7 +304,8 @@ QuicConfig::QuicConfig() initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL), // TODO(rjshade): Make this PRESENCE_REQUIRED when retiring // QUIC_VERSION_17. - peer_initial_flow_control_window_bytes_(kIFCW, PRESENCE_OPTIONAL, 0) { + peer_initial_flow_control_window_bytes_(kIFCW, PRESENCE_OPTIONAL, + kDefaultFlowControlSendWindow) { // All optional non-zero parameters should be initialized here. server_initial_congestion_window_.set(kMaxInitialWindow, kDefaultInitialWindow); @@ -432,7 +434,9 @@ void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const { server_initial_congestion_window_.ToHandshakeMessage(out); // TODO(ianswett): Don't transmit parameters which are optional and not set. initial_round_trip_time_us_.ToHandshakeMessage(out); - peer_initial_flow_control_window_bytes_.ToHandshakeMessage(out); + + // Don't add peer_initial_flow_control_window_bytes here, it is not a + // negotiated value. } QuicErrorCode QuicConfig::ProcessClientHello( diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h index 1a3e0ca9b3b9..05070d44823a 100644 --- a/net/quic/quic_config.h +++ b/net/quic/quic_config.h @@ -18,11 +18,11 @@ class CryptoHandshakeMessage; // Describes whether or not a given QuicTag is required or optional in the // handshake message. enum QuicConfigPresence { - // This value can be absent from the handshake message. Default value is - // selected as the negotiated value in such a case. + // This negotiable value can be absent from the handshake message. Default + // value is selected as the negotiated value in such a case. PRESENCE_OPTIONAL, - // This value is required in the handshake message otherwise the Process*Hello - // function returns an error. + // This negotiable value is required in the handshake message otherwise the + // Process*Hello function returns an error. PRESENCE_REQUIRED, }; @@ -168,7 +168,7 @@ class NET_EXPORT_PRIVATE QuicFixedUint32 : public QuicConfigValue { void set_value(uint32 value) { value_ = value; } - // Serialises |name_| and |value_| to |out|. + // Serialises |tag_| and |value_| to |out|. virtual void ToHandshakeMessage(CryptoHandshakeMessage* out) const OVERRIDE; // Sets |value_| to the corresponding value from |client_hello_| if it exists. diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc index 8cf17d11e22e..bc91c3ed3bdc 100644 --- a/net/quic/quic_config_test.cc +++ b/net/quic/quic_config_test.cc @@ -6,6 +6,7 @@ #include "net/quic/crypto/crypto_handshake_message.h" #include "net/quic/crypto/crypto_protocol.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_sent_packet_manager.h" #include "net/quic/quic_time.h" @@ -30,12 +31,11 @@ class QuicConfigTest : public ::testing::Test { }; TEST_F(QuicConfigTest, ToHandshakeMessage) { - FLAGS_enable_quic_pacing = false; + ValueRestore old_flag(&FLAGS_enable_quic_pacing, false); config_.SetDefaults(); config_.set_idle_connection_state_lifetime(QuicTime::Delta::FromSeconds(5), QuicTime::Delta::FromSeconds(2)); config_.set_max_streams_per_connection(4, 2); - config_.set_peer_initial_flow_control_window_bytes(6); CryptoHandshakeMessage msg; config_.ToHandshakeMessage(&msg); @@ -48,10 +48,6 @@ TEST_F(QuicConfigTest, ToHandshakeMessage) { EXPECT_EQ(QUIC_NO_ERROR, error); EXPECT_EQ(4u, value); - error = msg.GetUint32(kIFCW, &value); - EXPECT_EQ(QUIC_NO_ERROR, error); - EXPECT_EQ(6u, value); - const QuicTag* out; size_t out_len; error = msg.GetTaglist(kCGST, &out, &out_len); @@ -88,9 +84,6 @@ TEST_F(QuicConfigTest, ProcessClientHello) { client_config.set_initial_round_trip_time_us( 10 * base::Time::kMicrosecondsPerMillisecond, 10 * base::Time::kMicrosecondsPerMillisecond); - const uint32 kFlowControlWindow = 1234; - client_config.set_peer_initial_flow_control_window_bytes(kFlowControlWindow); - CryptoHandshakeMessage msg; client_config.ToHandshakeMessage(&msg); string error_details; @@ -105,8 +98,6 @@ TEST_F(QuicConfigTest, ProcessClientHello) { EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.keepalive_timeout()); EXPECT_EQ(10 * base::Time::kMicrosecondsPerMillisecond, config_.initial_round_trip_time_us()); - EXPECT_EQ(kFlowControlWindow, - config_.peer_initial_flow_control_window_bytes()); } TEST_F(QuicConfigTest, ProcessServerHello) { @@ -125,9 +116,6 @@ TEST_F(QuicConfigTest, ProcessServerHello) { server_config.set_initial_round_trip_time_us( 10 * base::Time::kMicrosecondsPerMillisecond, 10 * base::Time::kMicrosecondsPerMillisecond); - const uint32 kFlowControlWindow = 1234; - server_config.set_peer_initial_flow_control_window_bytes(kFlowControlWindow); - CryptoHandshakeMessage msg; server_config.ToHandshakeMessage(&msg); string error_details; @@ -144,8 +132,6 @@ TEST_F(QuicConfigTest, ProcessServerHello) { EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.keepalive_timeout()); EXPECT_EQ(10 * base::Time::kMicrosecondsPerMillisecond, config_.initial_round_trip_time_us()); - EXPECT_EQ(kFlowControlWindow, - config_.peer_initial_flow_control_window_bytes()); } TEST_F(QuicConfigTest, MissingOptionalValuesInCHLO) { @@ -163,7 +149,8 @@ TEST_F(QuicConfigTest, MissingOptionalValuesInCHLO) { const QuicErrorCode error = config_.ProcessClientHello(msg, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); - EXPECT_EQ(0u, config_.peer_initial_flow_control_window_bytes()); + EXPECT_EQ(kDefaultFlowControlSendWindow, + config_.peer_initial_flow_control_window_bytes()); } TEST_F(QuicConfigTest, MissingOptionalValuesInSHLO) { @@ -179,7 +166,8 @@ TEST_F(QuicConfigTest, MissingOptionalValuesInSHLO) { const QuicErrorCode error = config_.ProcessServerHello(msg, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); - EXPECT_EQ(0u, config_.peer_initial_flow_control_window_bytes()); + EXPECT_EQ(kDefaultFlowControlSendWindow, + config_.peer_initial_flow_control_window_bytes()); } TEST_F(QuicConfigTest, MissingValueInCHLO) { diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index dce0ca15c830..ac586d4dcfe7 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -22,6 +22,7 @@ #include "net/quic/iovector.h" #include "net/quic/quic_bandwidth.h" #include "net/quic/quic_config.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" using base::hash_map; @@ -36,8 +37,6 @@ using std::vector; using std::set; using std::string; -extern bool FLAGS_quic_allow_oversized_packets_for_test; - namespace net { class QuicDecrypter; @@ -168,9 +167,9 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id, QuicConnectionHelperInterface* helper, QuicPacketWriter* writer, bool is_server, - const QuicVersionVector& supported_versions) - : framer_(supported_versions, - helper->GetClock()->ApproximateNow(), + const QuicVersionVector& supported_versions, + uint32 max_flow_control_receive_window_bytes) + : framer_(supported_versions, helper->GetClock()->ApproximateNow(), is_server), helper_(helper), writer_(writer), @@ -204,7 +203,16 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id, version_negotiation_state_(START_NEGOTIATION), is_server_(is_server), connected_(true), - address_migrating_(false) { + address_migrating_(false), + max_flow_control_receive_window_bytes_( + max_flow_control_receive_window_bytes) { + if (max_flow_control_receive_window_bytes_ < kDefaultFlowControlSendWindow) { + DLOG(ERROR) << "Initial receive window (" + << max_flow_control_receive_window_bytes_ + << ") cannot be set lower than default (" + << kDefaultFlowControlSendWindow << ")."; + max_flow_control_receive_window_bytes_ = kDefaultFlowControlSendWindow; + } if (!is_server_) { // Pacing will be enabled if the client negotiates it. sent_packet_manager_.MaybeEnablePacing(); @@ -891,7 +899,7 @@ void QuicConnection::MaybeSendInResponseToPacket() { // are queued locally, or drain streams which are blocked. QuicTime::Delta delay = sent_packet_manager_.TimeUntilSend( time_of_last_received_packet_, NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); + HAS_RETRANSMITTABLE_DATA); if (delay.IsZero()) { send_alarm_->Cancel(); WriteIfNotBlocked(); @@ -1201,7 +1209,7 @@ bool QuicConnection::CanWrite(TransmissionType transmission_type, QuicTime now = clock_->Now(); QuicTime::Delta delay = sent_packet_manager_.TimeUntilSend( - now, transmission_type, retransmittable, handshake); + now, transmission_type, retransmittable); if (delay.IsInfinite()) { return false; } diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index f42b5a7d8046..03b5efcf8b26 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -212,7 +212,8 @@ class NET_EXPORT_PRIVATE QuicConnection QuicConnectionHelperInterface* helper, QuicPacketWriter* writer, bool is_server, - const QuicVersionVector& supported_versions); + const QuicVersionVector& supported_versions, + uint32 max_flow_control_receive_window_bytes); virtual ~QuicConnection(); // Sets connection parameters from the supplied |config|. @@ -445,6 +446,10 @@ class NET_EXPORT_PRIVATE QuicConnection HasRetransmittableData retransmittable, IsHandshake handshake); + uint32 max_flow_control_receive_window_bytes() const { + return max_flow_control_receive_window_bytes_; + } + protected: // Send a packet to the peer using encryption |level|. If |sequence_number| // is present in the |retransmission_map_|, then contents of this packet will @@ -714,6 +719,9 @@ class NET_EXPORT_PRIVATE QuicConnection // version negotiation packet. QuicVersionVector server_supported_versions_; + // Initial flow control receive window size for new streams. + uint32 max_flow_control_receive_window_bytes_; + DISALLOW_COPY_AND_ASSIGN(QuicConnection); }; diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index 485d48b6ff5b..6e51d70403cc 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -14,8 +14,8 @@ #include "net/quic/crypto/null_encrypter.h" #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_protocol.h" -#include "net/quic/quic_sent_packet_manager.h" #include "net/quic/quic_utils.h" #include "net/quic/test_tools/mock_clock.h" #include "net/quic/test_tools/mock_random.h" @@ -404,9 +404,11 @@ class TestConnection : public QuicConnection { TestConnectionHelper* helper, TestPacketWriter* writer, bool is_server, - QuicVersion version) + QuicVersion version, + uint32 flow_control_send_window) : QuicConnection(connection_id, address, helper, writer, is_server, - SupportedVersions(version)), + SupportedVersions(version), + flow_control_send_window), writer_(writer) { // Disable tail loss probes for most tests. QuicSentPacketManagerPeer::SetMaxTailLossProbes( @@ -547,7 +549,8 @@ class QuicConnectionTest : public ::testing::TestWithParam { helper_(new TestConnectionHelper(&clock_, &random_generator_)), writer_(new TestPacketWriter(version())), connection_(connection_id_, IPEndPoint(), helper_.get(), - writer_.get(), false, version()), + writer_.get(), false, version(), + kDefaultFlowControlSendWindow), frame1_(1, false, 0, MakeIOVector(data1)), frame2_(1, false, 3, MakeIOVector(data2)), accept_packet_(true) { @@ -558,17 +561,17 @@ class QuicConnectionTest : public ::testing::TestWithParam { // 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()); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .Times(AnyNumber()); EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly( Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillRepeatedly(Return( QuicBandwidth::FromKBitsPerSecond(100))); - ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .WillByDefault(Return(true)); EXPECT_CALL(visitor_, HasPendingWrites()).Times(AnyNumber()); EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber()); @@ -757,22 +760,22 @@ class QuicConnectionTest : public ::testing::TestWithParam { bool fin, QuicPacketSequenceNumber* last_packet) { QuicByteCount packet_size; - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .WillOnce(DoAll(SaveArg<2>(&packet_size), Return(true))); connection_.SendStreamDataWithString(id, data, offset, fin, NULL); if (last_packet != NULL) { *last_packet = QuicConnectionPeer::GetPacketCreator(&connection_)->sequence_number(); } - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .Times(AnyNumber()); return packet_size; } void SendAckPacketToPeer() { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(1); connection_.SendAck(); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .Times(AnyNumber()); } @@ -1091,14 +1094,14 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSendBadEntropy) { ProcessPacket(1); // Delay sending, then queue up an ack. EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).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(_, NOT_RETRANSMISSION, _, _)).WillRepeatedly( + TimeUntilSend(_, _)).WillRepeatedly( testing::Return(QuicTime::Delta::Zero())); // Skip a packet and then record an ack. creator_.set_sequence_number(2); @@ -1131,7 +1134,7 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) { QuicPacketSequenceNumber original; QuicByteCount packet_size; - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .WillOnce(DoAll(SaveArg<1>(&original), SaveArg<2>(&packet_size), Return(true))); connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL); @@ -1147,8 +1150,7 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) { EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1); QuicPacketSequenceNumber retransmission; EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, packet_size - kQuicVersionSize, - LOSS_RETRANSMISSION, _)) + OnPacketSent(_, _, packet_size - kQuicVersionSize, _)) .WillOnce(DoAll(SaveArg<1>(&retransmission), Return(true))); ProcessAckPacket(&frame); @@ -1164,7 +1166,7 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) { // Now if the peer sends an ack which still reports the retransmitted packet // as missing, that will bundle an ack with data after two acks in a row // indicate the high water mark needs to be raised. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, HAS_RETRANSMITTABLE_DATA)); connection_.SendStreamDataWithString(3, "foo", 3, !kFin, NULL); // No ack sent. @@ -1176,7 +1178,7 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) { EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _)) .WillRepeatedly(Return(SequenceNumberSet())); ProcessAckPacket(&frame2); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, HAS_RETRANSMITTABLE_DATA)); connection_.SendStreamDataWithString(3, "foo", 3, !kFin, NULL); // Ack bundled. @@ -1227,7 +1229,7 @@ TEST_P(QuicConnectionTest, LeastUnackedLower) { // Now claim it's one, but set the ordering so it was sent "after" the first // one. This should cause a connection error. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); creator_.set_sequence_number(7); if (version() > QUIC_VERSION_15) { EXPECT_CALL(visitor_, @@ -1265,7 +1267,7 @@ TEST_P(QuicConnectionTest, AckUnsentData) { // Ack a packet which has not been sent. EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, false)); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); QuicAckFrame frame(1, QuicTime::Zero(), 0); EXPECT_CALL(visitor_, OnCanWrite()).Times(0); ProcessAckPacket(&frame); @@ -1447,7 +1449,7 @@ TEST_P(QuicConnectionTest, FECSending) { connection_.options()->max_packets_per_fec_group = 2; // Send 4 data packets and 2 FEC packets. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(6); // The first stream frame will consume 2 fewer bytes than the other three. const string payload(payload_length * 4 - 6, 'a'); connection_.SendStreamDataWithString(1, payload, 0, !kFin, NULL); @@ -1483,7 +1485,7 @@ TEST_P(QuicConnectionTest, AbandonFECFromCongestionWindow) { } connection_.options()->max_packets_per_fec_group = 1; // 1 Data and 1 FEC packet. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(2); connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL); const QuicTime::Delta retransmission_time = @@ -1492,7 +1494,7 @@ TEST_P(QuicConnectionTest, AbandonFECFromCongestionWindow) { // Abandon FEC packet and data packet. EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(1); EXPECT_CALL(visitor_, OnCanWrite()); connection_.OnRetransmissionTimeout(); } @@ -1505,7 +1507,7 @@ TEST_P(QuicConnectionTest, DontAbandonAckedFEC) { connection_.options()->max_packets_per_fec_group = 1; // 1 Data and 1 FEC packet. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(6); connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL); // Send some more data afterwards to ensure early retransmit doesn't trigger. connection_.SendStreamDataWithString(3, "foo", 3, !kFin, NULL); @@ -1525,7 +1527,7 @@ TEST_P(QuicConnectionTest, DontAbandonAckedFEC) { // Don't abandon the acked FEC packet, but it will abandon 2 the subsequent // FEC packets. EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(3); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(3); connection_.GetRetransmissionAlarm()->Fire(); } @@ -1537,7 +1539,7 @@ TEST_P(QuicConnectionTest, AbandonAllFEC) { connection_.options()->max_packets_per_fec_group = 1; // 1 Data and 1 FEC packet. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(6); connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL); // Send some more data afterwards to ensure early retransmit doesn't trigger. connection_.SendStreamDataWithString(3, "foo", 3, !kFin, NULL); @@ -1585,9 +1587,7 @@ TEST_P(QuicConnectionTest, FramePacking) { IgnoreResult(InvokeWithoutArgs(&connection_, &TestConnection::SendStreamData5)))); - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)) - .Times(1); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(1); // Unblock the connection. connection_.GetSendAlarm()->Fire(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -1621,9 +1621,7 @@ TEST_P(QuicConnectionTest, FramePackingNonCryptoThenCrypto) { IgnoreResult(InvokeWithoutArgs(&connection_, &TestConnection::SendCryptoStreamData)))); - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)) - .Times(2); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(2); // Unblock the connection. connection_.GetSendAlarm()->Fire(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -1649,9 +1647,7 @@ TEST_P(QuicConnectionTest, FramePackingCryptoThenNonCrypto) { IgnoreResult(InvokeWithoutArgs(&connection_, &TestConnection::SendStreamData3)))); - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)) - .Times(3); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(3); // Unblock the connection. connection_.GetSendAlarm()->Fire(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -1681,8 +1677,7 @@ TEST_P(QuicConnectionTest, FramePackingFEC) { IgnoreResult(InvokeWithoutArgs(&connection_, &TestConnection::SendStreamData5)))); - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)).Times(2); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(2); // Unblock the connection. connection_.GetSendAlarm()->Fire(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -1705,9 +1700,7 @@ TEST_P(QuicConnectionTest, FramePackingAckResponse) { IgnoreResult(InvokeWithoutArgs(&connection_, &TestConnection::SendStreamData5)))); - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)) - .Times(1); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(1); // Process an ack to cause the visitor's OnCanWrite to be invoked. creator_.set_sequence_number(2); @@ -1734,7 +1727,7 @@ TEST_P(QuicConnectionTest, FramePackingAckResponse) { TEST_P(QuicConnectionTest, FramePackingSendv) { // Send data in 1 packet by writing multiple blocks in a single iovector // using writev. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); char data[] = "ABCD"; IOVector data_iov; @@ -1758,7 +1751,7 @@ TEST_P(QuicConnectionTest, FramePackingSendv) { TEST_P(QuicConnectionTest, FramePackingSendvQueued) { // Try to send two stream frames in 1 packet by using writev. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); BlockOnNextWrite(); char data[] = "ABCD"; @@ -1783,7 +1776,7 @@ TEST_P(QuicConnectionTest, FramePackingSendvQueued) { TEST_P(QuicConnectionTest, SendingZeroBytes) { // Send a zero byte write with a fin using writev. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); IOVector empty_iov; connection_.SendStreamData(1, empty_iov, 0, kFin, NULL); @@ -1806,7 +1799,7 @@ TEST_P(QuicConnectionTest, OnCanWrite) { &TestConnection::SendStreamData5)))); EXPECT_CALL(visitor_, HasPendingWrites()).WillOnce(Return(true)); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillRepeatedly( + TimeUntilSend(_, _)).WillRepeatedly( testing::Return(QuicTime::Delta::Zero())); connection_.OnCanWrite(); @@ -1847,8 +1840,8 @@ TEST_P(QuicConnectionTest, RetransmitOnNack) { EXPECT_CALL(*send_algorithm_, OnPacketLost(2, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _)).Times(1); EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, second_packet_size - kQuicVersionSize, - LOSS_RETRANSMISSION, _)).Times(1); + OnPacketSent(_, _, second_packet_size - kQuicVersionSize, _)). + Times(1); ProcessAckPacket(&nack_two); } @@ -1887,7 +1880,7 @@ TEST_P(QuicConnectionTest, DiscardRetransmit) { // since the previous transmission has been acked, we will not // send the retransmission. EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, _)).Times(0); + OnPacketSent(_, _, _, _)).Times(0); writer_->SetWritable(); connection_.OnCanWrite(); @@ -1899,7 +1892,7 @@ TEST_P(QuicConnectionTest, RetransmitNackedLargestObserved) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicPacketSequenceNumber largest_observed; QuicByteCount packet_size; - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .WillOnce(DoAll(SaveArg<1>(&largest_observed), SaveArg<2>(&packet_size), Return(true))); connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL); @@ -1915,14 +1908,13 @@ TEST_P(QuicConnectionTest, RetransmitNackedLargestObserved) { EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1); EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, packet_size - kQuicVersionSize, - LOSS_RETRANSMISSION, _)); + OnPacketSent(_, _, packet_size - kQuicVersionSize, _)); ProcessAckPacket(&frame); } TEST_P(QuicConnectionTest, QueueAfterTwoRTOs) { for (int i = 0; i < 10; ++i) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(1); connection_.SendStreamDataWithString(3, "foo", i * 3, !kFin, NULL); } @@ -1940,7 +1932,7 @@ TEST_P(QuicConnectionTest, QueueAfterTwoRTOs) { 2 * DefaultRetransmissionTime().ToMicroseconds())); // Retransmit already retransmitted packets event though the sequence number // greater than the largest observed. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(10); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(10); connection_.GetRetransmissionAlarm()->Fire(); connection_.OnCanWrite(); } @@ -1951,7 +1943,7 @@ TEST_P(QuicConnectionTest, WriteBlockedThenSent) { connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(1); connection_.OnPacketSent(WriteResult(WRITE_STATUS_OK, 0)); EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); } @@ -1968,7 +1960,7 @@ TEST_P(QuicConnectionTest, WriteBlockedAckedThenSent) { QuicAckFrame ack = InitAckFrame(1, 0); ProcessAckPacket(&ack); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(0); connection_.OnPacketSent(WriteResult(WRITE_STATUS_OK, 0)); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); } @@ -2039,7 +2031,7 @@ TEST_P(QuicConnectionTest, NoLimitPacketsPerNack) { 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_, OnPacketSent(_, _, _, _, _)).Times(14); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(14); ProcessAckPacket(&nack); } @@ -2078,7 +2070,7 @@ TEST_P(QuicConnectionTest, DontLatchUnackedPacket) { 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 save them. - ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .WillByDefault(Return(false)); SendAckPacketToPeer(); // Packet 2 @@ -2098,11 +2090,11 @@ TEST_P(QuicConnectionTest, DontLatchUnackedPacket) { // Check that the outgoing ack had its sequence number as least_unacked. EXPECT_EQ(3u, least_unacked()); - ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .WillByDefault(Return(true)); SendStreamDataToPeer(1, "bar", 3, false, NULL); // Packet 4 EXPECT_EQ(4u, outgoing_ack()->sent_info.least_unacked); - ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .WillByDefault(Return(false)); SendAckPacketToPeer(); // Packet 5 EXPECT_EQ(4u, least_unacked()); @@ -2191,7 +2183,7 @@ TEST_P(QuicConnectionTest, RTO) { // Simulate the retransmission alarm firing. clock_.AdvanceTime(DefaultRetransmissionTime()); EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 2u, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 2u, _, _)); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_EQ(2u, last_header()->packet_sequence_number); // We do not raise the high water mark yet. @@ -2219,8 +2211,8 @@ TEST_P(QuicConnectionTest, RTOWithSameEncryptionLevel) { { InSequence s; EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 3, _, RTO_RETRANSMISSION, _)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 4, _, RTO_RETRANSMISSION, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 3, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 4, _, _)); } // Simulate the retransmission alarm firing. @@ -2240,11 +2232,11 @@ TEST_P(QuicConnectionTest, SendHandshakeMessages) { // the end of the packet. We can test this to check which encrypter was used. connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01)); - // Attempt to send a handshake message while the congestion manager - // does not permit sending. + // Attempt to send a handshake message and have the socket block. EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, _, _, IS_HANDSHAKE)).WillRepeatedly( - testing::Return(QuicTime::Delta::Infinite())); + TimeUntilSend(_, _)).WillRepeatedly( + testing::Return(QuicTime::Delta::Zero())); + BlockOnNextWrite(); connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL); // The packet should be serialized, but not queued. EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -2254,9 +2246,7 @@ TEST_P(QuicConnectionTest, SendHandshakeMessages) { connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); // Now become writeable and flush the packets. - EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, _, _, IS_HANDSHAKE)).WillRepeatedly( - testing::Return(QuicTime::Delta::Zero())); + writer_->SetWritable(); EXPECT_CALL(visitor_, OnCanWrite()); connection_.OnCanWrite(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -2277,7 +2267,7 @@ TEST_P(QuicConnectionTest, connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(0); QuicTime default_retransmission_time = clock_.ApproximateNow().Add( DefaultRetransmissionTime()); @@ -2301,7 +2291,7 @@ TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) { SendStreamDataToPeer(2, "bar", 0, !kFin, NULL); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(1); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(1); connection_.RetransmitUnackedPackets(INITIAL_ENCRYPTION_ONLY); @@ -2336,12 +2326,12 @@ TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) { TEST_P(QuicConnectionTest, TestRetransmitOrder) { QuicByteCount first_packet_size; - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).WillOnce( + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).WillOnce( DoAll(SaveArg<2>(&first_packet_size), Return(true))); connection_.SendStreamDataWithString(3, "first_packet", 0, !kFin, NULL); QuicByteCount second_packet_size; - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).WillOnce( + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).WillOnce( DoAll(SaveArg<2>(&second_packet_size), Return(true))); connection_.SendStreamDataWithString(3, "second_packet", 12, !kFin, NULL); EXPECT_NE(first_packet_size, second_packet_size); @@ -2351,9 +2341,9 @@ TEST_P(QuicConnectionTest, TestRetransmitOrder) { { InSequence s; EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, first_packet_size, _, _)); + OnPacketSent(_, _, first_packet_size, _)); EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, second_packet_size, _, _)); + OnPacketSent(_, _, second_packet_size, _)); } connection_.GetRetransmissionAlarm()->Fire(); @@ -2363,9 +2353,9 @@ TEST_P(QuicConnectionTest, TestRetransmitOrder) { { InSequence s; EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, first_packet_size, _, _)); + OnPacketSent(_, _, first_packet_size, _)); EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, second_packet_size, _, _)); + OnPacketSent(_, _, second_packet_size, _)); } connection_.GetRetransmissionAlarm()->Fire(); } @@ -2373,7 +2363,7 @@ TEST_P(QuicConnectionTest, TestRetransmitOrder) { TEST_P(QuicConnectionTest, RetransmissionCountCalculation) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicPacketSequenceNumber original_sequence_number; - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .WillOnce(DoAll(SaveArg<1>(&original_sequence_number), Return(true))); connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL); @@ -2385,7 +2375,7 @@ TEST_P(QuicConnectionTest, RetransmissionCountCalculation) { clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10)); EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); QuicPacketSequenceNumber rto_sequence_number; - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, RTO_RETRANSMISSION, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .WillOnce(DoAll(SaveArg<1>(&rto_sequence_number), Return(true))); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_FALSE(QuicConnectionPeer::IsSavedForRetransmission( @@ -2406,9 +2396,9 @@ TEST_P(QuicConnectionTest, RetransmissionCountCalculation) { QuicPacketSequenceNumber nack_sequence_number = 0; // Ack packets might generate some other packets, which are not // retransmissions. (More ack packets). - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .Times(AnyNumber()); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, LOSS_RETRANSMISSION, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .WillOnce(DoAll(SaveArg<1>(&nack_sequence_number), Return(true))); QuicAckFrame ack = InitAckFrame(rto_sequence_number, 0); // Nack the retransmitted packet. @@ -2439,7 +2429,7 @@ TEST_P(QuicConnectionTest, SetRTOAfterWritingToSocket) { TEST_P(QuicConnectionTest, DelayRTOWithAckReceipt) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .Times(2); connection_.SendStreamDataWithString(2, "foo", 0, !kFin, NULL); connection_.SendStreamDataWithString(3, "bar", 0, !kFin, NULL); @@ -2465,7 +2455,7 @@ TEST_P(QuicConnectionTest, DelayRTOWithAckReceipt) { EXPECT_TRUE(retransmission_alarm->IsSet()); EXPECT_LT(retransmission_alarm->deadline(), clock_.ApproximateNow()); EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, RTO_RETRANSMISSION, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); // Manually cancel the alarm to simulate a real test. connection_.GetRetransmissionAlarm()->Fire(); @@ -2548,7 +2538,7 @@ TEST_P(QuicConnectionTest, DontUpdateQuicCongestionFeedbackFrameForRevived) { TEST_P(QuicConnectionTest, InitialTimeout) { EXPECT_TRUE(connection_.connected()); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); QuicTime default_timeout = clock_.ApproximateNow().Add( QuicTime::Delta::FromSeconds(kDefaultInitialTimeoutSecs)); @@ -2595,7 +2585,7 @@ TEST_P(QuicConnectionTest, TimeoutAfterSend) { // This time, we should time out. EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)), clock_.ApproximateNow()); @@ -2608,9 +2598,9 @@ 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(_, NOT_RETRANSMISSION, _, _)).WillOnce( + TimeUntilSend(_, _)).WillOnce( testing::Return(QuicTime::Delta::Zero())); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -2620,33 +2610,21 @@ 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(_, NOT_RETRANSMISSION, _, _)).WillOnce( + TimeUntilSend(_, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, _, _)).Times(0); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, _)).Times(0); connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); } -TEST_P(QuicConnectionTest, SendSchedulerForce) { - // Test that if we force send a packet, it is not queued. - QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); - EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, LOSS_RETRANSMISSION, _, _)).Times(0); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); - connection_.SendPacket( - ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); - // XXX: fixme. was: connection_.SendPacket(1, packet, kForce); - EXPECT_EQ(0u, connection_.NumQueuedPackets()); -} - TEST_P(QuicConnectionTest, SendSchedulerEAGAIN) { QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); BlockOnNextWrite(); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( + TimeUntilSend(_, _)).WillOnce( testing::Return(QuicTime::Delta::Zero())); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, _, _)).Times(0); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, _)).Times(0); connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -2656,7 +2634,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(_, NOT_RETRANSMISSION, _, _)).WillOnce( + TimeUntilSend(_, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); @@ -2665,19 +2643,18 @@ 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(_, NOT_RETRANSMISSION, _, _)).WillRepeatedly( + TimeUntilSend(_, _)).WillRepeatedly( testing::Return(QuicTime::Delta::Zero())); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); connection_.GetSendAlarm()->Fire(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); } TEST_P(QuicConnectionTest, SendSchedulerDelayThenRetransmit) { - EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _)) + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _)) .WillRepeatedly(testing::Return(QuicTime::Delta::Zero())); - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, 1, _, NOT_RETRANSMISSION, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, _)); connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL); EXPECT_EQ(0u, connection_.NumQueuedPackets()); // Advance the time for retransmission of lost packet. @@ -2686,7 +2663,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenRetransmit) { // sent packet manager, but not yet serialized. EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, RTO_RETRANSMISSION, _, _)).WillOnce( + TimeUntilSend(_, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -2694,12 +2671,11 @@ 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(_, RTO_RETRANSMISSION, _, _)).Times(2). + TimeUntilSend(_, _)).Times(3). WillRepeatedly(testing::Return(QuicTime::Delta::Zero())); // Ensure the scheduler is notified this is a retransmit. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, RTO_RETRANSMISSION, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1)); connection_.GetSendAlarm()->Fire(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -2708,7 +2684,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenRetransmit) { TEST_P(QuicConnectionTest, SendSchedulerDelayAndQueue) { QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( + TimeUntilSend(_, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); @@ -2725,7 +2701,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( + TimeUntilSend(_, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(10))); connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); @@ -2735,10 +2711,10 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) { // retransmit 3. The far end should stop waiting for it. QuicAckFrame frame = InitAckFrame(0, 1); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillRepeatedly( + TimeUntilSend(_, _)).WillRepeatedly( testing::Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, _)); + OnPacketSent(_, _, _, _)); ProcessAckPacket(&frame); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -2750,7 +2726,7 @@ TEST_P(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( + TimeUntilSend(_, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(10))); connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); @@ -2760,7 +2736,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(_, NOT_RETRANSMISSION, _, _)).WillOnce( + TimeUntilSend(_, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(1))); ProcessAckPacket(&frame); @@ -2772,7 +2748,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(_, NOT_RETRANSMISSION, _, _)).WillOnce( + TimeUntilSend(_, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(10))); connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); @@ -2794,7 +2770,7 @@ TEST_P(QuicConnectionTest, TestQueueLimitsOnSendStreamData) { // Queue the first packet. EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce( + TimeUntilSend(_, _)).WillOnce( testing::Return(QuicTime::Delta::FromMicroseconds(10))); const string payload(payload_length, 'a'); EXPECT_EQ(0u, @@ -2812,7 +2788,7 @@ TEST_P(QuicConnectionTest, LoopThroughSendingPackets) { NOT_IN_FEC_GROUP, &payload_length); // Queue the first packet. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(7); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(7); // The first stream frame will consume 2 fewer bytes than the other six. const string payload(payload_length * 7 - 12, 'a'); EXPECT_EQ(payload.size(), @@ -2972,7 +2948,7 @@ TEST_P(QuicConnectionTest, NoAckForClose) { 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); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(0); ProcessClosePacket(2, 0); } @@ -2982,7 +2958,7 @@ TEST_P(QuicConnectionTest, SendWhenDisconnected) { connection_.CloseConnection(QUIC_PEER_GOING_AWAY, false); EXPECT_FALSE(connection_.connected()); QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, _, _)).Times(0); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, _)).Times(0); connection_.SendPacket( ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA); } @@ -3376,22 +3352,18 @@ TEST_P(QuicConnectionTest, BadVersionNegotiation) { } TEST_P(QuicConnectionTest, CheckSendStats) { - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); connection_.SendStreamDataWithString(3, "first", 0, !kFin, NULL); size_t first_packet_size = last_sent_packet_size(); EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, NOT_RETRANSMISSION, _)); + OnPacketSent(_, _, _, _)); connection_.SendStreamDataWithString(5, "second", 0, !kFin, NULL); size_t second_packet_size = last_sent_packet_size(); // 2 retransmissions due to rto, 1 due to explicit nack. EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, RTO_RETRANSMISSION, _)).Times(2); - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, LOSS_RETRANSMISSION, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)).Times(3); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(1); // Retransmit due to RTO. @@ -3666,7 +3638,7 @@ TEST_P(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) { EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(3); EXPECT_CALL(*send_algorithm_, OnPacketLost(2, _)); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); ProcessAckPacket(&frame); // Now we get an ACK for packet 5 (retransmitted packet 2), which should @@ -3700,7 +3672,7 @@ TEST_P(QuicConnectionTest, AckNotifierCallbackForAckAfterRTO) { // Simulate the retransmission alarm firing. clock_.AdvanceTime(DefaultRetransmissionTime()); EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 2u, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 2u, _, _)); connection_.GetRetransmissionAlarm()->Fire(); EXPECT_EQ(2u, last_header()->packet_sequence_number); // We do not raise the high water mark yet. @@ -3750,7 +3722,7 @@ TEST_P(QuicConnectionTest, AckNotifierCallbackForAckOfNackedPacket) { .WillOnce(Return(lost_packets)); EXPECT_CALL(*send_algorithm_, OnPacketLost(2, _)); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(2, _)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)); ProcessAckPacket(&frame); // Now we get an ACK for packet 2, which was previously nacked. @@ -3889,9 +3861,11 @@ TEST_P(QuicConnectionTest, Pacing) { ValueRestore old_flag(&FLAGS_enable_quic_pacing, true); TestConnection server(connection_id_, IPEndPoint(), helper_.get(), - writer_.get(), true, version()); + writer_.get(), true, version(), + kDefaultFlowControlSendWindow); TestConnection client(connection_id_, IPEndPoint(), helper_.get(), - writer_.get(), false, version()); + writer_.get(), false, version(), + kDefaultFlowControlSendWindow); EXPECT_TRUE(client.sent_packet_manager().using_pacing()); EXPECT_FALSE(server.sent_packet_manager().using_pacing()); } @@ -3922,6 +3896,17 @@ TEST_P(QuicConnectionTest, ControlFramesInstigateAcks) { EXPECT_TRUE(ack_alarm->IsSet()); } +TEST_P(QuicConnectionTest, InvalidFlowControlWindow) { + ValueRestore old_flag(&FLAGS_enable_quic_pacing, true); + + const uint32 kSmallerFlowControlWindow = kDefaultFlowControlSendWindow - 1; + TestConnection connection(connection_id_, IPEndPoint(), helper_.get(), + writer_.get(), true, version(), + kSmallerFlowControlWindow); + EXPECT_EQ(kDefaultFlowControlSendWindow, + connection.max_flow_control_receive_window_bytes()); +} + } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc index d71a097d7684..c7d99ca043ac 100644 --- a/net/quic/quic_crypto_client_stream.cc +++ b/net/quic/quic_crypto_client_stream.cc @@ -154,6 +154,7 @@ void QuicCryptoClientStream::DoHandshakeLoop( server_key_, session()->connection()->connection_id(), session()->connection()->supported_versions().front(), + session()->connection()->max_flow_control_receive_window_bytes(), cached, session()->connection()->clock()->WallNow(), session()->connection()->random_generator(), diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc index a69f12638598..a45fbfe233fb 100644 --- a/net/quic/quic_crypto_client_stream_test.cc +++ b/net/quic/quic_crypto_client_stream_test.cc @@ -8,6 +8,7 @@ #include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_session_key.h" #include "net/quic/test_tools/crypto_test_utils.h" diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc index 879bca849e6e..a7de815fcd80 100644 --- a/net/quic/quic_crypto_server_stream.cc +++ b/net/quic/quic_crypto_server_stream.cc @@ -169,6 +169,7 @@ QuicErrorCode QuicCryptoServerStream::ProcessClientHello( session()->connection()->peer_address(), session()->connection()->version(), session()->connection()->supported_versions(), + session()->connection()->max_flow_control_receive_window_bytes(), session()->connection()->clock(), session()->connection()->random_generator(), &crypto_negotiated_params_, reply, error_details); diff --git a/net/quic/quic_crypto_stream.cc b/net/quic/quic_crypto_stream.cc index 414c2e2f7c25..095868a2343d 100644 --- a/net/quic/quic_crypto_stream.cc +++ b/net/quic/quic_crypto_stream.cc @@ -69,4 +69,8 @@ QuicCryptoStream::crypto_negotiated_params() const { return crypto_negotiated_params_; } +bool QuicCryptoStream::IsFlowControlEnabled() const { + return false; +} + } // namespace net diff --git a/net/quic/quic_crypto_stream.h b/net/quic/quic_crypto_stream.h index b29580b84701..8fd376f23b86 100644 --- a/net/quic/quic_crypto_stream.h +++ b/net/quic/quic_crypto_stream.h @@ -51,6 +51,9 @@ class NET_EXPORT_PRIVATE QuicCryptoStream const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const; + // Crypto stream is special and is not flow controlled. + virtual bool IsFlowControlEnabled() const OVERRIDE; + protected: bool encryption_established_; bool handshake_confirmed_; diff --git a/net/quic/quic_crypto_stream_test.cc b/net/quic/quic_crypto_stream_test.cc index c8dbab51453b..1aa682b791eb 100644 --- a/net/quic/quic_crypto_stream_test.cc +++ b/net/quic/quic_crypto_stream_test.cc @@ -10,6 +10,7 @@ #include "base/memory/scoped_ptr.h" #include "net/quic/crypto/crypto_handshake.h" #include "net/quic/crypto/crypto_protocol.h" +#include "net/quic/quic_flags.h" #include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/quic_test_utils.h" #include "testing/gmock/include/gmock/gmock.h" @@ -101,6 +102,11 @@ TEST_F(QuicCryptoStreamTest, ProcessBadData) { EXPECT_EQ(0u, stream_.ProcessRawData(bad.data(), bad.length())); } +TEST_F(QuicCryptoStreamTest, NoFlowControl) { + ValueRestore old_flag(&FLAGS_enable_quic_stream_flow_control, true); + EXPECT_FALSE(stream_.IsFlowControlEnabled()); +} + } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_data_stream.cc b/net/quic/quic_data_stream.cc index 5e0628ad4060..c40b927e0eb8 100644 --- a/net/quic/quic_data_stream.cc +++ b/net/quic/quic_data_stream.cc @@ -184,10 +184,8 @@ bool QuicDataStream::FinishedReadingHeaders() { return headers_decompressed_ && decompressed_headers_.empty(); } -void QuicDataStream::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { - DVLOG(1) << "Received WindowUpdateFrame for stream: " << id() - << ", with byte offset: " << frame.byte_offset; - // TODO(rjshade): Adjust flow control window. +bool QuicDataStream::IsFlowControlEnabled() const { + return version() >= QUIC_VERSION_17; } } // namespace net diff --git a/net/quic/quic_data_stream.h b/net/quic/quic_data_stream.h index 35b485c0a595..e0604719394b 100644 --- a/net/quic/quic_data_stream.h +++ b/net/quic/quic_data_stream.h @@ -109,8 +109,8 @@ class NET_EXPORT_PRIVATE QuicDataStream : public ReliableQuicStream { // Gets the SSL connection information. bool GetSSLInfo(SSLInfo* ssl_info); - // Adjust flow control windows according to new offset in |frame|. - void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame); + // Override base class to enable flow control for data streams. + virtual bool IsFlowControlEnabled() const OVERRIDE; protected: // Sets priority_ to priority. This should only be called before bytes are diff --git a/net/quic/quic_data_stream_test.cc b/net/quic/quic_data_stream_test.cc index 40e6b9a51779..8c3fb4466d67 100644 --- a/net/quic/quic_data_stream_test.cc +++ b/net/quic/quic_data_stream_test.cc @@ -6,17 +6,22 @@ #include "net/quic/quic_ack_notifier.h" #include "net/quic/quic_connection.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" #include "net/quic/quic_write_blocked_list.h" #include "net/quic/spdy_utils.h" #include "net/quic/test_tools/quic_session_peer.h" #include "net/quic/test_tools/quic_test_utils.h" +#include "net/quic/test_tools/reliable_quic_stream_peer.h" +#include "net/test/gtest_util.h" #include "testing/gmock/include/gmock/gmock.h" using base::StringPiece; using std::min; using testing::_; +using testing::AnyNumber; using testing::InSequence; +using testing::Return; using testing::SaveArg; using testing::StrictMock; @@ -274,6 +279,192 @@ TEST_P(QuicDataStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) { } } +TEST_P(QuicDataStreamTest, StreamFlowControlBlocked) { + // Tests that we send a BLOCKED frame to the peer when we attempt to write, + // but are flow control blocked. + if (GetParam() < QUIC_VERSION_17) { + return; + } + ValueRestore old_flag(&FLAGS_enable_quic_stream_flow_control, true); + + Initialize(kShouldProcessData); + + // Set a small flow control limit. + const uint64 kWindow = 36; + ReliableQuicStreamPeer::SetFlowControlSendOffset(stream_.get(), kWindow); + EXPECT_EQ(kWindow, ReliableQuicStreamPeer::SendWindowSize(stream_.get())); + + // Try to send more data than the flow control limit allows. + string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); + string body; + const uint64 kOverflow = 15; + GenerateBody(&body, kWindow + kOverflow); + + EXPECT_CALL(*connection_, SendBlocked(kStreamId)); + EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce( + Return(QuicConsumedData(kWindow, true))); + stream_->WriteOrBufferData(body, false, NULL); + + // Should have sent as much as possible, resulting in no send window left. + EXPECT_EQ(0u, ReliableQuicStreamPeer::SendWindowSize(stream_.get())); + + // And we should have queued the overflowed data. + EXPECT_EQ(kOverflow, + ReliableQuicStreamPeer::SizeOfQueuedData(stream_.get())); +} + +TEST_P(QuicDataStreamTest, StreamFlowControlNoWindowUpdateIfNotConsumed) { + // The flow control receive window decreases whenever we add new bytes to the + // sequencer, whether they are consumed immediately or buffered. However we + // only send WINDOW_UPDATE frames based on increasing number of bytes + // consumed. + if (GetParam() < QUIC_VERSION_17) { + return; + } + ValueRestore old_flag(&FLAGS_enable_quic_stream_flow_control, true); + + // Don't process data - it will be buffered instead. + Initialize(!kShouldProcessData); + + // Expect no WINDOW_UPDATE frames to be sent. + EXPECT_CALL(*connection_, SendWindowUpdate(_, _)).Times(0); + + // Set a small flow control limit. + const uint64 kWindow = 36; + ReliableQuicStreamPeer::SetFlowControlReceiveOffset(stream_.get(), + kWindow); + ReliableQuicStreamPeer::SetFlowControlMaxReceiveWindow(stream_.get(), + kWindow); + EXPECT_EQ(kWindow, ReliableQuicStreamPeer::ReceiveWindowSize(stream_.get())); + + // Stream receives enough data to fill a fraction of the receive window. + string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); + string body; + GenerateBody(&body, kWindow / 3); + stream_->OnStreamHeaders(headers); + EXPECT_EQ(headers, stream_->data()); + stream_->OnStreamHeadersComplete(false, headers.size()); + + QuicStreamFrame frame1(kStreamId, false, 0, MakeIOVector(body)); + stream_->OnStreamFrame(frame1); + EXPECT_EQ(kWindow - (kWindow / 3), + ReliableQuicStreamPeer::ReceiveWindowSize(stream_.get())); + + // Now receive another frame which results in the receive window being over + // half full. This should all be buffered, decreasing the receive window but + // not sending WINDOW_UPDATE. + QuicStreamFrame frame2(kStreamId, false, kWindow / 3, MakeIOVector(body)); + stream_->OnStreamFrame(frame2); + EXPECT_EQ(kWindow - (2 * kWindow / 3), + ReliableQuicStreamPeer::ReceiveWindowSize(stream_.get())); +} + +TEST_P(QuicDataStreamTest, StreamFlowControlWindowUpdate) { + // Tests that on receipt of data, the stream updates its receive window offset + // appropriately, and sends WINDOW_UPDATE frames when its receive window drops + // too low. + if (GetParam() < QUIC_VERSION_17) { + return; + } + ValueRestore old_flag(&FLAGS_enable_quic_stream_flow_control, true); + + Initialize(kShouldProcessData); + + // Set a small flow control limit. + const uint64 kWindow = 36; + ReliableQuicStreamPeer::SetFlowControlReceiveOffset(stream_.get(), + kWindow); + ReliableQuicStreamPeer::SetFlowControlMaxReceiveWindow(stream_.get(), + kWindow); + EXPECT_EQ(kWindow, ReliableQuicStreamPeer::ReceiveWindowSize(stream_.get())); + + // Stream receives enough data to fill a fraction of the receive window. + string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); + string body; + GenerateBody(&body, kWindow / 3); + stream_->OnStreamHeaders(headers); + EXPECT_EQ(headers, stream_->data()); + stream_->OnStreamHeadersComplete(false, headers.size()); + + QuicStreamFrame frame1(kStreamId, false, 0, MakeIOVector(body)); + stream_->OnStreamFrame(frame1); + EXPECT_EQ(kWindow - (kWindow / 3), + ReliableQuicStreamPeer::ReceiveWindowSize(stream_.get())); + + // Now receive another frame which results in the receive window being over + // half full. This will trigger the stream to increase its receive window + // offset and send a WINDOW_UPDATE. The result will be again an available + // window of kWindow bytes. + QuicStreamFrame frame2(kStreamId, false, kWindow / 3, MakeIOVector(body)); + EXPECT_CALL( + *connection_, + SendWindowUpdate( + kStreamId, + ReliableQuicStreamPeer::ReceiveWindowSize(stream_.get()) + kWindow)); + stream_->OnStreamFrame(frame2); + EXPECT_EQ(kWindow, + ReliableQuicStreamPeer::ReceiveWindowSize(stream_.get())); +} + +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. + if (GetParam() < QUIC_VERSION_17) { + return; + } + ValueRestore old_flag(&FLAGS_enable_quic_stream_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 limit. + const uint64 kWindow = 50; + ReliableQuicStreamPeer::SetFlowControlReceiveOffset(stream_.get(), + kWindow); + + string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); + string body; + GenerateBody(&body, kWindow + 1); + + stream_->OnStreamHeaders(headers); + EXPECT_EQ(headers, stream_->data()); + stream_->OnStreamHeadersComplete(false, headers.size()); + + // Receive data to overflow the window, violating flow control. + QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(body)); + EXPECT_CALL(*connection_, SendConnectionClose(QUIC_FLOW_CONTROL_ERROR)); + EXPECT_DFATAL(stream_->OnStreamFrame(frame), + "Server: Flow control violation on stream: 3, our receive " + "offset is: 50, we have consumed: 0, we have buffered: 51, " + "total: 51"); +} + +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. + if (GetParam() < QUIC_VERSION_17) { + return; + } + ValueRestore old_flag(&FLAGS_enable_quic_stream_flow_control, true); + + Initialize(kShouldProcessData); + + // Set a flow control limit of zero. + ReliableQuicStreamPeer::SetFlowControlReceiveOffset(stream_.get(), 0); + EXPECT_EQ(0u, ReliableQuicStreamPeer::ReceiveWindowSize(stream_.get())); + + // Send a frame with a FIN but no data. This should not be blocked. + string body = ""; + bool fin = true; + + EXPECT_CALL(*connection_, SendBlocked(kStreamId)).Times(0); + EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce( + Return(QuicConsumedData(0, fin))); + + stream_->WriteOrBufferData(body, fin, NULL); +} + } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_end_to_end_unittest.cc b/net/quic/quic_end_to_end_unittest.cc index 1f5cc0dfb966..3e493e10b299 100644 --- a/net/quic/quic_end_to_end_unittest.cc +++ b/net/quic/quic_end_to_end_unittest.cc @@ -20,6 +20,7 @@ #include "net/http/http_transaction_unittest.h" #include "net/http/transport_security_state.h" #include "net/proxy/proxy_service.h" +#include "net/quic/test_tools/quic_test_utils.h" #include "net/ssl/ssl_config_service_defaults.h" #include "net/tools/quic/quic_in_memory_cache.h" #include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h" @@ -134,7 +135,8 @@ class QuicEndToEndTest : public PlatformTest { server_config_.SetDefaults(); server_thread_.reset(new ServerThread(server_address_, server_config_, QuicSupportedVersions(), - strike_register_no_startup_period_)); + strike_register_no_startup_period_, + kInitialFlowControlWindowForTest)); server_thread_->Initialize(); server_address_ = IPEndPoint(server_address_.address(), server_thread_->GetPort()); diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc new file mode 100644 index 000000000000..e7a8e4453f05 --- /dev/null +++ b/net/quic/quic_flags.cc @@ -0,0 +1,26 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/quic_flags.h" + +// TODO(rtenneti): Remove this. +// Do not flip this flag until the flakiness of the +// net/tools/quic/end_to_end_test is fixed. +// If true, then QUIC connections will track the retransmission history of a +// packet so that an ack of a previous transmission will ack the data of all +// other transmissions. +bool FLAGS_track_retransmission_history = false; + +// Do not remove this flag until the Finch-trials described in b/11706275 +// are complete. +// If true, QUIC connections will support the use of a pacing algorithm when +// sending packets, in an attempt to reduce packet loss. The client must also +// request pacing for the server to enable it. +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. +bool FLAGS_enable_quic_stream_flow_control = true; + +bool FLAGS_quic_allow_oversized_packets_for_test = false; diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h new file mode 100644 index 000000000000..cb3bb387012d --- /dev/null +++ b/net/quic/quic_flags.h @@ -0,0 +1,15 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_QUIC_FLAGS_H_ +#define NET_QUIC_QUIC_FLAGS_H_ + +#include "net/base/net_export.h" + +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; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_oversized_packets_for_test; + +#endif // NET_QUIC_QUIC_FLAGS_H_ diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index c25926e9423a..3465b3912bab 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc @@ -13,6 +13,7 @@ #include "net/quic/crypto/quic_encrypter.h" #include "net/quic/quic_data_reader.h" #include "net/quic/quic_data_writer.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_socket_address_coder.h" using base::StringPiece; @@ -23,8 +24,6 @@ using std::min; using std::numeric_limits; using std::string; -bool FLAGS_quic_allow_oversized_packets_for_test = false; - namespace net { namespace { diff --git a/net/quic/quic_headers_stream.cc b/net/quic/quic_headers_stream.cc index f3a28c602a1f..bd07772d5d6b 100644 --- a/net/quic/quic_headers_stream.cc +++ b/net/quic/quic_headers_stream.cc @@ -207,6 +207,10 @@ uint32 QuicHeadersStream::ProcessRawData(const char* data, QuicPriority QuicHeadersStream::EffectivePriority() const { return 0; } +bool QuicHeadersStream::IsFlowControlEnabled() const { + return false; +} + void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id, SpdyPriority priority, bool fin) { diff --git a/net/quic/quic_headers_stream.h b/net/quic/quic_headers_stream.h index c3ccbdada408..c57847694165 100644 --- a/net/quic/quic_headers_stream.h +++ b/net/quic/quic_headers_stream.h @@ -37,6 +37,9 @@ class NET_EXPORT_PRIVATE QuicHeadersStream : public ReliableQuicStream { virtual uint32 ProcessRawData(const char* data, uint32 data_len) OVERRIDE; virtual QuicPriority EffectivePriority() const OVERRIDE; + // Headers stream is special and is not flow controlled. + virtual bool IsFlowControlEnabled() const OVERRIDE; + private: class SpdyFramerVisitor; diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc index bec7cb83531d..73dc8356cdee 100644 --- a/net/quic/quic_headers_stream_test.cc +++ b/net/quic/quic_headers_stream_test.cc @@ -4,6 +4,7 @@ #include "net/quic/quic_headers_stream.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" #include "net/quic/spdy_utils.h" #include "net/quic/test_tools/quic_connection_peer.h" @@ -315,6 +316,11 @@ TEST_P(QuicHeadersStreamTest, ProcessSpdyWindowUpdateFrame) { headers_stream_->ProcessRawData(frame->data(), frame->size()); } +TEST_P(QuicHeadersStreamTest, NoFlowControl) { + ValueRestore old_flag(&FLAGS_enable_quic_stream_flow_control, true); + EXPECT_FALSE(headers_stream_->IsFlowControlEnabled()); +} + } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index ac1f715b1acd..63978669afdb 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc @@ -60,7 +60,7 @@ class TestQuicConnection : public QuicConnection { QuicConnectionHelper* helper, QuicPacketWriter* writer) : QuicConnection(connection_id, address, helper, writer, false, - versions) { + versions, kInitialFlowControlWindowForTest) { } void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) { @@ -184,10 +184,10 @@ class QuicHttpStreamTest : public ::testing::TestWithParam { EXPECT_CALL(*receive_algorithm_, RecordIncomingPacket(_, _, _)). Times(AnyNumber()); EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, _)).WillRepeatedly(Return(true)); + OnPacketSent(_, _, _, _)).WillRepeatedly(Return(true)); EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly( Return(QuicTime::Delta::Zero())); - 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 f98af2838780..05e373ce99e2 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc @@ -160,6 +160,8 @@ QuicTag QuicVersionToQuicTag(const QuicVersion version) { return MakeQuicTag('Q', '0', '1', '5'); case QUIC_VERSION_16: return MakeQuicTag('Q', '0', '1', '6'); + case QUIC_VERSION_17: + return MakeQuicTag('Q', '0', '1', '7'); default: // This shold be an ERROR because we should never attempt to convert an // invalid QuicVersion to be written to the wire. @@ -189,6 +191,7 @@ string QuicVersionToString(const QuicVersion version) { RETURN_STRING_LITERAL(QUIC_VERSION_13); RETURN_STRING_LITERAL(QUIC_VERSION_15); RETURN_STRING_LITERAL(QUIC_VERSION_16); + RETURN_STRING_LITERAL(QUIC_VERSION_17); default: return "QUIC_VERSION_UNSUPPORTED"; } diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index b4666dc56472..7dfb5983f482 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -62,6 +62,9 @@ const QuicByteCount kMaxPacketSize = 1452; const size_t kDefaultInitialWindow = 10; const size_t kMaxInitialWindow = 100; +// Default size of initial flow control window. +const uint32 kDefaultFlowControlSendWindow = 16 * 1024; // 16 KB + // Maximum size of the congestion window, in packets, for TCP congestion control // algorithms. const size_t kMaxTcpCongestionWindow = 200; @@ -259,7 +262,8 @@ enum QuicVersion { QUIC_VERSION_13 = 13, QUIC_VERSION_15 = 15, - QUIC_VERSION_16 = 16, // Current version. + QUIC_VERSION_16 = 16, + QUIC_VERSION_17 = 17, // Current version. }; // This vector contains QUIC versions which we currently support. @@ -269,7 +273,8 @@ enum QuicVersion { // // IMPORTANT: if you are addding to this list, follow the instructions at // http://sites/quic/adding-and-removing-versions -static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_16, +static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_17, + QUIC_VERSION_16, QUIC_VERSION_15, QUIC_VERSION_13}; diff --git a/net/quic/quic_received_packet_manager.cc b/net/quic/quic_received_packet_manager.cc index 3e9860b19935..1dc8fc81d1c7 100644 --- a/net/quic/quic_received_packet_manager.cc +++ b/net/quic/quic_received_packet_manager.cc @@ -111,8 +111,8 @@ void QuicReceivedPacketManager::RecordPacketEntropyHash( QuicPacketEntropyHash entropy_hash) { if (sequence_number < largest_sequence_number_) { DVLOG(1) << "Ignoring received packet entropy for sequence_number:" - << sequence_number << " less than largest_peer_sequence_number:" - << largest_sequence_number_; + << sequence_number << " less than largest_peer_sequence_number:" + << largest_sequence_number_; return; } packets_entropy_.insert(make_pair(sequence_number, entropy_hash)); @@ -162,8 +162,8 @@ void QuicReceivedPacketManager::RecalculateEntropyHash( DCHECK_LE(peer_least_unacked, received_info_.largest_observed); if (peer_least_unacked < largest_sequence_number_) { DVLOG(1) << "Ignoring received peer_least_unacked:" << peer_least_unacked - << " less than largest_peer_sequence_number:" - << largest_sequence_number_; + << " less than largest_peer_sequence_number:" + << largest_sequence_number_; return; } largest_sequence_number_ = peer_least_unacked; diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index bd8efb196649..56e515370f64 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc @@ -12,27 +12,13 @@ #include "net/quic/crypto/crypto_protocol.h" #include "net/quic/quic_ack_notifier_manager.h" #include "net/quic/quic_connection_stats.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_utils_chromium.h" using std::make_pair; using std::max; using std::min; -// TODO(rtenneti): Remove this. -// Do not flip this flag until the flakiness of the -// net/tools/quic/end_to_end_test is fixed. -// If true, then QUIC connections will track the retransmission history of a -// packet so that an ack of a previous transmission will ack the data of all -// other transmissions. -bool FLAGS_track_retransmission_history = false; - -// Do not remove this flag until the Finch-trials described in b/11706275 -// are complete. -// If true, QUIC connections will support the use of a pacing algorithm when -// sending packets, in an attempt to reduce packet loss. The client must also -// request pacing for the server to enable it. -bool FLAGS_enable_quic_pacing = true; - namespace net { namespace { static const int kDefaultRetransmissionTimeMs = 500; @@ -242,7 +228,6 @@ void QuicSentPacketManager::MarkForRetransmission( const QuicUnackedPacketMap::TransmissionInfo& transmission_info = unacked_packets_.GetTransmissionInfo(sequence_number); LOG_IF(DFATAL, transmission_info.retransmittable_frames == NULL); - LOG_IF(DFATAL, transmission_info.sent_time == QuicTime::Zero()); // TODO(ianswett): Currently the RTO can fire while there are pending NACK // retransmissions for the same data, which is not ideal. if (ContainsKey(pending_retransmissions_, sequence_number)) { @@ -261,13 +246,28 @@ QuicSentPacketManager::PendingRetransmission DCHECK(!pending_retransmissions_.empty()); QuicPacketSequenceNumber sequence_number = pending_retransmissions_.begin()->first; + TransmissionType transmission_type = pending_retransmissions_.begin()->second; + if (unacked_packets_.HasPendingCryptoPackets()) { + // Ensure crypto packets are retransmitted before other packets. + PendingRetransmissionMap::const_iterator it = + pending_retransmissions_.begin(); + do { + if (HasCryptoHandshake( + unacked_packets_.GetTransmissionInfo(it->first))) { + sequence_number = it->first; + transmission_type = it->second; + break; + } + ++it; + } while (it != pending_retransmissions_.end()); + } DCHECK(unacked_packets_.IsUnacked(sequence_number)); const QuicUnackedPacketMap::TransmissionInfo& transmission_info = unacked_packets_.GetTransmissionInfo(sequence_number); DCHECK(transmission_info.retransmittable_frames); return PendingRetransmission(sequence_number, - pending_retransmissions_.begin()->second, + transmission_type, *transmission_info.retransmittable_frames, transmission_info.sequence_number_length); } @@ -372,7 +372,6 @@ bool QuicSentPacketManager::OnPacketSent( // Only track packets the send algorithm wants us to track. if (!send_algorithm_->OnPacketSent(sent_time, sequence_number, bytes, - transmission_type, has_retransmittable_data)) { unacked_packets_.RemovePacket(sequence_number); // Do not reset the retransmission timer, since the packet isn't tracked. @@ -605,10 +604,13 @@ void QuicSentPacketManager::MaybeUpdateRTT( QuicTime::Delta QuicSentPacketManager::TimeUntilSend( QuicTime now, TransmissionType transmission_type, - HasRetransmittableData retransmittable, - IsHandshake handshake) { - return send_algorithm_->TimeUntilSend(now, transmission_type, retransmittable, - handshake); + HasRetransmittableData retransmittable) { + // The TLP logic is entirely contained within QuicSentPacketManager, so the + // send algorithm does not need to be consulted. + if (transmission_type == TLP_RETRANSMISSION) { + return QuicTime::Delta::Zero(); + } + return send_algorithm_->TimeUntilSend(now, 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 827977596a6a..512fa4883a28 100644 --- a/net/quic/quic_sent_packet_manager.h +++ b/net/quic/quic_sent_packet_manager.h @@ -23,9 +23,6 @@ #include "net/quic/quic_protocol.h" #include "net/quic/quic_unacked_packet_map.h" -NET_EXPORT_PRIVATE extern bool FLAGS_track_retransmission_history; -NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_pacing; - namespace net { namespace test { @@ -139,8 +136,7 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager { // calculations. virtual QuicTime::Delta TimeUntilSend(QuicTime now, TransmissionType transmission_type, - HasRetransmittableData retransmittable, - IsHandshake handshake); + HasRetransmittableData retransmittable); // Returns amount of time for delayed ack timer. const QuicTime::Delta DelayedAckTime() const; diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc index 4e8b9ca3e40d..192fd3823fba 100644 --- a/net/quic/quic_sent_packet_manager_test.cc +++ b/net/quic/quic_sent_packet_manager_test.cc @@ -89,7 +89,7 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam { void RetransmitAndSendPacket(QuicPacketSequenceNumber old_sequence_number, QuicPacketSequenceNumber new_sequence_number) { RetransmitPacket(old_sequence_number, new_sequence_number); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, new_sequence_number, _, _, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, new_sequence_number, _, _)) .WillOnce(Return(true)); manager_.OnPacketSent(new_sequence_number, clock_.Now(), @@ -122,7 +122,7 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam { } void SendDataPacket(QuicPacketSequenceNumber sequence_number) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, sequence_number, _, _, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, sequence_number, _, _)) .Times(1).WillOnce(Return(true)); SerializedPacket packet(CreateDataPacket(sequence_number)); manager_.OnSerializedPacket(packet); @@ -132,7 +132,7 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam { } void SendCryptoPacket(QuicPacketSequenceNumber sequence_number) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, sequence_number, _, _, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, sequence_number, _, _)) .Times(1).WillOnce(Return(true)); SerializedPacket packet(CreateDataPacket(sequence_number)); packet.retransmittable_frames->AddStreamFrame( @@ -144,7 +144,7 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam { } void SendFecPacket(QuicPacketSequenceNumber sequence_number) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, sequence_number, _, _, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, sequence_number, _, _)) .Times(1).WillOnce(Return(true)); SerializedPacket packet(CreateFecPacket(sequence_number)); manager_.OnSerializedPacket(packet); @@ -158,7 +158,7 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam { QuicPacketSequenceNumber retransmission_sequence_number) { EXPECT_TRUE(manager_.HasPendingRetransmissions()); EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, retransmission_sequence_number, _, _, _)) + OnPacketSent(_, retransmission_sequence_number, _, _)) .Times(1).WillOnce(Return(true)); const QuicSentPacketManager::PendingRetransmission pending = manager_.NextPendingRetransmission(); @@ -290,7 +290,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitAndSendThenAckPrevious) { TEST_F(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) { SendDataPacket(1); RetransmitPacket(1, 2); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 2, _, _, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 2, _, _)) .WillOnce(Return(true)); manager_.OnPacketSent(2, clock_.ApproximateNow(), 1000, LOSS_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); @@ -581,7 +581,7 @@ TEST_F(QuicSentPacketManagerTest, GetSentTime) { SerializedPacket serialized_packet(CreateFecPacket(1)); manager_.OnSerializedPacket(serialized_packet); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, _, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 1, _, _)) .Times(1).WillOnce(Return(true)); manager_.OnPacketSent( 1, QuicTime::Zero(), 1000, NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA); @@ -589,7 +589,7 @@ TEST_F(QuicSentPacketManagerTest, GetSentTime) { SerializedPacket serialized_packet2(CreateFecPacket(2)); QuicTime sent_time = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(1)); manager_.OnSerializedPacket(serialized_packet2); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 2, _, _, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, 2, _, _)) .Times(1).WillOnce(Return(true)); manager_.OnPacketSent( 2, sent_time, 1000, NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA); @@ -645,7 +645,7 @@ TEST_F(QuicSentPacketManagerTest, FackRetransmit14PacketsAlternateAcks) { // Transmit 15 packets of data and 15 ack packets. The send algorithm will // inform the congestion manager not to save the acks by returning false. for (QuicPacketSequenceNumber i = 1; i <= kNumSentPackets; ++i) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .Times(1).WillOnce(Return(i % 2 == 0 ? false : true)); SerializedPacket packet(CreatePacket(i, i % 2 == 1)); manager_.OnSerializedPacket(packet); @@ -873,6 +873,41 @@ TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); } +TEST_F(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) { + // Send 2 crypto packets and 3 data packets. + const size_t kNumSentCryptoPackets = 2; + for (size_t i = 1; i <= kNumSentCryptoPackets; ++i) { + SendCryptoPacket(i); + } + const size_t kNumSentDataPackets = 3; + for (size_t i = 1; i <= kNumSentDataPackets; ++i) { + SendDataPacket(kNumSentCryptoPackets + i); + } + 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); + EXPECT_FALSE(manager_.HasPendingRetransmissions()); + EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); + + // 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. + ASSERT_TRUE(manager_.HasPendingRetransmissions()); + EXPECT_EQ(6u, manager_.NextPendingRetransmission().sequence_number); + RetransmitNextPacket(8); + EXPECT_EQ(7u, manager_.NextPendingRetransmission().sequence_number); + RetransmitNextPacket(9); + + EXPECT_TRUE(manager_.HasPendingRetransmissions()); +} + TEST_F(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) { // Send 1 crypto packet. SendCryptoPacket(1); diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index c2d25b747ba0..055eb5be0e66 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc @@ -280,7 +280,7 @@ void QuicSession::OnCanWrite() { has_pending_handshake_ = false; // We just popped it. } ReliableQuicStream* stream = GetStream(stream_id); - if (stream != NULL) { + if (stream != NULL && !stream->IsFlowControlBlocked()) { // If the stream can't write all bytes, it'll re-add itself to the blocked // list. stream->OnCanWrite(); @@ -364,6 +364,26 @@ bool QuicSession::IsCryptoHandshakeConfirmed() { void QuicSession::OnConfigNegotiated() { connection_->SetFromConfig(config_); + // Tell all streams about the newly received peer receive window. + if (connection()->version() >= QUIC_VERSION_17) { + // Streams which were created before the SHLO was received (0RTT requests) + // are now informed of the peer's initial flow control window. + uint32 new_flow_control_send_window = + config_.peer_initial_flow_control_window_bytes(); + if (new_flow_control_send_window < kDefaultFlowControlSendWindow) { + LOG(DFATAL) + << "Peer sent us an invalid flow control send window: " + << new_flow_control_send_window + << ", below default: " << kDefaultFlowControlSendWindow; + connection_->SendConnectionClose(QUIC_FLOW_CONTROL_ERROR); + return; + } + DataStreamMap::iterator it = stream_map_.begin(); + while (it != stream_map_.end()) { + it->second->UpdateFlowControlSendLimit(new_flow_control_send_window); + it++; + } + } } void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { @@ -522,6 +542,9 @@ void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) { #ifndef NDEBUG ReliableQuicStream* stream = GetStream(id); if (stream != NULL) { + if (stream->IsFlowControlBlocked()) { + LOG(DFATAL) << "Stream " << id << " is flow control blocked."; + } LOG_IF(DFATAL, priority != stream->EffectivePriority()) << "Priorities do not match. Got: " << priority << " Expected: " << stream->EffectivePriority(); @@ -541,6 +564,19 @@ void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) { write_blocked_streams_.PushBack(id, priority); } +void QuicSession::MarkFlowControlBlocked(QuicStreamId id, + QuicPriority priority) { + ReliableQuicStream* stream = GetStream(id); + if (stream == NULL) { + LOG(DFATAL) << "Trying to mark nonexistent stream " << id + << " flow control blocked."; + return; + } + + // Send a BLOCKED frame to peer. + connection()->SendBlocked(id); +} + bool QuicSession::HasDataToWrite() const { return write_blocked_streams_.HasWriteBlockedStreams() || connection_->HasQueuedData(); diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index 76fb274078b1..06b56e22edc1 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h @@ -179,6 +179,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { virtual size_t GetNumOpenStreams() const; void MarkWriteBlocked(QuicStreamId id, QuicPriority priority); + void MarkFlowControlBlocked(QuicStreamId id, QuicPriority priority); // Returns true if the session has data to be sent, either queued in the // connection, or in a write-blocked stream. diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc index 54c6cbbb8e73..762be71f46e1 100644 --- a/net/quic/quic_session_test.cc +++ b/net/quic/quic_session_test.cc @@ -11,6 +11,7 @@ #include "base/containers/hash_tables.h" #include "net/quic/crypto/crypto_protocol.h" #include "net/quic/quic_crypto_stream.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_utils.h" #include "net/quic/reliable_quic_stream.h" @@ -20,6 +21,7 @@ #include "net/quic/test_tools/quic_test_utils.h" #include "net/quic/test_tools/reliable_quic_stream_peer.h" #include "net/spdy/spdy_framer.h" +#include "net/test/gtest_util.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -51,6 +53,8 @@ class TestCryptoStream : public QuicCryptoStream { handshake_confirmed_ = true; CryptoHandshakeMessage msg; string error_details; + session()->config()->set_peer_initial_flow_control_window_bytes( + kInitialFlowControlWindowForTest); session()->config()->ToHandshakeMessage(&msg); const QuicErrorCode error = session()->config()->ProcessClientHello( msg, &error_details); @@ -74,6 +78,10 @@ class TestStream : public QuicDataStream { return data_len; } + void SendBody(const string& data, bool fin) { + WriteOrBufferData(data, fin, NULL); + } + MOCK_METHOD0(OnCanWrite, void()); }; @@ -98,7 +106,8 @@ class TestSession : public QuicSession { public: explicit TestSession(QuicConnection* connection) : QuicSession(connection, DefaultQuicConfig()), - crypto_stream_(this) { + crypto_stream_(this), + writev_consumes_all_data_(false) { } virtual TestCryptoStream* GetCryptoStream() OVERRIDE { @@ -123,7 +132,29 @@ class TestSession : public QuicSession { return QuicSession::GetIncomingDataStream(stream_id); } + virtual QuicConsumedData WritevData( + QuicStreamId id, + const IOVector& data, + QuicStreamOffset offset, + bool fin, + QuicAckNotifier::DelegateInterface* ack_notifier_delegate) OVERRIDE { + // Always consumes everything. + if (writev_consumes_all_data_) { + return QuicConsumedData(data.TotalBufferSize(), fin); + } else { + return QuicSession::WritevData(id, data, offset, fin, + ack_notifier_delegate); + } + } + + void set_writev_consumes_all_data(bool val) { + writev_consumes_all_data_ = val; + } + + private: TestCryptoStream crypto_stream_; + + bool writev_consumes_all_data_; }; class QuicSessionTest : public ::testing::TestWithParam { @@ -193,7 +224,7 @@ TEST_P(QuicSessionTest, PeerAddress) { TEST_P(QuicSessionTest, IsCryptoHandshakeConfirmed) { EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed()); CryptoHandshakeMessage message; - session_.crypto_stream_.OnHandshakeMessage(message); + session_.GetCryptoStream()->OnHandshakeMessage(message); EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed()); } @@ -302,6 +333,14 @@ TEST_P(QuicSessionTest, OnCanWrite) { TestStream* stream4 = session_.CreateOutgoingDataStream(); TestStream* stream6 = session_.CreateOutgoingDataStream(); + // Streams should not be flow control blocked _and_ write blocked. + // WINDOW_UPDATE frames ensure that streams are not flow control blocked. + if (version() >= QUIC_VERSION_17) { + stream2->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream2->id(), 1234)); + stream4->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream4->id(), 1234)); + stream6->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream6->id(), 1234)); + } + session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority); session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority); session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); @@ -328,18 +367,26 @@ TEST_P(QuicSessionTest, OnCanWriteCongestionControlBlocks) { TestStream* stream4 = session_.CreateOutgoingDataStream(); TestStream* stream6 = session_.CreateOutgoingDataStream(); + // Streams should not be flow control blocked _and_ write blocked. + // WINDOW_UPDATE frames ensure that streams are not flow control blocked. + if (version() >= QUIC_VERSION_17) { + stream2->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream2->id(), 1234)); + stream4->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream4->id(), 1234)); + stream6->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream6->id(), 1234)); + } + session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority); session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority); 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. @@ -347,14 +394,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(); @@ -366,11 +413,19 @@ TEST_P(QuicSessionTest, BufferedHandshake) { // Test that blocking other streams does not change our status. TestStream* stream2 = session_.CreateOutgoingDataStream(); + // Ensure stream is not flow control blocked. + if (version() >= QUIC_VERSION_17) { + stream2->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream2->id(), 1234)); + } StreamBlocker stream2_blocker(&session_, stream2->id()); stream2_blocker.MarkWriteBlocked(); EXPECT_FALSE(session_.HasPendingHandshake()); TestStream* stream3 = session_.CreateOutgoingDataStream(); + // Ensure stream is not flow control blocked. + if (version() >= QUIC_VERSION_17) { + stream3->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream3->id(), 1234)); + } StreamBlocker stream3_blocker(&session_, stream3->id()); stream3_blocker.MarkWriteBlocked(); EXPECT_FALSE(session_.HasPendingHandshake()); @@ -380,6 +435,10 @@ TEST_P(QuicSessionTest, BufferedHandshake) { EXPECT_TRUE(session_.HasPendingHandshake()); TestStream* stream4 = session_.CreateOutgoingDataStream(); + // Ensure stream is not flow control blocked. + if (version() >= QUIC_VERSION_17) { + stream4->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream4->id(), 1234)); + } StreamBlocker stream4_blocker(&session_, stream4->id()); stream4_blocker.MarkWriteBlocked(); EXPECT_TRUE(session_.HasPendingHandshake()); @@ -414,6 +473,14 @@ TEST_P(QuicSessionTest, OnCanWriteWithClosedStream) { TestStream* stream4 = session_.CreateOutgoingDataStream(); TestStream* stream6 = session_.CreateOutgoingDataStream(); + // Streams should not be flow control blocked _and_ write blocked. + // WINDOW_UPDATE frames ensure that streams are not flow control blocked. + if (version() >= QUIC_VERSION_17) { + stream2->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream2->id(), 1234)); + stream4->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream4->id(), 1234)); + stream6->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream6->id(), 1234)); + } + session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority); session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority); session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); @@ -449,7 +516,7 @@ TEST_P(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) { EXPECT_EQ(kDefaultInitialTimeoutSecs, QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); CryptoHandshakeMessage msg; - session_.crypto_stream_.OnHandshakeMessage(msg); + session_.GetCryptoStream()->OnHandshakeMessage(msg); EXPECT_EQ(kDefaultTimeoutSecs, QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); } @@ -468,6 +535,59 @@ TEST_P(QuicSessionTest, RstStreamBeforeHeadersDecompressed) { EXPECT_EQ(0u, session_.GetNumOpenStreams()); } +TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedStream) { + // Test that if a stream is flow control blocked, then on receipt of the SHLO + // containing a suitable send window offset, the stream becomes unblocked. + if (version() < QUIC_VERSION_17) { + return; + } + ValueRestore old_flag(&FLAGS_enable_quic_stream_flow_control, true); + + // Ensure that Writev consumes all the data it is given (simulate no socket + // blocking). + session_.set_writev_consumes_all_data(true); + + // Create a stream, and send enough data to make it flow control blocked. + TestStream* stream2 = session_.CreateOutgoingDataStream(); + string body(kDefaultFlowControlSendWindow, '.'); + EXPECT_FALSE(stream2->IsFlowControlBlocked()); + stream2->SendBody(body, false); + EXPECT_TRUE(stream2->IsFlowControlBlocked()); + + // Now complete the crypto handshake, resulting in an increased flow control + // send window. + CryptoHandshakeMessage msg; + session_.GetCryptoStream()->OnHandshakeMessage(msg); + + // Stream is now unblocked. + EXPECT_FALSE(stream2->IsFlowControlBlocked()); +} + +TEST_P(QuicSessionTest, InvalidFlowControlWindowInHandshake) { + // Test that receipt of an invalid (< default) flow control window from peer + // results in the connection being torn down. + if (version() < QUIC_VERSION_17) { + return; + } + ValueRestore old_flag(&FLAGS_enable_quic_stream_flow_control, true); + + uint32 kInvalidWindow = kDefaultFlowControlSendWindow - 1; + + CryptoHandshakeMessage msg; + string error_details; + session_.config()->set_peer_initial_flow_control_window_bytes(kInvalidWindow); + session_.config()->ToHandshakeMessage(&msg); + const QuicErrorCode error = + session_.config()->ProcessClientHello(msg, &error_details); + EXPECT_EQ(QUIC_NO_ERROR, error); + + EXPECT_CALL(*connection_, SendConnectionClose(QUIC_FLOW_CONTROL_ERROR)); + string expected_error("Peer sent us an invalid flow control send window: "); + expected_error.append(reinterpret_cast(&kInvalidWindow), + sizeof(kInvalidWindow)); + EXPECT_DFATAL(session_.OnConfigNegotiated(), expected_error); +} + } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index 3aec036970a4..a822856fab31 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc @@ -55,6 +55,9 @@ enum CreateSessionFailure { const uint64 kBrokenAlternateProtocolDelaySecs = 300; +// The initial receive window size for both streams and sessions. +const int32 kInitialReceiveWindowSize = 10 * 1024 * 1024; // 10MB + void HistogramCreateSessionFailure(enum CreateSessionFailure error) { UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error, CREATION_ERROR_MAX); @@ -740,10 +743,9 @@ int QuicStreamFactory::CreateSession( clock_.get(), random_generator_)); } - QuicConnection* connection = new QuicConnection(connection_id, addr, - helper_.get(), - writer.get(), false, - supported_versions_); + QuicConnection* connection = + new QuicConnection(connection_id, addr, helper_.get(), writer.get(), + false, supported_versions_, kInitialReceiveWindowSize); writer->SetConnection(connection); connection->options()->max_packet_length = max_packet_length_; diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc index 28328c4f469d..937d92891ae5 100644 --- a/net/quic/quic_stream_sequencer.cc +++ b/net/quic/quic_stream_sequencer.cc @@ -112,6 +112,8 @@ bool QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { data.iovec()[i].iov_len); } num_bytes_consumed_ += bytes_consumed; + stream_->MaybeSendWindowUpdate(); + if (MaybeCloseStream()) { return true; } @@ -287,6 +289,8 @@ void QuicStreamSequencer::FlushBufferedFrames() { void QuicStreamSequencer::RecordBytesConsumed(size_t bytes_consumed) { num_bytes_consumed_ += bytes_consumed; num_bytes_buffered_ -= bytes_consumed; + + stream_->MaybeSendWindowUpdate(); } } // namespace net diff --git a/net/quic/quic_stream_sequencer.h b/net/quic/quic_stream_sequencer.h index 5cdf8ad1b551..d24e8c5904b5 100644 --- a/net/quic/quic_stream_sequencer.h +++ b/net/quic/quic_stream_sequencer.h @@ -73,9 +73,8 @@ class NET_EXPORT_PRIVATE QuicStreamSequencer { // Blocks processing of frames until |FlushBufferedFrames| is called. void SetBlockedUntilFlush(); - size_t num_bytes_buffered() const { - return num_bytes_buffered_; - } + size_t num_bytes_buffered() const { return num_bytes_buffered_; } + QuicStreamOffset num_bytes_consumed() const { return num_bytes_consumed_; } private: friend class test::QuicStreamSequencerPeer; diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc index 3cb56fdd6b5f..2ae9ba34dbc3 100644 --- a/net/quic/quic_stream_sequencer_test.cc +++ b/net/quic/quic_stream_sequencer_test.cc @@ -81,6 +81,9 @@ class MockStream : public ReliableQuicStream { virtual QuicPriority EffectivePriority() const { return QuicUtils::HighestPriority(); } + virtual bool IsFlowControlEnabled() const { + return true; + } }; namespace { diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index edcb0261e05f..c03e5f3f2a29 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc @@ -5,6 +5,7 @@ #include "net/quic/reliable_quic_stream.h" #include "base/logging.h" +#include "net/quic/iovector.h" #include "net/quic/quic_session.h" #include "net/quic/quic_write_blocked_list.h" @@ -104,8 +105,7 @@ ReliableQuicStream::PendingData::PendingData( ReliableQuicStream::PendingData::~PendingData() { } -ReliableQuicStream::ReliableQuicStream(QuicStreamId id, - QuicSession* session) +ReliableQuicStream::ReliableQuicStream(QuicStreamId id, QuicSession* session) : sequencer_(this), id_(id), session_(session), @@ -113,12 +113,22 @@ ReliableQuicStream::ReliableQuicStream(QuicStreamId id, stream_bytes_written_(0), stream_error_(QUIC_STREAM_NO_ERROR), connection_error_(QUIC_NO_ERROR), + flow_control_send_limit_( + session_->config()->peer_initial_flow_control_window_bytes()), + max_flow_control_receive_window_bytes_( + session_->connection()->max_flow_control_receive_window_bytes()), + flow_control_receive_window_offset_bytes_( + session_->connection()->max_flow_control_receive_window_bytes()), read_side_closed_(false), write_side_closed_(false), fin_buffered_(false), fin_sent_(false), rst_sent_(false), is_server_(session_->is_server()) { + DVLOG(1) << ENDPOINT << "Created stream " << id_ + << ", setting initial receive window to: " + << flow_control_receive_window_offset_bytes_ + << ", setting send window to: " << flow_control_send_limit_; } ReliableQuicStream::~ReliableQuicStream() { @@ -143,14 +153,63 @@ bool ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) { // We don't want to be reading: blackhole the data. return true; } - // Note: This count include duplicate data received. + + // This count include duplicate data received. stream_bytes_read_ += frame.data.TotalBufferSize(); bool accepted = sequencer_.OnStreamFrame(frame); + if (IsFlowControlEnabled()) { + if (flow_control_receive_window_offset_bytes_ < TotalReceivedBytes()) { + // TODO(rjshade): Lower severity from DFATAL once we have established that + // flow control is working correctly. + LOG(DFATAL) + << ENDPOINT << "Flow control violation on stream: " << id() + << ", our receive offset is: " + << flow_control_receive_window_offset_bytes_ + << ", we have consumed: " << sequencer_.num_bytes_consumed() + << ", we have buffered: " << sequencer_.num_bytes_buffered() + << ", total: " << TotalReceivedBytes(); + session_->connection()->SendConnectionClose(QUIC_FLOW_CONTROL_ERROR); + return false; + } + MaybeSendWindowUpdate(); + } + return accepted; } +void ReliableQuicStream::MaybeSendWindowUpdate() { + if (!IsFlowControlEnabled()) { + return; + } + + // Send WindowUpdate to increase receive window if + // (receive window offset - consumed bytes) < (max window / 2). + // This is behaviour copied from SPDY. + size_t consumed_window = flow_control_receive_window_offset_bytes_ - + sequencer_.num_bytes_consumed(); + size_t threshold = (max_flow_control_receive_window_bytes_ / 2); + if (consumed_window < threshold) { + // Update our receive window. + flow_control_receive_window_offset_bytes_ += + (max_flow_control_receive_window_bytes_ - consumed_window); + DVLOG(1) << ENDPOINT << "Stream: " << id() + << ", sending WindowUpdate frame. " + << "Consumed bytes: " << sequencer_.num_bytes_consumed() + << ", Receive window offset: " + << flow_control_receive_window_offset_bytes_ + << ", Consumed window: " << consumed_window + << ", and threshold: " << threshold + << ". New receive window offset is: " + << flow_control_receive_window_offset_bytes_; + + // Inform the peer of our new receive window. + session()->connection()->SendWindowUpdate( + id(), flow_control_receive_window_offset_bytes_); + } +} + void ReliableQuicStream::OnStreamReset(const QuicRstStreamFrame& frame) { stream_error_ = frame.error_code; CloseWriteSide(); @@ -280,10 +339,29 @@ QuicConsumedData ReliableQuicStream::WritevData( return QuicConsumedData(0, false); } - size_t write_length = 0u; - for (int i = 0; i < iov_count; ++i) { - write_length += iov[i].iov_len; - // TODO(rjshade): Maybe block write based on available flow control window. + // How much data we want to write. + size_t write_length = TotalIovecLength(iov, iov_count); + + // How much data we are allowed to write from flow control. + size_t send_window = SendWindowSize(); + + // A FIN with zero data payload should not be flow control blocked. + bool fin_with_zero_data = (fin && write_length == 0); + + if (IsFlowControlEnabled()) { + if (send_window == 0 && !fin_with_zero_data) { + // Quick return if we can't send anything. + session_->MarkFlowControlBlocked(id(), EffectivePriority()); + return QuicConsumedData(0, false); + } + + if (write_length > send_window) { + // Don't send the FIN if we aren't going to send all the data. + fin = false; + + // Writing more data would be a violation of flow control. + write_length = send_window; + } } // Fill an IOVector with bytes from the iovec. @@ -293,7 +371,20 @@ QuicConsumedData ReliableQuicStream::WritevData( QuicConsumedData consumed_data = session()->WritevData( id(), data, stream_bytes_written_, fin, ack_notifier_delegate); stream_bytes_written_ += consumed_data.bytes_consumed; + if (consumed_data.bytes_consumed == write_length) { + if (IsFlowControlEnabled() && write_length == send_window && + !fin_with_zero_data) { + DVLOG(1) << ENDPOINT << "Stream " << id() + << " is flow control blocked. " + << "Send window: " << send_window + << ", stream_bytes_written: " << stream_bytes_written_ + << ", flow_control_send_limit: " + << flow_control_send_limit_; + // The entire send_window has been consumed, we are now flow control + // blocked. + session_->MarkFlowControlBlocked(id(), EffectivePriority()); + } if (fin && consumed_data.fin_consumed) { fin_sent_ = true; CloseWriteSide(); @@ -351,4 +442,57 @@ void ReliableQuicStream::OnClose() { } } +void ReliableQuicStream::OnWindowUpdateFrame( + const QuicWindowUpdateFrame& frame) { + if (!IsFlowControlEnabled()) { + DLOG(DFATAL) << "Flow control not enabled! " << version(); + return; + } + + DVLOG(1) << ENDPOINT + << "OnWindowUpdateFrame for stream " << id() + << " with byte offset " << frame.byte_offset + << " , current offset: " << flow_control_send_limit_ << ")."; + + UpdateFlowControlSendLimit(frame.byte_offset); +} + +void ReliableQuicStream::UpdateFlowControlSendLimit(QuicStreamOffset offset) { + if (offset <= flow_control_send_limit_) { + DVLOG(1) << ENDPOINT << "Stream " << id() + << ", not changing window, current: " << flow_control_send_limit_ + << " new: " << offset; + // No change to our send window. + return; + } + + DVLOG(1) << ENDPOINT << "Stream " << id() + << ", changing window, current: " << flow_control_send_limit_ + << " new: " << offset; + // Send window has increased. + flow_control_send_limit_ = offset; + + // We can write again! + // TODO(rjshade): This does not respect priorities (e.g. multiple outstanding + // POSTs are unblocked on arrival of SHLO with initial window). + OnCanWrite(); +} + +bool ReliableQuicStream::IsFlowControlBlocked() const { + if (IsFlowControlEnabled()) { + return stream_bytes_written_ == flow_control_send_limit_ || + SendWindowSize() == 0; + } else { + return false; + } +} + +uint64 ReliableQuicStream::SendWindowSize() const { + return flow_control_send_limit_ - stream_bytes_written(); +} + +uint64 ReliableQuicStream::TotalReceivedBytes() const { + return sequencer_.num_bytes_consumed() + sequencer_.num_bytes_buffered(); +} + } // namespace net diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h index 15cd03056418..44b0bb5375fb 100644 --- a/net/quic/reliable_quic_stream.h +++ b/net/quic/reliable_quic_stream.h @@ -92,6 +92,20 @@ class NET_EXPORT_PRIVATE ReliableQuicStream { void set_fin_sent(bool fin_sent) { fin_sent_ = fin_sent; } void set_rst_sent(bool rst_sent) { rst_sent_ = rst_sent; } + // Adjust our flow control windows according to new offset in |frame|. + virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame); + + // True if this stream is blocked from writing due to flow control limits. + bool IsFlowControlBlocked() const; + + // Updates our send window offset (if offset larger). + void UpdateFlowControlSendLimit(QuicStreamOffset offset); + + // If our receive window has dropped below the threshold, then send a + // WINDOW_UPDATE frame. This is called whenever bytes are consumed from the + // sequencer's buffer. + void MaybeSendWindowUpdate(); + protected: // Sends as much of 'data' to the connection as the connection will consume, // and then buffers any remaining data in queued_data_. @@ -127,6 +141,9 @@ class NET_EXPORT_PRIVATE ReliableQuicStream { const QuicStreamSequencer* sequencer() const { return &sequencer_; } QuicStreamSequencer* sequencer() { return &sequencer_; } + // Returns true if flow control is enabled for this stream. + virtual bool IsFlowControlEnabled() const = 0; + private: friend class test::ReliableQuicStreamPeer; friend class QuicStreamUtils; @@ -143,6 +160,12 @@ class NET_EXPORT_PRIVATE ReliableQuicStream { scoped_refptr delegate; }; + // Calculates and returns available flow control send window. + uint64 SendWindowSize() const; + + // Calculates and returns total number of bytes this stream has received. + uint64 TotalReceivedBytes() const; + std::list queued_data_; QuicStreamSequencer sequencer_; @@ -161,6 +184,23 @@ class NET_EXPORT_PRIVATE ReliableQuicStream { // should check |connection_error_|. QuicErrorCode connection_error_; + // Stream level flow control. + // This stream is allowed to send up to flow_control_send_limit_ bytes. Once + // it has reached this limit it must not send more data until it receives a + // suitable WINDOW_UPDATE frame from the peer. + QuicStreamOffset flow_control_send_limit_; + + // Stream level flow control. + // The maximum size of the stream receive window. Used to determine by how + // much we should increase the window offset when sending a WINDOW_UPDATE. + uint64 max_flow_control_receive_window_bytes_; + + // Stream level flow control. + // This stream expects to receive up to receive_window_offset_bytes_. + // If the peer sends more than this (without sending us a WINDOW_UPDATE frame + // first), then this is a flow control error. + QuicStreamOffset flow_control_receive_window_offset_bytes_; + // True if the read side is closed and further frames should be rejected. bool read_side_closed_; // True if the write side is closed, and further writes should fail. diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc index 9ea4fd6b52da..23602a349a3f 100644 --- a/net/quic/reliable_quic_stream_test.cc +++ b/net/quic/reliable_quic_stream_test.cc @@ -6,6 +6,7 @@ #include "net/quic/quic_ack_notifier.h" #include "net/quic/quic_connection.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" #include "net/quic/quic_write_blocked_list.h" #include "net/quic/spdy_utils.h" @@ -57,6 +58,10 @@ class TestStream : public ReliableQuicStream { return QuicUtils::HighestPriority(); } + virtual bool IsFlowControlEnabled() const OVERRIDE { + return true; + } + using ReliableQuicStream::WriteOrBufferData; using ReliableQuicStream::CloseReadSide; using ReliableQuicStream::CloseWriteSide; @@ -69,7 +74,8 @@ class TestStream : public ReliableQuicStream { class ReliableQuicStreamTest : public ::testing::TestWithParam { public: - ReliableQuicStreamTest() { + ReliableQuicStreamTest() + : initial_flow_control_window_bytes_(kMaxPacketSize) { headers_[":host"] = "www.google.com"; headers_[":path"] = "/index.hml"; headers_[":scheme"] = "https"; @@ -102,6 +108,12 @@ class ReliableQuicStreamTest : public ::testing::TestWithParam { void Initialize(bool stream_should_process_data) { connection_ = new StrictMock(kIsServer); session_.reset(new StrictMock(connection_)); + + // New streams rely on having the peer's flow control receive window + // negotiated in the config. + session_->config()->set_peer_initial_flow_control_window_bytes( + initial_flow_control_window_bytes_); + stream_.reset(new TestStream(kStreamId, session_.get(), stream_should_process_data)); stream2_.reset(new TestStream(kStreamId + 2, session_.get(), @@ -113,6 +125,10 @@ class ReliableQuicStreamTest : public ::testing::TestWithParam { bool fin_sent() { return ReliableQuicStreamPeer::FinSent(stream_.get()); } bool rst_sent() { return ReliableQuicStreamPeer::RstSent(stream_.get()); } + void set_initial_flow_control_window_bytes(uint32 val) { + initial_flow_control_window_bytes_ = val; + } + protected: MockConnection* connection_; scoped_ptr session_; @@ -120,6 +136,7 @@ class ReliableQuicStreamTest : public ::testing::TestWithParam { scoped_ptr stream2_; SpdyHeaderBlock headers_; QuicWriteBlockedList* write_blocked_list_; + uint32 initial_flow_control_window_bytes_; }; TEST_F(ReliableQuicStreamTest, WriteAllData) { @@ -291,6 +308,37 @@ TEST_F(ReliableQuicStreamTest, OnlySendOneRst) { EXPECT_TRUE(rst_sent()); } +TEST_F(ReliableQuicStreamTest, StreamFlowControlMultipleWindowUpdates) { + ValueRestore old_flag(&FLAGS_enable_quic_stream_flow_control, true); + set_initial_flow_control_window_bytes(1000); + + Initialize(kShouldProcessData); + + // If we receive multiple WINDOW_UPDATES (potentially out of order), then we + // want to make sure we latch the largest offset we see. + + // Initially should be default. + EXPECT_EQ(initial_flow_control_window_bytes_, + ReliableQuicStreamPeer::SendWindowOffset(stream_.get())); + + // Check a single WINDOW_UPDATE results in correct offset. + QuicWindowUpdateFrame window_update_1(stream_->id(), 1234); + stream_->OnWindowUpdateFrame(window_update_1); + EXPECT_EQ(window_update_1.byte_offset, + ReliableQuicStreamPeer::SendWindowOffset(stream_.get())); + + // Now send a few more WINDOW_UPDATES and make sure that only the largest is + // remembered. + QuicWindowUpdateFrame window_update_2(stream_->id(), 1); + QuicWindowUpdateFrame window_update_3(stream_->id(), 9999); + QuicWindowUpdateFrame window_update_4(stream_->id(), 5678); + stream_->OnWindowUpdateFrame(window_update_2); + stream_->OnWindowUpdateFrame(window_update_3); + stream_->OnWindowUpdateFrame(window_update_4); + EXPECT_EQ(window_update_3.byte_offset, + ReliableQuicStreamPeer::SendWindowOffset(stream_.get())); +} + void SaveProxyAckNotifierDelegate( scoped_refptr* delegate_out, QuicAckNotifier::DelegateInterface* delegate) { diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index 7d24b2f3f9be..fbba0042ae3a 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc @@ -270,7 +270,8 @@ MockConnection::MockConnection(bool is_server) IPEndPoint(TestPeerIPAddress(), kTestPort), new testing::NiceMock(), new testing::NiceMock(), - is_server, QuicSupportedVersions()), + is_server, QuicSupportedVersions(), + kInitialFlowControlWindowForTest), writer_(QuicConnectionPeer::GetWriter(this)), helper_(helper()) { } @@ -280,7 +281,8 @@ MockConnection::MockConnection(IPEndPoint address, : QuicConnection(kTestConnectionId, address, new testing::NiceMock(), new testing::NiceMock(), - is_server, QuicSupportedVersions()), + is_server, QuicSupportedVersions(), + kInitialFlowControlWindowForTest), writer_(QuicConnectionPeer::GetWriter(this)), helper_(helper()) { } @@ -291,7 +293,8 @@ MockConnection::MockConnection(QuicConnectionId connection_id, IPEndPoint(TestPeerIPAddress(), kTestPort), new testing::NiceMock(), new testing::NiceMock(), - is_server, QuicSupportedVersions()), + is_server, QuicSupportedVersions(), + kInitialFlowControlWindowForTest), writer_(QuicConnectionPeer::GetWriter(this)), helper_(helper()) { } @@ -302,7 +305,8 @@ MockConnection::MockConnection(bool is_server, IPEndPoint(TestPeerIPAddress(), kTestPort), new testing::NiceMock(), new testing::NiceMock(), - is_server, supported_versions), + is_server, supported_versions, + kInitialFlowControlWindowForTest), writer_(QuicConnectionPeer::GetWriter(this)), helper_(helper()) { } @@ -459,6 +463,14 @@ IPAddressNumber Loopback4() { return addr; } +void GenerateBody(string* body, int length) { + body->clear(); + body->reserve(length); + for (int i = 0; i < length; ++i) { + body->append(1, static_cast(32 + i % (126 - 32))); + } +} + QuicEncryptedPacket* ConstructEncryptedPacket( QuicConnectionId connection_id, bool version_flag, diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 1cca4e860ee6..ba106f7f70e5 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h @@ -30,6 +30,7 @@ namespace test { static const QuicConnectionId kTestConnectionId = 42; static const int kTestPort = 123; +static const uint32 kInitialFlowControlWindowForTest = 32 * 1024; // 32 KB // Returns the test peer IP address. IPAddressNumber TestPeerIPAddress(); @@ -43,6 +44,8 @@ QuicVersion QuicVersionMin(); // Returns an address for 127.0.0.1. IPAddressNumber Loopback4(); +void GenerateBody(std::string* body, int length); + // Create an encrypted packet for testing. QuicEncryptedPacket* ConstructEncryptedPacket( QuicConnectionId connection_id, @@ -457,15 +460,14 @@ class MockSendAlgorithm : public SendAlgorithmInterface { MOCK_METHOD2(OnPacketAcked, void(QuicPacketSequenceNumber, QuicByteCount)); MOCK_METHOD2(OnPacketLost, void(QuicPacketSequenceNumber, QuicTime)); - MOCK_METHOD5(OnPacketSent, + MOCK_METHOD4(OnPacketSent, bool(QuicTime sent_time, QuicPacketSequenceNumber, QuicByteCount, - TransmissionType, HasRetransmittableData)); + HasRetransmittableData)); MOCK_METHOD1(OnRetransmissionTimeout, void(bool)); MOCK_METHOD2(OnPacketAbandoned, void(QuicPacketSequenceNumber sequence_number, QuicByteCount abandoned_bytes)); - MOCK_METHOD4(TimeUntilSend, QuicTime::Delta(QuicTime now, TransmissionType, - HasRetransmittableData, - IsHandshake)); + MOCK_METHOD2(TimeUntilSend, QuicTime::Delta(QuicTime now, + HasRetransmittableData)); MOCK_CONST_METHOD0(BandwidthEstimate, QuicBandwidth(void)); MOCK_METHOD1(UpdateRtt, void(QuicTime::Delta rtt_sample)); MOCK_CONST_METHOD0(RetransmissionDelay, QuicTime::Delta(void)); diff --git a/net/quic/test_tools/reliable_quic_stream_peer.cc b/net/quic/test_tools/reliable_quic_stream_peer.cc index 5b69a30e0939..09b628022ba1 100644 --- a/net/quic/test_tools/reliable_quic_stream_peer.cc +++ b/net/quic/test_tools/reliable_quic_stream_peer.cc @@ -4,6 +4,8 @@ #include "net/quic/test_tools/reliable_quic_stream_peer.h" +#include + #include "net/quic/reliable_quic_stream.h" namespace net { @@ -37,5 +39,62 @@ bool ReliableQuicStreamPeer::RstSent(ReliableQuicStream* stream) { return stream->rst_sent_; } +// static +void ReliableQuicStreamPeer::SetFlowControlSendOffset( + ReliableQuicStream* stream, + QuicStreamOffset offset) { + stream->flow_control_send_limit_ = offset; +} + +// static +void ReliableQuicStreamPeer::SetFlowControlReceiveOffset( + ReliableQuicStream* stream, + QuicStreamOffset offset) { + stream->flow_control_receive_window_offset_bytes_ = offset; +} + +// static +void ReliableQuicStreamPeer::SetFlowControlMaxReceiveWindow( + ReliableQuicStream* stream, + uint64 window_size) { + stream->max_flow_control_receive_window_bytes_ = window_size; +} + +// static +QuicStreamOffset ReliableQuicStreamPeer::SendWindowOffset( + ReliableQuicStream* stream) { + return stream->flow_control_send_limit_; +} + +// static +QuicStreamOffset ReliableQuicStreamPeer::SendWindowSize( + ReliableQuicStream* stream) { + return stream->SendWindowSize(); +} + +// static +QuicStreamOffset ReliableQuicStreamPeer::ReceiveWindowOffset( + ReliableQuicStream* stream) { + return stream->flow_control_receive_window_offset_bytes_; +} + +// static +uint64 ReliableQuicStreamPeer::ReceiveWindowSize(ReliableQuicStream* stream) { + return stream->flow_control_receive_window_offset_bytes_ - + stream->TotalReceivedBytes(); +} + +// static +uint32 ReliableQuicStreamPeer::SizeOfQueuedData(ReliableQuicStream* stream) { + uint32 total = 0; + std::list::iterator it = + stream->queued_data_.begin(); + while (it != stream->queued_data_.end()) { + total += it->data.size(); + ++it; + } + return total; +} + } // namespace test } // namespace net diff --git a/net/quic/test_tools/reliable_quic_stream_peer.h b/net/quic/test_tools/reliable_quic_stream_peer.h index 0ac4e15caefe..38d4b1e93d88 100644 --- a/net/quic/test_tools/reliable_quic_stream_peer.h +++ b/net/quic/test_tools/reliable_quic_stream_peer.h @@ -24,6 +24,19 @@ class ReliableQuicStreamPeer { static bool FinSent(ReliableQuicStream* stream); static bool RstSent(ReliableQuicStream* stream); + static void SetFlowControlSendOffset(ReliableQuicStream* stream, + QuicStreamOffset offset); + static void SetFlowControlReceiveOffset(ReliableQuicStream* stream, + QuicStreamOffset offset); + static void SetFlowControlMaxReceiveWindow(ReliableQuicStream* stream, + uint64 window_size); + static QuicStreamOffset SendWindowOffset(ReliableQuicStream* stream); + static uint64 SendWindowSize(ReliableQuicStream* stream); + static QuicStreamOffset ReceiveWindowOffset(ReliableQuicStream* stream); + static uint64 ReceiveWindowSize(ReliableQuicStream* stream); + + static uint32 SizeOfQueuedData(ReliableQuicStream* stream); + private: DISALLOW_COPY_AND_ASSIGN(ReliableQuicStreamPeer); }; diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index dcba71aefb5d..b598fef65802 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc @@ -16,6 +16,7 @@ #include "net/quic/congestion_control/tcp_cubic_sender.h" #include "net/quic/crypto/aes_128_gcm_12_encrypter.h" #include "net/quic/crypto/null_encrypter.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_framer.h" #include "net/quic/quic_packet_creator.h" #include "net/quic/quic_protocol.h" @@ -44,6 +45,7 @@ using base::StringPiece; using base::WaitableEvent; +using net::test::GenerateBody; using net::test::QuicConnectionPeer; using net::test::QuicSessionPeer; using net::test::ReliableQuicStreamPeer; @@ -62,14 +64,6 @@ namespace { const char* kFooResponseBody = "Artichoke hearts make me happy."; const char* kBarResponseBody = "Palm hearts are pretty delicious, also."; -void GenerateBody(string* body, int length) { - body->clear(); - body->reserve(length); - for (int i = 0; i < length; ++i) { - body->append(1, static_cast(32 + i % (126 - 32))); - } -} - // Run all tests with the cross products of all versions. struct TestParams { TestParams(const QuicVersionVector& client_supported_versions, @@ -163,6 +157,10 @@ class EndToEndTest : public ::testing::TestWithParam { server_supported_versions_ = GetParam().server_supported_versions; negotiated_version_ = GetParam().negotiated_version; FLAGS_enable_quic_pacing = GetParam().use_pacing; + + if (negotiated_version_ >= QUIC_VERSION_17) { + FLAGS_enable_quic_stream_flow_control = true; + } VLOG(1) << "Using Configuration: " << GetParam(); client_config_.SetDefaults(); @@ -170,6 +168,12 @@ class EndToEndTest : public ::testing::TestWithParam { server_config_.set_initial_round_trip_time_us(kMaxInitialRoundTripTimeUs, 0); + // Use different flow control windows for client/server. + client_initial_flow_control_receive_window_ = + 2 * kInitialFlowControlWindowForTest; + server_initial_flow_control_receive_window_ = + 3 * kInitialFlowControlWindowForTest; + QuicInMemoryCachePeer::ResetForTests(); AddToCache("GET", "https://www.google.com/foo", "HTTP/1.1", "200", "OK", kFooResponseBody); @@ -184,16 +188,30 @@ class EndToEndTest : public ::testing::TestWithParam { } QuicTestClient* CreateQuicClient(QuicPacketWriterWrapper* writer) { - QuicTestClient* client = new QuicTestClient(server_address_, - server_key_, - false, // not secure - client_config_, - client_supported_versions_); + QuicTestClient* client = new QuicTestClient( + server_address_, + server_key_, + false, // not secure + client_config_, + client_supported_versions_, + client_initial_flow_control_receive_window_); client->UseWriter(writer); client->Connect(); return client; } + void set_client_initial_flow_control_receive_window(uint32 window) { + CHECK(client_.get() == NULL); + DVLOG(1) << "Setting client initial flow control window: " << window; + client_initial_flow_control_receive_window_ = window; + } + + void set_server_initial_flow_control_receive_window(uint32 window) { + CHECK(server_thread_.get() == NULL); + DVLOG(1) << "Setting server initial flow control window: " << window; + server_initial_flow_control_receive_window_ = window; + } + bool Initialize() { // Start the server first, because CreateQuicClient() attempts // to connect to the server. @@ -220,9 +238,12 @@ class EndToEndTest : public ::testing::TestWithParam { } void StartServer() { - server_thread_.reset(new ServerThread(server_address_, server_config_, - server_supported_versions_, - strike_register_no_startup_period_)); + server_thread_.reset( + new ServerThread(server_address_, + server_config_, + server_supported_versions_, + strike_register_no_startup_period_, + server_initial_flow_control_receive_window_)); server_thread_->Initialize(); server_address_ = IPEndPoint(server_address_.address(), server_thread_->GetPort()); @@ -294,6 +315,8 @@ class EndToEndTest : public ::testing::TestWithParam { QuicVersionVector server_supported_versions_; QuicVersion negotiated_version_; bool strike_register_no_startup_period_; + uint32 client_initial_flow_control_receive_window_; + uint32 server_initial_flow_control_receive_window_; }; // Run all end to end tests with all supported versions. @@ -545,6 +568,14 @@ TEST_P(EndToEndTest, DISABLED_LargePostZeroRTTFailure) { // The 0-RTT handshake should succeed. client_->Connect(); + if (client_supported_versions_[0] >= QUIC_VERSION_17 && + negotiated_version_ < QUIC_VERSION_17) { + // If the version negotiation has resulted in a downgrade, then the client + // must wait for the handshake to complete before sending any data. + // Otherwise it may have queued QUIC_VERSION_17 frames which will trigger a + // DFATAL when they are serialized after the downgrade. + client_->client()->WaitForCryptoHandshakeConfirmed(); + } client_->WaitForResponseForMs(-1); ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request)); @@ -558,6 +589,14 @@ TEST_P(EndToEndTest, DISABLED_LargePostZeroRTTFailure) { StartServer(); client_->Connect(); + if (client_supported_versions_[0] >= QUIC_VERSION_17 && + negotiated_version_ < QUIC_VERSION_17) { + // If the version negotiation has resulted in a downgrade, then the client + // must wait for the handshake to complete before sending any data. + // Otherwise it may have queued QUIC_VERSION_17 frames which will trigger a + // DFATAL when they are serialized after the downgrade. + client_->client()->WaitForCryptoHandshakeConfirmed(); + } ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request)); EXPECT_EQ(2, client_->client()->session()->GetNumSentClientHellos()); @@ -871,6 +910,39 @@ TEST_P(EndToEndTest, ConnectionMigration) { EXPECT_EQ(QUIC_ERROR_MIGRATING_ADDRESS, client_->connection_error()); } +TEST_P(EndToEndTest, DifferentFlowControlWindows) { + // Client and server can set different initial flow control receive windows. + // These are sent in CHLO/SHLO. Tests that these values are exchanged properly + // in the crypto handshake. + + const uint32 kClientIFCW = 123456; + set_client_initial_flow_control_receive_window(kClientIFCW); + + const uint32 kServerIFCW = 654321; + set_server_initial_flow_control_receive_window(kServerIFCW); + + ASSERT_TRUE(Initialize()); + + // Values are exchanged during crypto handshake, so wait for that to finish. + client_->client()->WaitForCryptoHandshakeConfirmed(); + server_thread_->WaitForCryptoHandshakeConfirmed(); + + // Client should have the right value for server's receive window. + EXPECT_EQ(kServerIFCW, client_->client() + ->session() + ->config() + ->peer_initial_flow_control_window_bytes()); + + // Server should have the right value for client's receive window. + server_thread_->Pause(); + QuicDispatcher* dispatcher = + QuicServerPeer::GetDispatcher(server_thread_->server()); + QuicSession* session = dispatcher->session_map().begin()->second; + EXPECT_EQ(kClientIFCW, + session->config()->peer_initial_flow_control_window_bytes()); + server_thread_->Resume(); +} + } // namespace } // namespace test } // namespace tools diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc index 83d867f92b72..f0cca3b56918 100644 --- a/net/tools/quic/quic_client.cc +++ b/net/tools/quic/quic_client.cc @@ -34,7 +34,8 @@ const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET; QuicClient::QuicClient(IPEndPoint server_address, const QuicSessionKey& server_key, const QuicVersionVector& supported_versions, - bool print_response) + bool print_response, + uint32 initial_flow_control_window) : server_address_(server_address), server_key_(server_key), local_port_(0), @@ -44,14 +45,16 @@ QuicClient::QuicClient(IPEndPoint server_address, packets_dropped_(0), overflow_supported_(false), supported_versions_(supported_versions), - print_response_(print_response) { + print_response_(print_response), + initial_flow_control_window_(initial_flow_control_window) { config_.SetDefaults(); } QuicClient::QuicClient(IPEndPoint server_address, const QuicSessionKey& server_key, const QuicConfig& config, - const QuicVersionVector& supported_versions) + const QuicVersionVector& supported_versions, + uint32 initial_flow_control_window) : server_address_(server_address), server_key_(server_key), config_(config), @@ -62,7 +65,8 @@ QuicClient::QuicClient(IPEndPoint server_address, packets_dropped_(0), overflow_supported_(false), supported_versions_(supported_versions), - print_response_(false) { + print_response_(false), + initial_flow_control_window_(initial_flow_control_window) { } QuicClient::~QuicClient() { @@ -166,7 +170,8 @@ bool QuicClient::StartConnect() { server_key_, config_, new QuicConnection(GenerateConnectionId(), server_address_, helper_.get(), - writer_.get(), false, supported_versions_), + writer_.get(), false, supported_versions_, + initial_flow_control_window_), &crypto_config_)); return session_->CryptoConnect(); } diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h index a5b91125ffdb..a439d28e84c5 100644 --- a/net/tools/quic/quic_client.h +++ b/net/tools/quic/quic_client.h @@ -50,11 +50,13 @@ class QuicClient : public EpollCallbackInterface, QuicClient(IPEndPoint server_address, const QuicSessionKey& server_key, const QuicVersionVector& supported_versions, - bool print_response); + bool print_response, + uint32 initial_flow_control_window); QuicClient(IPEndPoint server_address, const QuicSessionKey& server_key, const QuicConfig& config, - const QuicVersionVector& supported_versions); + const QuicVersionVector& supported_versions, + uint32 initial_flow_control_window); virtual ~QuicClient(); @@ -236,6 +238,9 @@ class QuicClient : public EpollCallbackInterface, // when the stream is closed (in OnClose). bool print_response_; + // Size of initial flow control receive window to advertise to server. + uint32 initial_flow_control_window_; + DISALLOW_COPY_AND_ASSIGN(QuicClient); }; diff --git a/net/tools/quic/quic_client_bin.cc b/net/tools/quic/quic_client_bin.cc index 8f4ad502982c..7f11827661ee 100644 --- a/net/tools/quic/quic_client_bin.cc +++ b/net/tools/quic/quic_client_bin.cc @@ -5,6 +5,8 @@ // A binary wrapper for QuicClient. Connects to --hostname via --address // on --port and requests URLs specified on the command line. // Pass --secure to check the certificates using proof verifier. +// Pass --initial_flow_control_window to specify the size of the initial flow +// control receive window to advertise to server. // // For example: // quic_client --address=127.0.0.1 --port=6122 --hostname=www.google.com @@ -21,9 +23,14 @@ #include "net/quic/quic_protocol.h" #include "net/tools/quic/quic_client.h" +// The port the quic client will connect to. int32 FLAGS_port = 6121; std::string FLAGS_address = "127.0.0.1"; +// The hostname the quic client will connect to. std::string FLAGS_hostname = "localhost"; +// Size of the initial flow control receive window to advertise to server. +int32 FLAGS_initial_flow_control_window = 100 * net::kMaxPacketSize; +// Check the certificates using proof verifier. bool FLAGS_secure = false; int main(int argc, char *argv[]) { @@ -76,7 +83,7 @@ int main(int argc, char *argv[]) { net::IPEndPoint(addr, FLAGS_port), net::QuicSessionKey(FLAGS_hostname, FLAGS_port, FLAGS_secure, net::kPrivacyModeDisabled), - net::QuicSupportedVersions(), true); + net::QuicSupportedVersions(), true, FLAGS_initial_flow_control_window); client.Initialize(); diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc index 92e5d706e231..0fed4fd3bcfd 100644 --- a/net/tools/quic/quic_dispatcher.cc +++ b/net/tools/quic/quic_dispatcher.cc @@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/stl_util.h" #include "net/quic/quic_blocked_writer_interface.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" #include "net/tools/quic/quic_default_packet_writer.h" #include "net/tools/quic/quic_epoll_connection_helper.h" @@ -139,16 +140,19 @@ class QuicDispatcher::QuicFramerVisitor : public QuicFramerVisitorInterface { QuicDispatcher::QuicDispatcher(const QuicConfig& config, const QuicCryptoServerConfig& crypto_config, const QuicVersionVector& supported_versions, - EpollServer* epoll_server) + EpollServer* epoll_server, + uint32 initial_flow_control_window_bytes) : config_(config), crypto_config_(crypto_config), delete_sessions_alarm_(new DeleteSessionsAlarm(this)), epoll_server_(epoll_server), helper_(new QuicEpollConnectionHelper(epoll_server_)), supported_versions_(supported_versions), + supported_versions_no_flow_control_(supported_versions), current_packet_(NULL), framer_(supported_versions, /*unused*/ QuicTime::Zero(), true), - framer_visitor_(new QuicFramerVisitor(this)) { + framer_visitor_(new QuicFramerVisitor(this)), + initial_flow_control_window_bytes_(initial_flow_control_window_bytes) { framer_.set_visitor(framer_visitor_.get()); } @@ -163,6 +167,17 @@ void QuicDispatcher::Initialize(int fd) { time_wait_list_manager_.reset( new QuicTimeWaitListManager(writer_.get(), this, epoll_server(), supported_versions())); + + // Remove all versions > QUIC_VERSION_16 from the + // supported_versions_no_flow_control_ vector. + QuicVersionVector::iterator it = + find(supported_versions_no_flow_control_.begin(), + supported_versions_no_flow_control_.end(), QUIC_VERSION_17); + if (it != supported_versions_no_flow_control_.end()) { + supported_versions_no_flow_control_.erase( + supported_versions_no_flow_control_.begin(), it + 1); + } + CHECK(!supported_versions_no_flow_control_.empty()); } void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address, @@ -337,7 +352,10 @@ QuicSession* QuicDispatcher::CreateQuicSession( const IPEndPoint& client_address) { QuicServerSession* session = new QuicServerSession( config_, - CreateQuicConnection(connection_id, server_address, client_address), + CreateQuicConnection(connection_id, + server_address, + client_address, + initial_flow_control_window_bytes_), this); session->InitializeSession(crypto_config_); return session; @@ -346,9 +364,22 @@ QuicSession* QuicDispatcher::CreateQuicSession( QuicConnection* QuicDispatcher::CreateQuicConnection( QuicConnectionId connection_id, const IPEndPoint& server_address, - const IPEndPoint& client_address) { - return new QuicConnection(connection_id, client_address, helper_.get(), - writer_.get(), true, supported_versions_); + 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) { + 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"; + return new QuicConnection(connection_id, client_address, helper_.get(), + writer_.get(), true, + supported_versions_no_flow_control_, + initial_flow_control_window_bytes_); + } } void QuicDispatcher::set_writer(QuicPacketWriter* writer) { diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h index 1fe9af2aaab0..f2ae0c7c4791 100644 --- a/net/tools/quic/quic_dispatcher.h +++ b/net/tools/quic/quic_dispatcher.h @@ -63,7 +63,8 @@ class QuicDispatcher : public QuicServerSessionVisitor { QuicDispatcher(const QuicConfig& config, const QuicCryptoServerConfig& crypto_config, const QuicVersionVector& supported_versions, - EpollServer* epoll_server); + EpollServer* epoll_server, + uint32 initial_flow_control_window_bytes); virtual ~QuicDispatcher(); @@ -117,7 +118,8 @@ class QuicDispatcher : public QuicServerSessionVisitor { QuicConnection* CreateQuicConnection(QuicConnectionId connection_id, const IPEndPoint& server_address, - const IPEndPoint& client_address); + const IPEndPoint& client_address, + uint32 initial_flow_control_window); // Replaces the packet writer with |writer|. Takes ownership of |writer|. void set_writer(QuicPacketWriter* writer); @@ -139,6 +141,9 @@ class QuicDispatcher : public QuicServerSessionVisitor { const IPEndPoint& current_server_address() { return current_server_address_; } + const IPEndPoint& current_client_address() { + return current_client_address_; + } const QuicEncryptedPacket& current_packet() { return *current_packet_; } @@ -195,6 +200,13 @@ class QuicDispatcher : public QuicServerSessionVisitor { // skipped as necessary). const QuicVersionVector supported_versions_; + // Versions which do not support flow control (introduced in QUIC_VERSION_17). + // This is used to construct new QuicConnections when flow control is disabled + // via flag. + // TODO(rjshade): Remove this when + // FLAGS_enable_quic_stream_flow_control is removed. + QuicVersionVector supported_versions_no_flow_control_; + // Information about the packet currently being handled. IPEndPoint current_client_address_; IPEndPoint current_server_address_; @@ -203,6 +215,10 @@ class QuicDispatcher : public QuicServerSessionVisitor { QuicFramer framer_; scoped_ptr framer_visitor_; + // Initial flow control window size to advertize to peer on newly created + // connections. + const uint32 initial_flow_control_window_bytes_; + DISALLOW_COPY_AND_ASSIGN(QuicDispatcher); }; diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc index fa63c2f047f6..0228e08e7f9c 100644 --- a/net/tools/quic/quic_dispatcher_test.cc +++ b/net/tools/quic/quic_dispatcher_test.cc @@ -11,6 +11,7 @@ #include "net/quic/crypto/quic_crypto_server_config.h" #include "net/quic/crypto/quic_random.h" #include "net/quic/quic_crypto_stream.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" #include "net/quic/test_tools/quic_test_utils.h" #include "net/tools/epoll_server/epoll_server.h" @@ -43,7 +44,11 @@ class TestDispatcher : public QuicDispatcher { explicit TestDispatcher(const QuicConfig& config, const QuicCryptoServerConfig& crypto_config, EpollServer* eps) - : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), eps) { + : QuicDispatcher(config, + crypto_config, + QuicSupportedVersions(), + eps, + kInitialFlowControlWindowForTest) { } MOCK_METHOD3(CreateQuicSession, QuicSession*( @@ -51,6 +56,9 @@ class TestDispatcher : public QuicDispatcher { const IPEndPoint& server_address, const IPEndPoint& client_address)); using QuicDispatcher::write_blocked_list; + + using QuicDispatcher::current_server_address; + using QuicDispatcher::current_client_address; }; // A Connection class which unregisters the session from the dispatcher @@ -74,7 +82,7 @@ class MockServerConnection : public MockConnection { QuicSession* CreateSession(QuicDispatcher* dispatcher, QuicConnectionId connection_id, - const IPEndPoint& addr, + const IPEndPoint& client_address, MockSession** session) { MockServerConnection* connection = new MockServerConnection(connection_id, dispatcher); @@ -83,7 +91,7 @@ QuicSession* CreateSession(QuicDispatcher* dispatcher, WithoutArgs(Invoke( connection, &MockServerConnection::UnregisterOnConnectionClosed))); EXPECT_CALL(*reinterpret_cast((*session)->connection()), - ProcessUdpPacket(_, addr, _)); + ProcessUdpPacket(_, client_address, _)); return *session; } @@ -109,14 +117,14 @@ class QuicDispatcherTest : public ::testing::Test { return reinterpret_cast(session2_->connection()); } - void ProcessPacket(IPEndPoint addr, + void ProcessPacket(IPEndPoint client_address, QuicConnectionId connection_id, bool has_version_flag, const string& data) { scoped_ptr packet(ConstructEncryptedPacket( connection_id, has_version_flag, false, 1, data)); data_ = string(packet->data(), packet->length()); - dispatcher_.ProcessPacket(IPEndPoint(), addr, *packet.get()); + dispatcher_.ProcessPacket(server_address_, client_address, *packet.get()); } void ValidatePacket(const QuicEncryptedPacket& packet) { @@ -127,6 +135,7 @@ class QuicDispatcherTest : public ::testing::Test { EpollServer eps_; QuicConfig config_; QuicCryptoServerConfig crypto_config_; + IPEndPoint server_address_; TestDispatcher dispatcher_; MockSession* session1_; MockSession* session2_; @@ -134,33 +143,39 @@ class QuicDispatcherTest : public ::testing::Test { }; TEST_F(QuicDispatcherTest, ProcessPackets) { - IPEndPoint addr(net::test::Loopback4(), 1); + IPEndPoint client_address(net::test::Loopback4(), 1); + IPAddressNumber any4; + CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4)); + server_address_ = IPEndPoint(any4, 5); - EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, addr)) + EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, client_address)) .WillOnce(testing::Return(CreateSession( - &dispatcher_, 1, addr, &session1_))); - ProcessPacket(addr, 1, true, "foo"); + &dispatcher_, 1, client_address, &session1_))); + ProcessPacket(client_address, 1, true, "foo"); + EXPECT_EQ(client_address, dispatcher_.current_client_address()); + EXPECT_EQ(server_address_, dispatcher_.current_server_address()); + - EXPECT_CALL(dispatcher_, CreateQuicSession(2, _, addr)) + EXPECT_CALL(dispatcher_, CreateQuicSession(2, _, client_address)) .WillOnce(testing::Return(CreateSession( - &dispatcher_, 2, addr, &session2_))); - ProcessPacket(addr, 2, true, "bar"); + &dispatcher_, 2, client_address, &session2_))); + ProcessPacket(client_address, 2, true, "bar"); EXPECT_CALL(*reinterpret_cast(session1_->connection()), ProcessUdpPacket(_, _, _)).Times(1). WillOnce(testing::WithArgs<2>(Invoke( this, &QuicDispatcherTest::ValidatePacket))); - ProcessPacket(addr, 1, false, "eep"); + ProcessPacket(client_address, 1, false, "eep"); } TEST_F(QuicDispatcherTest, Shutdown) { - IPEndPoint addr(net::test::Loopback4(), 1); + IPEndPoint client_address(net::test::Loopback4(), 1); - EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr)) + EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address)) .WillOnce(testing::Return(CreateSession( - &dispatcher_, 1, addr, &session1_))); + &dispatcher_, 1, client_address, &session1_))); - ProcessPacket(addr, 1, true, "foo"); + ProcessPacket(client_address, 1, true, "foo"); EXPECT_CALL(*reinterpret_cast(session1_->connection()), SendConnectionClose(QUIC_PEER_GOING_AWAY)); @@ -190,12 +205,12 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) { QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_, time_wait_list_manager); // Create a new session. - IPEndPoint addr(net::test::Loopback4(), 1); + IPEndPoint client_address(net::test::Loopback4(), 1); QuicConnectionId connection_id = 1; - EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, _, addr)) + EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, _, client_address)) .WillOnce(testing::Return(CreateSession( - &dispatcher_, connection_id, addr, &session1_))); - ProcessPacket(addr, connection_id, true, "foo"); + &dispatcher_, connection_id, client_address, &session1_))); + ProcessPacket(client_address, connection_id, true, "foo"); // Close the connection by sending public reset packet. QuicPublicResetPacket packet; @@ -215,14 +230,14 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) { .WillOnce(Invoke( reinterpret_cast(session1_->connection()), &MockConnection::ReallyProcessUdpPacket)); - dispatcher_.ProcessPacket(IPEndPoint(), addr, *encrypted); + dispatcher_.ProcessPacket(IPEndPoint(), client_address, *encrypted); EXPECT_TRUE(time_wait_list_manager->IsConnectionIdInTimeWait(connection_id)); // Dispatcher forwards subsequent packets for this connection_id to the time // wait list manager. EXPECT_CALL(*time_wait_list_manager, ProcessPacket(_, _, connection_id, _)).Times(1); - ProcessPacket(addr, connection_id, true, "foo"); + ProcessPacket(client_address, connection_id, true, "foo"); } TEST_F(QuicDispatcherTest, StrayPacketToTimeWaitListManager) { @@ -233,7 +248,7 @@ TEST_F(QuicDispatcherTest, StrayPacketToTimeWaitListManager) { QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_, time_wait_list_manager); - IPEndPoint addr(net::test::Loopback4(), 1); + IPEndPoint client_address(net::test::Loopback4(), 1); QuicConnectionId connection_id = 1; // Dispatcher forwards all packets for this connection_id to the time wait // list manager. @@ -241,7 +256,50 @@ TEST_F(QuicDispatcherTest, StrayPacketToTimeWaitListManager) { EXPECT_CALL(*time_wait_list_manager, ProcessPacket(_, _, connection_id, _)).Times(1); string data = "foo"; - ProcessPacket(addr, connection_id, false, "foo"); + ProcessPacket(client_address, connection_id, false, "foo"); +} + +TEST(QuicDispatcherFlowControlTest, NoNewVersion17ConnectionsIfFlagDisabled) { + // If FLAGS_enable_quic_stream_flow_control is disabled + // then the dispatcher should stop creating connections that support + // QUIC_VERSION_17 (existing connections will stay alive). + // TODO(rjshade): Remove once + // FLAGS_enable_quic_stream_flow_control is removed. + + EpollServer eps; + QuicConfig config; + QuicCryptoServerConfig server_config(QuicCryptoServerConfig::TESTING, + QuicRandom::GetInstance()); + IPEndPoint client(net::test::Loopback4(), 1); + IPEndPoint server(net::test::Loopback4(), 1); + QuicConnectionId kCID = 1234; + + QuicVersion kTestQuicVersions[] = {QUIC_VERSION_17, + QUIC_VERSION_16, + QUIC_VERSION_15}; + QuicVersionVector kTestVersions; + for (size_t i = 0; i < arraysize(kTestQuicVersions); ++i) { + kTestVersions.push_back(kTestQuicVersions[i]); + } + + QuicDispatcher dispatcher(config, server_config, kTestVersions, &eps, + kInitialFlowControlWindowForTest); + dispatcher.Initialize(0); + + // When flag is enabled, new connections should support QUIC_VERSION_17. + FLAGS_enable_quic_stream_flow_control = true; + scoped_ptr connection_1( + QuicDispatcherPeer::CreateQuicConnection( + &dispatcher, kCID, client, server, kInitialFlowControlWindowForTest)); + EXPECT_EQ(QUIC_VERSION_17, connection_1->version()); + + + // When flag is disabled, new connections should not support QUIC_VERSION_17. + FLAGS_enable_quic_stream_flow_control = false; + scoped_ptr connection_2( + QuicDispatcherPeer::CreateQuicConnection( + &dispatcher, kCID, client, server, kInitialFlowControlWindowForTest)); + EXPECT_EQ(QUIC_VERSION_16, connection_2->version()); } class BlockingWriter : public QuicPacketWriterWrapper { @@ -254,13 +312,13 @@ class BlockingWriter : public QuicPacketWriterWrapper { virtual WriteResult WritePacket( const char* buffer, size_t buf_len, - const IPAddressNumber& self_address, - const IPEndPoint& peer_address) OVERRIDE { + const IPAddressNumber& self_client_address, + const IPEndPoint& peer_client_address) OVERRIDE { if (write_blocked_) { return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN); } else { return QuicPacketWriterWrapper::WritePacket( - buffer, buf_len, self_address, peer_address); + buffer, buf_len, self_client_address, peer_client_address); } } @@ -273,17 +331,17 @@ class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTest { writer_ = new BlockingWriter; QuicDispatcherPeer::UseWriter(&dispatcher_, writer_); - IPEndPoint addr(net::test::Loopback4(), 1); + IPEndPoint client_address(net::test::Loopback4(), 1); - EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr)) + EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address)) .WillOnce(testing::Return(CreateSession( - &dispatcher_, 1, addr, &session1_))); - ProcessPacket(addr, 1, true, "foo"); + &dispatcher_, 1, client_address, &session1_))); + ProcessPacket(client_address, 1, true, "foo"); - EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr)) + EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address)) .WillOnce(testing::Return(CreateSession( - &dispatcher_, 2, addr, &session2_))); - ProcessPacket(addr, 2, true, "bar"); + &dispatcher_, 2, client_address, &session2_))); + ProcessPacket(client_address, 2, true, "bar"); blocked_list_ = dispatcher_.write_blocked_list(); } diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc index c3660b257f29..b59400911756 100644 --- a/net/tools/quic/quic_server.cc +++ b/net/tools/quic/quic_server.cc @@ -29,6 +29,7 @@ const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET; static const char kSourceAddressTokenSecret[] = "secret"; +const uint32 kServerInitialFlowControlWindow = 100 * net::kMaxPacketSize; namespace net { namespace tools { @@ -40,7 +41,9 @@ QuicServer::QuicServer() overflow_supported_(false), use_recvmmsg_(false), crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()), - supported_versions_(QuicSupportedVersions()) { + supported_versions_(QuicSupportedVersions()), + server_initial_flow_control_receive_window_( + kServerInitialFlowControlWindow) { // Use hardcoded crypto parameters for now. config_.SetDefaults(); config_.set_initial_round_trip_time_us(kMaxInitialRoundTripTimeUs, 0); @@ -50,7 +53,8 @@ QuicServer::QuicServer() } QuicServer::QuicServer(const QuicConfig& config, - const QuicVersionVector& supported_versions) + const QuicVersionVector& supported_versions, + uint32 server_initial_flow_control_receive_window) : port_(0), fd_(-1), packets_dropped_(0), @@ -58,7 +62,9 @@ QuicServer::QuicServer(const QuicConfig& config, use_recvmmsg_(false), config_(config), crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()), - supported_versions_(supported_versions) { + supported_versions_(supported_versions), + server_initial_flow_control_receive_window_( + server_initial_flow_control_receive_window) { Initialize(); } @@ -148,7 +154,11 @@ bool QuicServer::Listen(const IPEndPoint& address) { epoll_server_.RegisterFD(fd_, this, kEpollFlags); dispatcher_.reset(new QuicDispatcher( - config_, crypto_config_, supported_versions_, &epoll_server_)); + config_, + crypto_config_, + supported_versions_, + &epoll_server_, + server_initial_flow_control_receive_window_)); dispatcher_->Initialize(fd_); return true; diff --git a/net/tools/quic/quic_server.h b/net/tools/quic/quic_server.h index 76204d4f8092..119fa78ee4e0 100644 --- a/net/tools/quic/quic_server.h +++ b/net/tools/quic/quic_server.h @@ -31,7 +31,8 @@ class QuicServer : public EpollCallbackInterface { public: QuicServer(); QuicServer(const QuicConfig& config, - const QuicVersionVector& supported_versions); + const QuicVersionVector& supported_versions, + uint32 server_initial_flow_control_receive_window); virtual ~QuicServer(); @@ -121,6 +122,10 @@ class QuicServer : public EpollCallbackInterface { // skipped as necessary). QuicVersionVector supported_versions_; + // Size of flow control receive window to advertise to clients on new + // connections. + uint32 server_initial_flow_control_receive_window_; + DISALLOW_COPY_AND_ASSIGN(QuicServer); }; diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc index 5dd10d009c45..004ac8bf6b3a 100644 --- a/net/tools/quic/quic_spdy_client_stream_test.cc +++ b/net/tools/quic/quic_spdy_client_stream_test.cc @@ -40,6 +40,11 @@ class QuicSpdyClientStreamTest : public TestWithParam { headers_.ReplaceOrAppendHeader("content-length", "11"); headers_string_ = SpdyUtils::SerializeResponseHeaders(headers_); + + // New streams rely on having the peer's flow control receive window + // negotiated in the config. + session_.config()->set_peer_initial_flow_control_window_bytes( + kInitialFlowControlWindowForTest); stream_.reset(new QuicSpdyClientStream(3, &session_)); } diff --git a/net/tools/quic/quic_spdy_server_stream_test.cc b/net/tools/quic/quic_spdy_server_stream_test.cc index 7fb9375e3ae9..9f176563eeeb 100644 --- a/net/tools/quic/quic_spdy_server_stream_test.cc +++ b/net/tools/quic/quic_spdy_server_stream_test.cc @@ -81,6 +81,12 @@ class QuicSpdyServerStreamTest : public ::testing::TestWithParam { request_headers.ReplaceOrAppendHeader("content-length", "11"); headers_string_ = SpdyUtils::SerializeRequestHeaders(request_headers); + + // New streams rely on having the peer's flow control receive window + // negotiated in the config. + const uint32 kInitialWindow = 10 * kMaxPacketSize; + session_.config()->set_peer_initial_flow_control_window_bytes( + kInitialWindow); stream_.reset(new QuicSpdyServerStreamPeer(3, &session_)); } diff --git a/net/tools/quic/test_tools/mock_quic_dispatcher.cc b/net/tools/quic/test_tools/mock_quic_dispatcher.cc index 724890981ddd..21195bc20b35 100644 --- a/net/tools/quic/test_tools/mock_quic_dispatcher.cc +++ b/net/tools/quic/test_tools/mock_quic_dispatcher.cc @@ -4,6 +4,10 @@ #include "net/tools/quic/test_tools/mock_quic_dispatcher.h" +#include "net/quic/test_tools/quic_test_utils.h" + +using net::test::kInitialFlowControlWindowForTest; + namespace net { namespace tools { namespace test { @@ -12,7 +16,11 @@ MockQuicDispatcher::MockQuicDispatcher( const QuicConfig& config, const QuicCryptoServerConfig& crypto_config, EpollServer* eps) - : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), eps) {} + : QuicDispatcher(config, + crypto_config, + QuicSupportedVersions(), + eps, + kInitialFlowControlWindowForTest) {} MockQuicDispatcher::~MockQuicDispatcher() {} diff --git a/net/tools/quic/test_tools/quic_dispatcher_peer.cc b/net/tools/quic/test_tools/quic_dispatcher_peer.cc index 3adcedfd2ee2..56411843c3bb 100644 --- a/net/tools/quic/test_tools/quic_dispatcher_peer.cc +++ b/net/tools/quic/test_tools/quic_dispatcher_peer.cc @@ -37,6 +37,19 @@ QuicEpollConnectionHelper* QuicDispatcherPeer::GetHelper( return dispatcher->helper_.get(); } +// static +QuicConnection* QuicDispatcherPeer::CreateQuicConnection( + QuicDispatcher* dispatcher, + QuicConnectionId connection_id, + const IPEndPoint& server, + const IPEndPoint& client, + uint32 initial_flow_control_window_bytes) { + return dispatcher->CreateQuicConnection(connection_id, + server, + client, + initial_flow_control_window_bytes); +} + } // namespace test } // namespace tools } // namespace net diff --git a/net/tools/quic/test_tools/quic_dispatcher_peer.h b/net/tools/quic/test_tools/quic_dispatcher_peer.h index a6b72e0189d2..fb93d6ef12a8 100644 --- a/net/tools/quic/test_tools/quic_dispatcher_peer.h +++ b/net/tools/quic/test_tools/quic_dispatcher_peer.h @@ -7,6 +7,8 @@ #include "net/tools/quic/quic_dispatcher.h" +#include "net/base/ip_endpoint.h" + namespace net { namespace tools { @@ -28,6 +30,13 @@ class QuicDispatcherPeer { static QuicPacketWriterWrapper* GetWriter(QuicDispatcher* dispatcher); static QuicEpollConnectionHelper* GetHelper(QuicDispatcher* dispatcher); + + static QuicConnection* CreateQuicConnection( + QuicDispatcher* dispatcher, + QuicConnectionId connection_id, + const IPEndPoint& server, + const IPEndPoint& client, + uint32 initial_flow_control_window_bytes); }; } // namespace test diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc index 741320271746..d9fa2194317d 100644 --- a/net/tools/quic/test_tools/quic_test_client.cc +++ b/net/tools/quic/test_tools/quic_test_client.cc @@ -12,6 +12,7 @@ #include "net/quic/crypto/proof_verifier.h" #include "net/quic/quic_session_key.h" #include "net/quic/test_tools/quic_connection_peer.h" +#include "net/quic/test_tools/quic_test_utils.h" #include "net/tools/balsa/balsa_headers.h" #include "net/tools/quic/quic_epoll_connection_helper.h" #include "net/tools/quic/quic_packet_writer_wrapper.h" @@ -21,6 +22,7 @@ #include "url/gurl.h" using base::StringPiece; +using net::test::kInitialFlowControlWindowForTest; using net::test::QuicConnectionPeer; using std::string; using std::vector; @@ -100,16 +102,26 @@ class MockableQuicClient : public QuicClient { public: MockableQuicClient(IPEndPoint server_address, const QuicSessionKey& server_key, - const QuicVersionVector& supported_versions) - : QuicClient(server_address, server_key, supported_versions, false), + const QuicVersionVector& supported_versions, + uint32 initial_flow_control_window) + : QuicClient(server_address, + server_key, + supported_versions, + false, + initial_flow_control_window), override_connection_id_(0), test_writer_(NULL) {} MockableQuicClient(IPEndPoint server_address, const QuicSessionKey& server_key, const QuicConfig& config, - const QuicVersionVector& supported_versions) - : QuicClient(server_address, server_key, config, supported_versions), + const QuicVersionVector& supported_versions, + uint32 initial_flow_control_window) + : QuicClient(server_address, + server_key, + config, + supported_versions, + initial_flow_control_window), override_connection_id_(0), test_writer_(NULL) {} @@ -134,7 +146,10 @@ class MockableQuicClient : public QuicClient { } // Takes ownership of writer. - void UseWriter(QuicPacketWriterWrapper* writer) { test_writer_ = writer; } + void UseWriter(QuicPacketWriterWrapper* writer) { + CHECK(test_writer_ == NULL); + test_writer_ = writer; + } void UseConnectionId(QuicConnectionId connection_id) { override_connection_id_ = connection_id; @@ -148,7 +163,10 @@ class MockableQuicClient : public QuicClient { QuicTestClient::QuicTestClient(IPEndPoint address, const QuicSessionKey& server_key, const QuicVersionVector& supported_versions) - : client_(new MockableQuicClient(address, server_key, supported_versions)) { + : client_(new MockableQuicClient(address, + server_key, + supported_versions, + kInitialFlowControlWindowForTest)) { Initialize(address, server_key, true); } @@ -156,17 +174,26 @@ QuicTestClient::QuicTestClient(IPEndPoint address, const QuicSessionKey& server_key, bool secure, const QuicVersionVector& supported_versions) - : client_(new MockableQuicClient(address, server_key, supported_versions)) { + : client_(new MockableQuicClient(address, + server_key, + supported_versions, + kInitialFlowControlWindowForTest)) { Initialize(address, server_key, secure); } -QuicTestClient::QuicTestClient(IPEndPoint address, - const QuicSessionKey& server_key, - bool secure, - const QuicConfig& config, - const QuicVersionVector& supported_versions) - : client_(new MockableQuicClient(address, server_key, config, - supported_versions)) { +QuicTestClient::QuicTestClient( + IPEndPoint address, + const QuicSessionKey& server_key, + bool secure, + const QuicConfig& config, + const QuicVersionVector& supported_versions, + uint32 client_initial_flow_control_receive_window) + : client_( + new MockableQuicClient(address, + server_key, + config, + supported_versions, + client_initial_flow_control_receive_window)) { Initialize(address, server_key, secure); } diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h index 7a0ab82d537b..114c520f3fbd 100644 --- a/net/tools/quic/test_tools/quic_test_client.h +++ b/net/tools/quic/test_tools/quic_test_client.h @@ -42,7 +42,8 @@ class QuicTestClient : public QuicDataStream::Visitor { const QuicSessionKey& server_key, bool secure, const QuicConfig& config, - const QuicVersionVector& supported_versions); + const QuicVersionVector& supported_versions, + uint32 client_initial_flow_control_receive_window); virtual ~QuicTestClient(); diff --git a/net/tools/quic/test_tools/quic_test_utils.cc b/net/tools/quic/test_tools/quic_test_utils.cc index 016e834d7c3f..78e67cabfe94 100644 --- a/net/tools/quic/test_tools/quic_test_utils.cc +++ b/net/tools/quic/test_tools/quic_test_utils.cc @@ -11,6 +11,7 @@ #include "net/tools/quic/quic_epoll_connection_helper.h" using base::StringPiece; +using net::test::kInitialFlowControlWindowForTest; using net::test::MockHelper; namespace net { @@ -22,7 +23,8 @@ MockConnection::MockConnection(bool is_server) IPEndPoint(net::test::Loopback4(), kTestPort), new testing::NiceMock(), new testing::NiceMock(), - is_server, QuicSupportedVersions()), + is_server, QuicSupportedVersions(), + kInitialFlowControlWindowForTest), writer_(net::test::QuicConnectionPeer::GetWriter(this)), helper_(helper()) { } @@ -32,7 +34,8 @@ MockConnection::MockConnection(IPEndPoint address, : QuicConnection(kTestConnectionId, address, new testing::NiceMock(), new testing::NiceMock(), - is_server, QuicSupportedVersions()), + is_server, QuicSupportedVersions(), + kInitialFlowControlWindowForTest), writer_(net::test::QuicConnectionPeer::GetWriter(this)), helper_(helper()) { } @@ -43,7 +46,8 @@ MockConnection::MockConnection(QuicConnectionId connection_id, IPEndPoint(net::test::Loopback4(), kTestPort), new testing::NiceMock(), new testing::NiceMock(), - is_server, QuicSupportedVersions()), + is_server, QuicSupportedVersions(), + kInitialFlowControlWindowForTest), writer_(net::test::QuicConnectionPeer::GetWriter(this)), helper_(helper()) { } @@ -54,7 +58,8 @@ MockConnection::MockConnection(bool is_server, IPEndPoint(net::test::Loopback4(), kTestPort), new testing::NiceMock(), new testing::NiceMock(), - is_server, supported_versions), + is_server, QuicSupportedVersions(), + kInitialFlowControlWindowForTest), writer_(net::test::QuicConnectionPeer::GetWriter(this)), helper_(helper()) { } diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h index 41cccd1a248b..c35bc7c4adfc 100644 --- a/net/tools/quic/test_tools/quic_test_utils.h +++ b/net/tools/quic/test_tools/quic_test_utils.h @@ -27,6 +27,7 @@ namespace test { static const QuicConnectionId kTestConnectionId = 42; static const int kTestPort = 123; +static const uint32 kInitialFlowControlWindowForTest = 32 * 1024; // 32 KB // Simple random number generator used to compute random numbers suitable // for pseudo-randomly dropping packets in tests. It works by computing diff --git a/net/tools/quic/test_tools/server_thread.cc b/net/tools/quic/test_tools/server_thread.cc index e2b6506d17aa..839e137fb7a1 100644 --- a/net/tools/quic/test_tools/server_thread.cc +++ b/net/tools/quic/test_tools/server_thread.cc @@ -13,14 +13,17 @@ namespace test { ServerThread::ServerThread(IPEndPoint address, const QuicConfig& config, const QuicVersionVector& supported_versions, - bool strike_register_no_startup_period) + bool strike_register_no_startup_period, + uint32 server_initial_flow_control_receive_window) : SimpleThread("server_thread"), confirmed_(true, false), pause_(true, false), paused_(true, false), resume_(true, false), quit_(true, false), - server_(config, supported_versions), + server_(config, + supported_versions, + server_initial_flow_control_receive_window), address_(address), port_(0), initialized_(false) { diff --git a/net/tools/quic/test_tools/server_thread.h b/net/tools/quic/test_tools/server_thread.h index c2c4c61cf423..94737842f89c 100644 --- a/net/tools/quic/test_tools/server_thread.h +++ b/net/tools/quic/test_tools/server_thread.h @@ -20,7 +20,8 @@ class ServerThread : public base::SimpleThread { ServerThread(IPEndPoint address, const QuicConfig& config, const QuicVersionVector& supported_versions, - bool strike_register_no_startup_period); + bool strike_register_no_startup_period, + uint32 server_initial_flow_control_receive_window); virtual ~ServerThread(); -- 2.11.4.GIT