diff options
51 files changed, 636 insertions, 517 deletions
diff --git a/net/net.gypi b/net/net.gypi index 8577ac9..344f8a0 100644 --- a/net/net.gypi +++ b/net/net.gypi @@ -732,8 +732,6 @@ 'quic/congestion_control/leaky_bucket.h', 'quic/congestion_control/loss_detection_interface.cc', 'quic/congestion_control/loss_detection_interface.h', - 'quic/congestion_control/paced_sender.cc', - 'quic/congestion_control/paced_sender.h', 'quic/congestion_control/pacing_sender.cc', 'quic/congestion_control/pacing_sender.h', 'quic/congestion_control/receive_algorithm_interface.cc', @@ -914,6 +912,8 @@ 'quic/quic_stream_sequencer.h', 'quic/quic_time.cc', 'quic/quic_time.h', + 'quic/quic_types.cc', + 'quic/quic_types.h', 'quic/quic_unacked_packet_map.cc', 'quic/quic_unacked_packet_map.h', 'quic/quic_utils.cc', @@ -1401,7 +1401,6 @@ 'quic/congestion_control/fix_rate_test.cc', 'quic/congestion_control/hybrid_slow_start_test.cc', 'quic/congestion_control/leaky_bucket_test.cc', - 'quic/congestion_control/paced_sender_test.cc', 'quic/congestion_control/pacing_sender_test.cc', 'quic/congestion_control/rtt_stats_test.cc', 'quic/congestion_control/tcp_cubic_sender_test.cc', diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc index 8027205..c346a63 100644 --- a/net/quic/congestion_control/fix_rate_sender.cc +++ b/net/quic/congestion_control/fix_rate_sender.cc @@ -26,7 +26,6 @@ FixRateSender::FixRateSender(const RttStats* rtt_stats) bitrate_(QuicBandwidth::FromBytesPerSecond(kInitialBitrate)), max_segment_size_(kDefaultMaxPacketSize), fix_rate_leaky_bucket_(bitrate_), - paced_sender_(bitrate_, max_segment_size_), latest_rtt_(QuicTime::Delta::Zero()) { DVLOG(1) << "FixRateSender"; } @@ -45,7 +44,6 @@ void FixRateSender::OnIncomingQuicCongestionFeedbackFrame( if (feedback.type == kFixRate) { bitrate_ = feedback.fix_rate.bitrate; fix_rate_leaky_bucket_.SetDrainingRate(feedback_receive_time, bitrate_); - paced_sender_.UpdateBandwidthEstimate(feedback_receive_time, bitrate_); } // Silently ignore invalid messages in release mode. } @@ -63,7 +61,6 @@ bool FixRateSender::OnPacketSent( QuicByteCount bytes, HasRetransmittableData /*has_retransmittable_data*/) { fix_rate_leaky_bucket_.Add(sent_time, bytes); - paced_sender_.OnPacketSent(sent_time, bytes); return true; } @@ -72,24 +69,12 @@ void FixRateSender::OnRetransmissionTimeout(bool packets_retransmitted) { } QuicTime::Delta FixRateSender::TimeUntilSend( QuicTime now, - QuicByteCount bytes_in_flight, - HasRetransmittableData /*has_retransmittable_data*/) { - if (CongestionWindow() > fix_rate_leaky_bucket_.BytesPending(now)) { - if (CongestionWindow() <= bytes_in_flight) { - // We need an ack before we send more. - return QuicTime::Delta::Infinite(); - } - return paced_sender_.TimeUntilSend(now, QuicTime::Delta::Zero()); - } - QuicTime::Delta time_remaining = fix_rate_leaky_bucket_.TimeRemaining(now); - if (time_remaining.IsZero()) { - // We need an ack before we send more. - return QuicTime::Delta::Infinite(); - } - return paced_sender_.TimeUntilSend(now, time_remaining); + QuicByteCount /*bytes_in_flight*/, + HasRetransmittableData /*has_retransmittable_data*/) const { + return fix_rate_leaky_bucket_.TimeRemaining(now); } -QuicByteCount FixRateSender::CongestionWindow() { +QuicByteCount FixRateSender::CongestionWindow() const { QuicByteCount window_size_bytes = bitrate_.ToBytesPerPeriod( QuicTime::Delta::FromMicroseconds(kWindowSizeUs)); // Make sure window size is not less than a packet. diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h index 6f85090..3cb07ff 100644 --- a/net/quic/congestion_control/fix_rate_sender.h +++ b/net/quic/congestion_control/fix_rate_sender.h @@ -14,7 +14,6 @@ #include "net/quic/quic_connection_stats.h" #include "net/quic/quic_time.h" #include "net/quic/congestion_control/leaky_bucket.h" -#include "net/quic/congestion_control/paced_sender.h" #include "net/quic/congestion_control/send_algorithm_interface.h" namespace net { @@ -45,20 +44,19 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface { virtual QuicTime::Delta TimeUntilSend( QuicTime now, QuicByteCount bytes_in_flight, - HasRetransmittableData has_retransmittable_data) OVERRIDE; + HasRetransmittableData has_retransmittable_data) const OVERRIDE; virtual QuicBandwidth BandwidthEstimate() const OVERRIDE; virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE; virtual QuicByteCount GetCongestionWindow() const OVERRIDE; // End implementation of SendAlgorithmInterface. private: - QuicByteCount CongestionWindow(); + QuicByteCount CongestionWindow() const; const RttStats* rtt_stats_; QuicBandwidth bitrate_; QuicByteCount max_segment_size_; LeakyBucket fix_rate_leaky_bucket_; - PacedSender paced_sender_; QuicTime::Delta latest_rtt_; DISALLOW_COPY_AND_ASSIGN(FixRateSender); diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc index e696823..c82bb60 100644 --- a/net/quic/congestion_control/fix_rate_test.cc +++ b/net/quic/congestion_control/fix_rate_test.cc @@ -68,59 +68,33 @@ TEST_F(FixRateTest, SenderAPI) { sender_->OnPacketSent(clock_.Now(), kUnused, 1, kDefaultMaxPacketSize, HAS_RETRANSMITTABLE_DATA); + EXPECT_FALSE(sender_->TimeUntilSend(clock_.Now(), + kDefaultMaxPacketSize, + HAS_RETRANSMITTABLE_DATA).IsZero()); + clock_.AdvanceTime(sender_->TimeUntilSend(clock_.Now(), + kDefaultMaxPacketSize, + HAS_RETRANSMITTABLE_DATA)); EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), kDefaultMaxPacketSize, HAS_RETRANSMITTABLE_DATA).IsZero()); sender_->OnPacketSent(clock_.Now(), kUnused, 2, kDefaultMaxPacketSize, HAS_RETRANSMITTABLE_DATA); - sender_->OnPacketSent(clock_.Now(), kUnused, 3, 600, - HAS_RETRANSMITTABLE_DATA); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), - sender_->TimeUntilSend(clock_.Now(), - kDefaultMaxPacketSize * 2 + 600, - HAS_RETRANSMITTABLE_DATA)); - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2)); - EXPECT_EQ(QuicTime::Delta::Infinite(), - sender_->TimeUntilSend(clock_.Now(), - kDefaultMaxPacketSize * 2 + 600, - HAS_RETRANSMITTABLE_DATA)); - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8)); + EXPECT_FALSE(sender_->TimeUntilSend(clock_.Now(), + kDefaultMaxPacketSize, + HAS_RETRANSMITTABLE_DATA).IsZero()); + // Advance the time twice as much and expect only one packet to be sent. + clock_.AdvanceTime(sender_->TimeUntilSend( + clock_.Now(), + kDefaultMaxPacketSize, + HAS_RETRANSMITTABLE_DATA).Multiply(2)); EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - 0, + kDefaultMaxPacketSize, HAS_RETRANSMITTABLE_DATA).IsZero()); -} - -TEST_F(FixRateTest, FixRatePacing) { - const QuicByteCount packet_size = 1200; - const QuicBandwidth bitrate = QuicBandwidth::FromKBytesPerSecond(240); - const int64 num_packets = 200; - QuicCongestionFeedbackFrame feedback; - receiver_->SetBitrate(QuicBandwidth::FromKBytesPerSecond(240)); - ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); - sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now()); - QuicTime acc_advance_time(QuicTime::Zero()); - QuicPacketSequenceNumber sequence_number = 0; - for (int i = 0; i < num_packets; i += 2) { - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - 0, - HAS_RETRANSMITTABLE_DATA).IsZero()); - sender_->OnPacketSent(clock_.Now(), kUnused, sequence_number++, packet_size, - HAS_RETRANSMITTABLE_DATA); - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), - kDefaultMaxPacketSize, - HAS_RETRANSMITTABLE_DATA).IsZero()); - sender_->OnPacketSent(clock_.Now(), kUnused, sequence_number++, packet_size, - HAS_RETRANSMITTABLE_DATA); - QuicTime::Delta advance_time = - sender_->TimeUntilSend(clock_.Now(), - 2 * kDefaultMaxPacketSize, - HAS_RETRANSMITTABLE_DATA); - clock_.AdvanceTime(advance_time); - acc_advance_time = acc_advance_time.Add(advance_time); - } - EXPECT_EQ(num_packets * packet_size * 1000000 / bitrate.ToBytesPerSecond(), - static_cast<uint64>(acc_advance_time.Subtract(start_) - .ToMicroseconds())); + sender_->OnPacketSent(clock_.Now(), kUnused, 3, kDefaultMaxPacketSize, + HAS_RETRANSMITTABLE_DATA); + EXPECT_FALSE(sender_->TimeUntilSend(clock_.Now(), + kDefaultMaxPacketSize, + HAS_RETRANSMITTABLE_DATA).IsZero()); } } // namespace test diff --git a/net/quic/congestion_control/leaky_bucket.cc b/net/quic/congestion_control/leaky_bucket.cc index 06c1f87..f3972f6 100644 --- a/net/quic/congestion_control/leaky_bucket.cc +++ b/net/quic/congestion_control/leaky_bucket.cc @@ -24,11 +24,15 @@ void LeakyBucket::Add(QuicTime now, QuicByteCount bytes) { bytes_ += bytes; } -QuicTime::Delta LeakyBucket::TimeRemaining(QuicTime now) { - Update(now); - return QuicTime::Delta::FromMicroseconds( +QuicTime::Delta LeakyBucket::TimeRemaining(QuicTime now) const { + QuicTime::Delta time_since_last_update = now.Subtract(time_last_updated_); + QuicTime::Delta send_delay = QuicTime::Delta::FromMicroseconds( (bytes_ * base::Time::kMicrosecondsPerSecond) / draining_rate_.ToBytesPerSecond()); + if (send_delay < time_since_last_update) { + return QuicTime::Delta::Zero(); + } + return send_delay.Subtract(time_since_last_update); } QuicByteCount LeakyBucket::BytesPending(QuicTime now) { diff --git a/net/quic/congestion_control/leaky_bucket.h b/net/quic/congestion_control/leaky_bucket.h index 8717620..eb4cdb0 100644 --- a/net/quic/congestion_control/leaky_bucket.h +++ b/net/quic/congestion_control/leaky_bucket.h @@ -29,7 +29,7 @@ class NET_EXPORT_PRIVATE LeakyBucket { void Add(QuicTime now, QuicByteCount bytes); // Time until the buffer is empty. - QuicTime::Delta TimeRemaining(QuicTime now); + QuicTime::Delta TimeRemaining(QuicTime now) const; // Number of bytes in the buffer. QuicByteCount BytesPending(QuicTime now); diff --git a/net/quic/congestion_control/paced_sender.cc b/net/quic/congestion_control/paced_sender.cc deleted file mode 100644 index 87042a5..0000000 --- a/net/quic/congestion_control/paced_sender.cc +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2012 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/congestion_control/paced_sender.h" - -#include <algorithm> - -#include "net/quic/quic_protocol.h" - -using std::max; - -namespace net { - -// To prevent too aggressive pacing we allow the following packet burst size. -const int64 kMinPacketBurstSize = 2; -// Max estimated time between calls to TimeUntilSend and -// AvailableCongestionWindow. -const int64 kMaxSchedulingDelayUs = 2000; - -PacedSender::PacedSender(QuicBandwidth estimate, QuicByteCount max_segment_size) - : leaky_bucket_(estimate), - pace_(estimate), - max_segment_size_(kDefaultMaxPacketSize) { -} - -void PacedSender::UpdateBandwidthEstimate(QuicTime now, - QuicBandwidth estimate) { - leaky_bucket_.SetDrainingRate(now, estimate); - pace_ = estimate; -} - -void PacedSender::OnPacketSent(QuicTime now, QuicByteCount bytes) { - leaky_bucket_.Add(now, bytes); -} - -QuicTime::Delta PacedSender::TimeUntilSend(QuicTime now, - QuicTime::Delta time_until_send) { - if (time_until_send.ToMicroseconds() >= kMaxSchedulingDelayUs) { - return time_until_send; - } - // Pace the data. - QuicByteCount pacing_window = pace_.ToBytesPerPeriod( - QuicTime::Delta::FromMicroseconds(kMaxSchedulingDelayUs)); - QuicByteCount min_window_size = kMinPacketBurstSize * max_segment_size_; - pacing_window = max(pacing_window, min_window_size); - - if (pacing_window > leaky_bucket_.BytesPending(now)) { - // We have not filled our pacing window yet. - return time_until_send; - } - return leaky_bucket_.TimeRemaining(now); -} - -} // namespace net diff --git a/net/quic/congestion_control/paced_sender.h b/net/quic/congestion_control/paced_sender.h deleted file mode 100644 index d600dcb..0000000 --- a/net/quic/congestion_control/paced_sender.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2012 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. -// -// Helper class that limits the congestion window to pace the packets. - -#ifndef NET_QUIC_CONGESTION_CONTROL_PACED_SENDER_H_ -#define NET_QUIC_CONGESTION_CONTROL_PACED_SENDER_H_ - -#include "base/basictypes.h" -#include "net/base/net_export.h" -#include "net/quic/congestion_control/leaky_bucket.h" -#include "net/quic/quic_bandwidth.h" -#include "net/quic/quic_time.h" - -namespace net { - -class NET_EXPORT_PRIVATE PacedSender { - public: - PacedSender(QuicBandwidth bandwidth_estimate, QuicByteCount max_segment_size); - - // The estimated bandidth from the congestion algorithm changed. - void UpdateBandwidthEstimate(QuicTime now, QuicBandwidth bandwidth_estimate); - - // A packet of size bytes was sent. - void OnPacketSent(QuicTime now, QuicByteCount bytes); - - // Return time until we can send based on the pacing. - QuicTime::Delta TimeUntilSend(QuicTime now, QuicTime::Delta time_until_send); - - private: - // Helper object to track the rate data can leave the buffer for pacing. - LeakyBucket leaky_bucket_; - QuicBandwidth pace_; - QuicByteCount max_segment_size_; - - DISALLOW_COPY_AND_ASSIGN(PacedSender); -}; - -} // namespace net - -#endif // NET_QUIC_CONGESTION_CONTROL_PACED_SENDER_H_ diff --git a/net/quic/congestion_control/paced_sender_test.cc b/net/quic/congestion_control/paced_sender_test.cc deleted file mode 100644 index fa42c2c..0000000 --- a/net/quic/congestion_control/paced_sender_test.cc +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "net/quic/congestion_control/paced_sender.h" -#include "net/quic/quic_protocol.h" -#include "net/quic/test_tools/mock_clock.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { -namespace test { - -const int kHundredKBytesPerS = 100; - -class PacedSenderTest : public ::testing::Test { - protected: - PacedSenderTest() - : zero_time_(QuicTime::Delta::Zero()), - paced_sender_(new PacedSender( - QuicBandwidth::FromKBytesPerSecond(kHundredKBytesPerS), - kDefaultMaxPacketSize)) { - } - - const QuicTime::Delta zero_time_; - MockClock clock_; - scoped_ptr<PacedSender> paced_sender_; -}; - -TEST_F(PacedSenderTest, Basic) { - paced_sender_->UpdateBandwidthEstimate(clock_.Now(), - QuicBandwidth::FromKBytesPerSecond(kHundredKBytesPerS * 10)); - EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); - paced_sender_->OnPacketSent(clock_.Now(), kDefaultMaxPacketSize); - EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); - paced_sender_->OnPacketSent(clock_.Now(), kDefaultMaxPacketSize); - EXPECT_EQ(static_cast<int64>(kDefaultMaxPacketSize * 2), - paced_sender_->TimeUntilSend( - clock_.Now(), zero_time_).ToMicroseconds()); - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(24)); - EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); -} - -TEST_F(PacedSenderTest, LowRate) { - paced_sender_->UpdateBandwidthEstimate(clock_.Now(), - QuicBandwidth::FromKBytesPerSecond(kHundredKBytesPerS)); - EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); - paced_sender_->OnPacketSent(clock_.Now(), kDefaultMaxPacketSize); - EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); - paced_sender_->OnPacketSent(clock_.Now(), kDefaultMaxPacketSize); - EXPECT_EQ(static_cast<int64>(kDefaultMaxPacketSize * 20), - paced_sender_->TimeUntilSend( - clock_.Now(), zero_time_).ToMicroseconds()); - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(24)); - EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); -} - -TEST_F(PacedSenderTest, HighRate) { - QuicBandwidth bandwidth_estimate = QuicBandwidth::FromKBytesPerSecond( - kHundredKBytesPerS * 100); - paced_sender_->UpdateBandwidthEstimate(clock_.Now(), bandwidth_estimate); - EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); - for (int i = 0; i < 16; ++i) { - paced_sender_->OnPacketSent(clock_.Now(), kDefaultMaxPacketSize); - EXPECT_TRUE(paced_sender_->TimeUntilSend( - clock_.Now(), zero_time_).IsZero()); - } - paced_sender_->OnPacketSent(clock_.Now(), kDefaultMaxPacketSize); - EXPECT_EQ(2040, paced_sender_->TimeUntilSend( - clock_.Now(), zero_time_).ToMicroseconds()); - clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(20400)); - EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); -} - -} // namespace test -} // namespace net diff --git a/net/quic/congestion_control/pacing_sender.cc b/net/quic/congestion_control/pacing_sender.cc index 96f6c62..97138f7 100644 --- a/net/quic/congestion_control/pacing_sender.cc +++ b/net/quic/congestion_control/pacing_sender.cc @@ -59,19 +59,20 @@ bool PacingSender::OnPacketSent( // invoked, allow the connection to make up for lost time. if (was_last_send_delayed_) { next_packet_send_time_ = next_packet_send_time_.Add(delay); - // As long as we're making up time and not application limited, - // continue to consider the packets delayed. // The send was application limited if it takes longer than the // pacing delay between sent packets. const bool application_limited = last_delayed_packet_sent_time_.IsInitialized() && sent_time > last_delayed_packet_sent_time_.Add(delay); - const bool making_up_for_lost_time = next_packet_send_time_ > sent_time; - if (making_up_for_lost_time || application_limited) { + const bool making_up_for_lost_time = next_packet_send_time_ <= sent_time; + // As long as we're making up time and not application limited, + // continue to consider the packets delayed, allowing the packets to be + // sent immediately. + if (making_up_for_lost_time && !application_limited) { + last_delayed_packet_sent_time_ = sent_time; + } else { was_last_send_delayed_ = false; last_delayed_packet_sent_time_ = QuicTime::Zero(); - } else { - last_delayed_packet_sent_time_ = sent_time; } } else { next_packet_send_time_ = @@ -90,7 +91,7 @@ void PacingSender::OnRetransmissionTimeout(bool packets_retransmitted) { QuicTime::Delta PacingSender::TimeUntilSend( QuicTime now, QuicByteCount bytes_in_flight, - HasRetransmittableData has_retransmittable_data) { + HasRetransmittableData has_retransmittable_data) const { QuicTime::Delta time_until_send = sender_->TimeUntilSend(now, bytes_in_flight, has_retransmittable_data); if (!has_valid_rtt_) { diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h index f7c2622..c741771 100644 --- a/net/quic/congestion_control/pacing_sender.h +++ b/net/quic/congestion_control/pacing_sender.h @@ -47,7 +47,7 @@ class NET_EXPORT_PRIVATE PacingSender : public SendAlgorithmInterface { virtual QuicTime::Delta TimeUntilSend( QuicTime now, QuicByteCount bytes_in_flight, - HasRetransmittableData has_retransmittable_data) OVERRIDE; + HasRetransmittableData has_retransmittable_data) const OVERRIDE; virtual QuicBandwidth BandwidthEstimate() const OVERRIDE; virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE; virtual QuicByteCount GetCongestionWindow() const OVERRIDE; diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h index 12cf8f6..6b1c755 100644 --- a/net/quic/congestion_control/send_algorithm_interface.h +++ b/net/quic/congestion_control/send_algorithm_interface.h @@ -71,7 +71,7 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface { virtual QuicTime::Delta TimeUntilSend( QuicTime now, QuicByteCount bytes_in_flight, - HasRetransmittableData has_retransmittable_data) = 0; + HasRetransmittableData has_retransmittable_data) const = 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 aaec6a4..19f07d4 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.cc +++ b/net/quic/congestion_control/tcp_cubic_sender.cc @@ -170,7 +170,7 @@ bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/, QuicTime::Delta TcpCubicSender::TimeUntilSend( QuicTime /* now */, QuicByteCount bytes_in_flight, - HasRetransmittableData has_retransmittable_data) { + HasRetransmittableData has_retransmittable_data) const { if (has_retransmittable_data == NO_RETRANSMITTABLE_DATA) { // For TCP we can always send an ACK immediately. return QuicTime::Delta::Zero(); @@ -184,7 +184,7 @@ QuicTime::Delta TcpCubicSender::TimeUntilSend( return QuicTime::Delta::Infinite(); } -QuicByteCount TcpCubicSender::SendWindow() { +QuicByteCount TcpCubicSender::SendWindow() const { // What's the current send window in bytes. return min(receive_window_, GetCongestionWindow()); } @@ -294,7 +294,7 @@ void TcpCubicSender::PrrOnPacketAcked(QuicByteCount acked_bytes) { } QuicTime::Delta TcpCubicSender::PrrTimeUntilSend( - QuicByteCount bytes_in_flight) { + QuicByteCount bytes_in_flight) const { DCHECK(InRecovery()); // Return QuicTime::Zero In order to ensure limited transmit always works. if (prr_out_ == 0) { diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h index 12fd997..f9234c9 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.h +++ b/net/quic/congestion_control/tcp_cubic_sender.h @@ -57,7 +57,7 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { virtual QuicTime::Delta TimeUntilSend( QuicTime now, QuicByteCount bytes_in_flight, - HasRetransmittableData has_retransmittable_data) OVERRIDE; + HasRetransmittableData has_retransmittable_data) const OVERRIDE; virtual QuicBandwidth BandwidthEstimate() const OVERRIDE; virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE; virtual QuicByteCount GetCongestionWindow() const OVERRIDE; @@ -73,7 +73,7 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { void OnPacketLost(QuicPacketSequenceNumber largest_loss, QuicByteCount bytes_in_flight); - QuicByteCount SendWindow(); + QuicByteCount SendWindow() const; void MaybeIncreaseCwnd(QuicPacketSequenceNumber acked_sequence_number, QuicByteCount bytes_in_flight); bool IsCwndLimited(QuicByteCount bytes_in_flight) const; @@ -81,7 +81,7 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { // Methods for isolating PRR from the rest of TCP Cubic. void PrrOnPacketLost(QuicByteCount bytes_in_flight); void PrrOnPacketAcked(QuicByteCount acked_bytes); - QuicTime::Delta PrrTimeUntilSend(QuicByteCount bytes_in_flight); + QuicTime::Delta PrrTimeUntilSend(QuicByteCount bytes_in_flight) const; HybridSlowStart hybrid_slow_start_; diff --git a/net/quic/crypto/proof_test.cc b/net/quic/crypto/proof_test.cc index 31b2a60..56e9abc 100644 --- a/net/quic/crypto/proof_test.cc +++ b/net/quic/crypto/proof_test.cc @@ -70,22 +70,22 @@ void RunVerification(ProofVerifier* verifier, TestProofVerifierCallback* callback = new TestProofVerifierCallback(&comp_callback, &ok, &error_details); - ProofVerifier::Status status = verifier->VerifyProof( + QuicAsyncStatus status = verifier->VerifyProof( hostname, server_config, certs, proof, verify_context.get(), &error_details, &details, callback); switch (status) { - case ProofVerifier::FAILURE: + case QUIC_FAILURE: delete callback; ASSERT_FALSE(expected_ok); ASSERT_NE("", error_details); return; - case ProofVerifier::SUCCESS: + case QUIC_SUCCESS: delete callback; ASSERT_TRUE(expected_ok); ASSERT_EQ("", error_details); return; - case ProofVerifier::PENDING: + case QUIC_PENDING: comp_callback.WaitForResult(); ASSERT_EQ(expected_ok, ok); break; diff --git a/net/quic/crypto/proof_verifier.h b/net/quic/crypto/proof_verifier.h index 779d63f..12bbb4c 100644 --- a/net/quic/crypto/proof_verifier.h +++ b/net/quic/crypto/proof_verifier.h @@ -10,6 +10,7 @@ #include "base/memory/scoped_ptr.h" #include "net/base/net_export.h" +#include "net/quic/quic_types.h" namespace net { @@ -49,42 +50,33 @@ class NET_EXPORT_PRIVATE ProofVerifierCallback { // chain that backs the public key. class NET_EXPORT_PRIVATE ProofVerifier { public: - // Status enumerates the possible results of verifying a proof. - enum Status { - SUCCESS = 0, - FAILURE = 1, - // PENDING results from a verification which will occur asynchonously. When - // the verification is complete, |callback|'s |Run| method will be called. - PENDING = 2, - }; - virtual ~ProofVerifier() {} // VerifyProof checks that |signature| is a valid signature of // |server_config| by the public key in the leaf certificate of |certs|, and // that |certs| is a valid chain for |hostname|. On success, it returns - // SUCCESS. On failure, it returns ERROR and sets |*error_details| to a - // description of the problem. In either case it may set |*details|, which the - // caller takes ownership of. + // QUIC_SUCCESS. On failure, it returns QUIC_ERROR and sets |*error_details| + // to a description of the problem. In either case it may set |*details|, + // which the caller takes ownership of. // // |context| specifies an implementation specific struct (which may be NULL // for some implementations) that provides useful information for the // verifier, e.g. logging handles. // - // This function may also return PENDING, in which case the ProofVerifier + // This function may also return QUIC_PENDING, in which case the ProofVerifier // will call back, on the original thread, via |callback| when complete. // In this case, the ProofVerifier will take ownership of |callback|. // // The signature uses SHA-256 as the hash function and PSS padding in the // case of RSA. - virtual Status VerifyProof(const std::string& hostname, - const std::string& server_config, - const std::vector<std::string>& certs, - const std::string& signature, - const ProofVerifyContext* context, - std::string* error_details, - scoped_ptr<ProofVerifyDetails>* details, - ProofVerifierCallback* callback) = 0; + virtual QuicAsyncStatus VerifyProof(const std::string& hostname, + const std::string& server_config, + const std::vector<std::string>& certs, + const std::string& signature, + const ProofVerifyContext* context, + std::string* error_details, + scoped_ptr<ProofVerifyDetails>* details, + ProofVerifierCallback* callback) = 0; }; } // namespace net diff --git a/net/quic/crypto/proof_verifier_chromium.cc b/net/quic/crypto/proof_verifier_chromium.cc index cbb4436..9829c97 100644 --- a/net/quic/crypto/proof_verifier_chromium.cc +++ b/net/quic/crypto/proof_verifier_chromium.cc @@ -42,13 +42,13 @@ class ProofVerifierChromium::Job { // Starts the proof verification. If |PENDING| is returned, then |callback| // will be invoked asynchronously when the verification completes. - Status VerifyProof(const std::string& hostname, - const std::string& server_config, - const std::vector<std::string>& certs, - const std::string& signature, - std::string* error_details, - scoped_ptr<ProofVerifyDetails>* verify_details, - ProofVerifierCallback* callback); + QuicAsyncStatus VerifyProof(const std::string& hostname, + const std::string& server_config, + const std::vector<std::string>& certs, + const std::string& signature, + std::string* error_details, + scoped_ptr<ProofVerifyDetails>* verify_details, + ProofVerifierCallback* callback); private: enum State { @@ -98,7 +98,7 @@ ProofVerifierChromium::Job::Job(ProofVerifierChromium* proof_verifier, net_log_(net_log) { } -ProofVerifierChromium::Status ProofVerifierChromium::Job::VerifyProof( +QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof( const string& hostname, const string& server_config, const vector<string>& certs, @@ -115,7 +115,7 @@ ProofVerifierChromium::Status ProofVerifierChromium::Job::VerifyProof( if (STATE_NONE != next_state_) { *error_details = "Certificate is already set and VerifyProof has begun"; DLOG(DFATAL) << *error_details; - return FAILURE; + return QUIC_FAILURE; } verify_details_.reset(new ProofVerifyDetailsChromium); @@ -125,7 +125,7 @@ ProofVerifierChromium::Status ProofVerifierChromium::Job::VerifyProof( DLOG(WARNING) << *error_details; verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID; verify_details->reset(verify_details_.release()); - return FAILURE; + return QUIC_FAILURE; } // Convert certs to X509Certificate. @@ -139,7 +139,7 @@ ProofVerifierChromium::Status ProofVerifierChromium::Job::VerifyProof( DLOG(WARNING) << *error_details; verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID; verify_details->reset(verify_details_.release()); - return FAILURE; + return QUIC_FAILURE; } // We call VerifySignature first to avoid copying of server_config and @@ -149,7 +149,7 @@ ProofVerifierChromium::Status ProofVerifierChromium::Job::VerifyProof( DLOG(WARNING) << *error_details; verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID; verify_details->reset(verify_details_.release()); - return FAILURE; + return QUIC_FAILURE; } hostname_ = hostname; @@ -158,14 +158,14 @@ ProofVerifierChromium::Status ProofVerifierChromium::Job::VerifyProof( switch (DoLoop(OK)) { case OK: verify_details->reset(verify_details_.release()); - return SUCCESS; + return QUIC_SUCCESS; case ERR_IO_PENDING: callback_.reset(callback); - return PENDING; + return QUIC_PENDING; default: *error_details = error_details_; verify_details->reset(verify_details_.release()); - return FAILURE; + return QUIC_FAILURE; } } @@ -317,7 +317,7 @@ ProofVerifierChromium::~ProofVerifierChromium() { STLDeleteElements(&active_jobs_); } -ProofVerifierChromium::Status ProofVerifierChromium::VerifyProof( +QuicAsyncStatus ProofVerifierChromium::VerifyProof( const std::string& hostname, const std::string& server_config, const std::vector<std::string>& certs, @@ -328,14 +328,15 @@ ProofVerifierChromium::Status ProofVerifierChromium::VerifyProof( ProofVerifierCallback* callback) { if (!verify_context) { *error_details = "Missing context"; - return FAILURE; + return QUIC_FAILURE; } const ProofVerifyContextChromium* chromium_context = reinterpret_cast<const ProofVerifyContextChromium*>(verify_context); scoped_ptr<Job> job(new Job(this, cert_verifier_, chromium_context->net_log)); - Status status = job->VerifyProof(hostname, server_config, certs, signature, - error_details, verify_details, callback); - if (status == PENDING) { + QuicAsyncStatus status = job->VerifyProof(hostname, server_config, certs, + signature, error_details, + verify_details, callback); + if (status == QUIC_PENDING) { active_jobs_.insert(job.release()); } return status; diff --git a/net/quic/crypto/proof_verifier_chromium.h b/net/quic/crypto/proof_verifier_chromium.h index ebf9a2c..6f8a231 100644 --- a/net/quic/crypto/proof_verifier_chromium.h +++ b/net/quic/crypto/proof_verifier_chromium.h @@ -48,14 +48,15 @@ class NET_EXPORT_PRIVATE ProofVerifierChromium : public ProofVerifier { virtual ~ProofVerifierChromium(); // ProofVerifier interface - virtual Status VerifyProof(const std::string& hostname, - const std::string& server_config, - const std::vector<std::string>& certs, - const std::string& signature, - const ProofVerifyContext* verify_context, - std::string* error_details, - scoped_ptr<ProofVerifyDetails>* verify_details, - ProofVerifierCallback* callback) OVERRIDE; + virtual QuicAsyncStatus VerifyProof( + const std::string& hostname, + const std::string& server_config, + const std::vector<std::string>& certs, + const std::string& signature, + const ProofVerifyContext* verify_context, + std::string* error_details, + scoped_ptr<ProofVerifyDetails>* verify_details, + ProofVerifierCallback* callback) OVERRIDE; private: class Job; diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc index 260c0d4..52acd43 100644 --- a/net/quic/crypto/quic_crypto_server_config.cc +++ b/net/quic/crypto/quic_crypto_server_config.cc @@ -1278,7 +1278,11 @@ string QuicCryptoServerConfig::NewSourceAddressToken(const Config& config, QuicRandom* rand, QuicWallTime now) const { SourceAddressToken source_address_token; - source_address_token.set_ip(IPAddressToPackedString(ip.address())); + IPAddressNumber ip_address = ip.address(); + if (ip.GetSockAddrFamily() == AF_INET) { + ip_address = ConvertIPv4NumberToIPv6Number(ip_address); + } + source_address_token.set_ip(IPAddressToPackedString(ip_address)); source_address_token.set_timestamp(now.ToUNIXSeconds()); return config.source_address_token_boxer->Box( @@ -1302,7 +1306,11 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken( return false; } - if (source_address_token.ip() != IPAddressToPackedString(ip.address())) { + IPAddressNumber ip_address = ip.address(); + if (ip.GetSockAddrFamily() == AF_INET) { + ip_address = ConvertIPv4NumberToIPv6Number(ip_address); + } + if (source_address_token.ip() != IPAddressToPackedString(ip_address)) { // It's for a different IP address. return false; } diff --git a/net/quic/crypto/quic_crypto_server_config_test.cc b/net/quic/crypto/quic_crypto_server_config_test.cc index 8aeef00..069c523 100644 --- a/net/quic/crypto/quic_crypto_server_config_test.cc +++ b/net/quic/crypto/quic_crypto_server_config_test.cc @@ -14,6 +14,7 @@ #include "net/quic/crypto/strike_register_client.h" #include "net/quic/quic_time.h" #include "net/quic/test_tools/mock_clock.h" +#include "net/quic/test_tools/quic_test_utils.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -261,17 +262,20 @@ TEST(QuicCryptoServerConfigTest, SourceAddressTokens) { EXPECT_TRUE(peer.ConfigHasDefaultSourceAddressTokenBoxer(kPrimary)); EXPECT_FALSE(peer.ConfigHasDefaultSourceAddressTokenBoxer(kOverride)); - IPAddressNumber ip; - CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip)); - IPEndPoint ip4 = IPEndPoint(ip, 1); - CHECK(ParseIPLiteralToNumber("2001:db8:0::42", &ip)); - IPEndPoint ip6 = IPEndPoint(ip, 2); + IPEndPoint ip4 = IPEndPoint(Loopback4(), 1); + IPEndPoint ip4d = IPEndPoint(ConvertIPv4NumberToIPv6Number(ip4.address()), 1); + IPEndPoint ip6 = IPEndPoint(Loopback6(), 2); // Primary config generates configs that validate successfully. const string token4 = peer.NewSourceAddressToken(kPrimary, ip4, rand, now); + const string token4d = peer.NewSourceAddressToken(kPrimary, ip4d, rand, now); const string token6 = peer.NewSourceAddressToken(kPrimary, ip6, rand, now); EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token4, ip4, now)); + EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token4, ip4d, now)); EXPECT_FALSE(peer.ValidateSourceAddressToken(kPrimary, token4, ip6, now)); + EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token4d, ip4, now)); + EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token4d, ip4d, now)); + EXPECT_FALSE(peer.ValidateSourceAddressToken(kPrimary, token4d, ip6, now)); EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token6, ip6, now)); // Override config generates configs that validate successfully. diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 04426d3..2f8c845 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -1246,7 +1246,8 @@ void QuicConnection::WritePendingRetransmissions() { pending.sequence_number, serialized_packet.sequence_number); } sent_packet_manager_.OnRetransmittedPacket( - pending.sequence_number, serialized_packet.sequence_number); + pending.sequence_number, + serialized_packet.sequence_number); SendOrQueuePacket(pending.retransmittable_frames.encryption_level(), serialized_packet, diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index c35e863..9e93715e 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -40,6 +40,7 @@ #include "net/quic/quic_received_packet_manager.h" #include "net/quic/quic_sent_entropy_manager.h" #include "net/quic/quic_sent_packet_manager.h" +#include "net/quic/quic_types.h" namespace net { @@ -112,7 +113,8 @@ class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface { // points. Implementations must not mutate the state of the connection // as a result of these callbacks. class NET_EXPORT_PRIVATE QuicConnectionDebugVisitor - : public QuicPacketGenerator::DebugDelegate { + : public QuicPacketGenerator::DebugDelegate, + public QuicSentPacketManager::DebugDelegate { public: virtual ~QuicConnectionDebugVisitor() {} @@ -347,6 +349,7 @@ class NET_EXPORT_PRIVATE QuicConnection void set_debug_visitor(QuicConnectionDebugVisitor* debug_visitor) { debug_visitor_ = debug_visitor; packet_generator_.set_debug_delegate(debug_visitor); + sent_packet_manager_.set_debug_delegate(debug_visitor); } const IPEndPoint& self_address() const { return self_address_; } const IPEndPoint& peer_address() const { return peer_address_; } diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc index 9fa9367..dcc4182 100644 --- a/net/quic/quic_crypto_client_stream.cc +++ b/net/quic/quic_crypto_client_stream.cc @@ -237,7 +237,7 @@ void QuicCryptoClientStream::DoHandshakeLoop( verify_ok_ = false; - ProofVerifier::Status status = verifier->VerifyProof( + QuicAsyncStatus status = verifier->VerifyProof( server_id_.host(), cached->server_config(), cached->certs(), @@ -248,14 +248,14 @@ void QuicCryptoClientStream::DoHandshakeLoop( proof_verify_callback); switch (status) { - case ProofVerifier::PENDING: + case QUIC_PENDING: proof_verify_callback_ = proof_verify_callback; DVLOG(1) << "Doing VerifyProof"; return; - case ProofVerifier::FAILURE: + case QUIC_FAILURE: delete proof_verify_callback; break; - case ProofVerifier::SUCCESS: + case QUIC_SUCCESS: delete proof_verify_callback; verify_ok_ = true; break; diff --git a/net/quic/quic_data_stream_test.cc b/net/quic/quic_data_stream_test.cc index 6799131..04b7c4e 100644 --- a/net/quic/quic_data_stream_test.cc +++ b/net/quic/quic_data_stream_test.cc @@ -497,7 +497,8 @@ TEST_P(QuicDataStreamTest, StreamFlowControlViolation) { string body; GenerateBody(&body, kWindow + 1); QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body)); - EXPECT_CALL(*connection_, SendConnectionClose(QUIC_FLOW_CONTROL_ERROR)); + EXPECT_CALL(*connection_, + SendConnectionClose(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA)); stream_->OnStreamFrame(frame); } @@ -534,7 +535,8 @@ TEST_P(QuicDataStreamTest, ConnectionFlowControlViolation) { EXPECT_LT(body.size(), kStreamWindow); QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body)); - EXPECT_CALL(*connection_, SendConnectionClose(QUIC_FLOW_CONTROL_ERROR)); + EXPECT_CALL(*connection_, + SendConnectionClose(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA)); stream_->OnStreamFrame(frame); } diff --git a/net/quic/quic_flow_controller.cc b/net/quic/quic_flow_controller.cc index a469fd5..6ca3520 100644 --- a/net/quic/quic_flow_controller.cc +++ b/net/quic/quic_flow_controller.cc @@ -13,31 +13,32 @@ namespace net { #define ENDPOINT (is_server_ ? "Server: " : " Client: ") -QuicFlowController::QuicFlowController(QuicVersion version, +QuicFlowController::QuicFlowController(QuicConnection* connection, QuicStreamId id, bool is_server, uint64 send_window_offset, uint64 receive_window_offset, uint64 max_receive_window) - : id_(id), - is_enabled_(true), - is_server_(is_server), - bytes_consumed_(0), - highest_received_byte_offset_(0), - bytes_sent_(0), - send_window_offset_(send_window_offset), - receive_window_offset_(receive_window_offset), - max_receive_window_(max_receive_window), - last_blocked_send_window_offset_(0) { + : connection_(connection), + id_(id), + is_enabled_(true), + is_server_(is_server), + bytes_consumed_(0), + highest_received_byte_offset_(0), + bytes_sent_(0), + send_window_offset_(send_window_offset), + receive_window_offset_(receive_window_offset), + max_receive_window_(max_receive_window), + last_blocked_send_window_offset_(0) { DVLOG(1) << ENDPOINT << "Created flow controller for stream " << id_ << ", setting initial receive window offset to: " << receive_window_offset_ << ", max receive window to: " << max_receive_window_ << ", setting send window offset to: " << send_window_offset_; - if (version < QUIC_VERSION_17) { + if (connection_->version() < QUIC_VERSION_17) { DVLOG(1) << ENDPOINT << "Disabling QuicFlowController for stream " << id_ - << ", QUIC version " << version; + << ", QUIC version " << connection_->version(); Disable(); } } @@ -49,6 +50,8 @@ void QuicFlowController::AddBytesConsumed(uint64 bytes_consumed) { bytes_consumed_ += bytes_consumed; DVLOG(1) << ENDPOINT << "Stream " << id_ << " consumed: " << bytes_consumed_; + + MaybeSendWindowUpdate(); } bool QuicFlowController::UpdateHighestReceivedOffset(uint64 new_offset) { @@ -78,6 +81,9 @@ void QuicFlowController::AddBytesSent(uint64 bytes_sent) { << bytes_sent << " bytes, when bytes_sent = " << bytes_sent_ << ", and send_window_offset_ = " << send_window_offset_; bytes_sent_ = send_window_offset_; + + // This is an error on our side, close the connection as soon as possible. + connection_->SendConnectionClose(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA); return; } @@ -101,7 +107,7 @@ bool QuicFlowController::FlowControlViolation() { return false; } -void QuicFlowController::MaybeSendWindowUpdate(QuicConnection* connection) { +void QuicFlowController::MaybeSendWindowUpdate() { if (!IsEnabled()) { return; } @@ -109,6 +115,7 @@ void QuicFlowController::MaybeSendWindowUpdate(QuicConnection* connection) { // Send WindowUpdate to increase receive window if // (receive window offset - consumed bytes) < (max window / 2). // This is behaviour copied from SPDY. + DCHECK_LT(bytes_consumed_, receive_window_offset_); size_t consumed_window = receive_window_offset_ - bytes_consumed_; size_t threshold = (max_receive_window_ / 2); @@ -124,11 +131,11 @@ void QuicFlowController::MaybeSendWindowUpdate(QuicConnection* connection) { << ". New receive window offset is: " << receive_window_offset_; // Inform the peer of our new receive window. - connection->SendWindowUpdate(id_, receive_window_offset_); + connection_->SendWindowUpdate(id_, receive_window_offset_); } } -void QuicFlowController::MaybeSendBlocked(QuicConnection* connection) { +void QuicFlowController::MaybeSendBlocked() { if (!IsEnabled()) { return; } @@ -141,7 +148,7 @@ void QuicFlowController::MaybeSendBlocked(QuicConnection* connection) { << ", send limit: " << send_window_offset_; // The entire send_window has been consumed, we are now flow control // blocked. - connection->SendBlocked(id_); + connection_->SendBlocked(id_); // Keep track of when we last sent a BLOCKED frame so that we only send one // at a given send offset. diff --git a/net/quic/quic_flow_controller.h b/net/quic/quic_flow_controller.h index 596ef1a..e5f5494 100644 --- a/net/quic/quic_flow_controller.h +++ b/net/quic/quic_flow_controller.h @@ -25,7 +25,7 @@ const QuicStreamId kConnectionLevelId = 0; // can send WINDOW_UPDATE or BLOCKED frames when needed. class NET_EXPORT_PRIVATE QuicFlowController { public: - QuicFlowController(QuicVersion version, + QuicFlowController(QuicConnection* connection, QuicStreamId id, bool is_server, uint64 send_window_offset, @@ -39,7 +39,8 @@ class NET_EXPORT_PRIVATE QuicFlowController { // in the case where |new_offset| is <= highest_received_byte_offset_. bool UpdateHighestReceivedOffset(uint64 new_offset); - // Called when bytes received from the peer are consumed locally. + // Called when bytes received from the peer are consumed locally. This may + // trigger the sending of a WINDOW_UPDATE frame using |connection|. void AddBytesConsumed(uint64 bytes_consumed); // Called when bytes are sent to the peer. @@ -53,11 +54,8 @@ class NET_EXPORT_PRIVATE QuicFlowController { // Returns the current available send window. uint64 SendWindowSize() const; - // Send a BLOCKED frame on |connection| if appropriate. - void MaybeSendBlocked(QuicConnection* connection); - - // Send a WINDOW_UPDATE frame on |connection| if appropriate. - void MaybeSendWindowUpdate(QuicConnection* connection); + // Send a BLOCKED frame if appropriate. + void MaybeSendBlocked(); // Disable flow control. void Disable(); @@ -71,6 +69,8 @@ class NET_EXPORT_PRIVATE QuicFlowController { // Returns true if flow control receive limits have been violated by the peer. bool FlowControlViolation(); + uint64 bytes_consumed() const { return bytes_consumed_; } + uint64 highest_received_byte_offset() const { return highest_received_byte_offset_; } @@ -78,6 +78,14 @@ class NET_EXPORT_PRIVATE QuicFlowController { private: friend class test::QuicFlowControllerPeer; + // Send a WINDOW_UPDATE frame if appropriate. + void MaybeSendWindowUpdate(); + + // The parent connection, used to send connection close on flow control + // violation, and WINDOW_UPDATE and BLOCKED frames when appropriate. + // Not owned. + QuicConnection* connection_; + // ID of stream this flow controller belongs to. This can be 0 if this is a // connection level flow controller. QuicStreamId id_; diff --git a/net/quic/quic_flow_controller_test.cc b/net/quic/quic_flow_controller_test.cc index 7ef9bb4..e40dc94 100644 --- a/net/quic/quic_flow_controller_test.cc +++ b/net/quic/quic_flow_controller_test.cc @@ -7,6 +7,7 @@ #include "base/strings/stringprintf.h" #include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" +#include "net/quic/test_tools/quic_connection_peer.h" #include "net/quic/test_tools/quic_flow_controller_peer.h" #include "net/quic/test_tools/quic_test_utils.h" #include "net/test/gtest_util.h" @@ -23,28 +24,26 @@ class QuicFlowControllerTest : public ::testing::Test { public: QuicFlowControllerTest() : stream_id_(1234), - send_window_(100), - receive_window_(200), - max_receive_window_(200), - version_(QuicVersionMax()), + send_window_(kInitialFlowControlWindowForTest), + receive_window_(kInitialFlowControlWindowForTest), + max_receive_window_(kInitialFlowControlWindowForTest), + connection_(false), old_flag_(&FLAGS_enable_quic_stream_flow_control_2, true) { } void Initialize() { - flow_controller_.reset(new QuicFlowController(version_, stream_id_, false, - send_window_, receive_window_, - max_receive_window_)); + flow_controller_.reset(new QuicFlowController( + &connection_, stream_id_, false, send_window_, + receive_window_, max_receive_window_)); } - void set_version(QuicVersion version) { version_ = version; } - protected: QuicStreamId stream_id_; uint64 send_window_; uint64 receive_window_; uint64 max_receive_window_; - QuicVersion version_; scoped_ptr<QuicFlowController> flow_controller_; + MockConnection connection_; ValueRestore<bool> old_flag_; }; @@ -67,9 +66,8 @@ TEST_F(QuicFlowControllerTest, SendingBytes) { EXPECT_EQ(0u, flow_controller_->SendWindowSize()); // BLOCKED frame should get sent. - MockConnection connection(false); - EXPECT_CALL(connection, SendBlocked(stream_id_)).Times(1); - flow_controller_->MaybeSendBlocked(&connection); + EXPECT_CALL(connection_, SendBlocked(stream_id_)).Times(1); + flow_controller_->MaybeSendBlocked(); // Update the send window, and verify this has unblocked. EXPECT_TRUE(flow_controller_->UpdateSendWindowOffset(2 * send_window_)); @@ -81,6 +79,8 @@ TEST_F(QuicFlowControllerTest, SendingBytes) { EXPECT_EQ(send_window_, flow_controller_->SendWindowSize()); // Try to send more bytes, violating flow control. + EXPECT_CALL(connection_, + SendConnectionClose(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA)); EXPECT_DFATAL( flow_controller_->AddBytesSent(send_window_ * 10), StringPrintf("Trying to send an extra %d bytes", @@ -95,8 +95,11 @@ TEST_F(QuicFlowControllerTest, ReceivingBytes) { EXPECT_TRUE(flow_controller_->IsEnabled()); EXPECT_FALSE(flow_controller_->IsBlocked()); EXPECT_FALSE(flow_controller_->FlowControlViolation()); + EXPECT_EQ(kInitialFlowControlWindowForTest, + QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get())); - // Buffer some bytes, not enough to fill window. + // Receive some bytes, updating highest received offset, but not enough to + // fill flow control receive window. EXPECT_TRUE( flow_controller_->UpdateHighestReceivedOffset(1 + receive_window_ / 2)); EXPECT_FALSE(flow_controller_->FlowControlViolation()); @@ -104,21 +107,27 @@ TEST_F(QuicFlowControllerTest, ReceivingBytes) { QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get())); // Consume enough bytes to send a WINDOW_UPDATE frame. + EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, _)).Times(1); + flow_controller_->AddBytesConsumed(1 + receive_window_ / 2); + + // Result is that once again we have a fully open receive window. EXPECT_FALSE(flow_controller_->FlowControlViolation()); - EXPECT_EQ((receive_window_ / 2) - 1, + EXPECT_EQ(kInitialFlowControlWindowForTest, QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get())); - - MockConnection connection(false); - EXPECT_CALL(connection, SendWindowUpdate(stream_id_, _)).Times(1); - flow_controller_->MaybeSendWindowUpdate(&connection); } TEST_F(QuicFlowControllerTest, DisabledWhenQuicVersionDoesNotSupportFlowControl) { - set_version(QUIC_VERSION_16); + // Only support version 16: no flow control. + QuicVersionVector supported_versions; + supported_versions.push_back(QUIC_VERSION_16); + QuicConnectionPeer::SetSupportedVersions(&connection_, supported_versions); + Initialize(); + MockConnection connection(false); + // Should not be enabled, and should not report as blocked. EXPECT_FALSE(flow_controller_->IsEnabled()); EXPECT_FALSE(flow_controller_->IsBlocked()); @@ -148,15 +157,14 @@ TEST_F(QuicFlowControllerTest, EXPECT_EQ(send_window_, QuicFlowControllerPeer::SendWindowOffset(flow_controller_.get())); - // Should never send WINDOW_UPDATE or BLOCKED frames, even if the internal - // state implies that it should. - MockConnection connection(false); + // The connection should never send WINDOW_UPDATE or BLOCKED frames, even if + // the internal state implies that it should. // If the flow controller was enabled, then a send window size of 0 would // trigger a BLOCKED frame to be sent. EXPECT_EQ(send_window_, flow_controller_->SendWindowSize()); - EXPECT_CALL(connection, SendBlocked(_)).Times(0); - flow_controller_->MaybeSendBlocked(&connection); + EXPECT_CALL(connection_, SendBlocked(_)).Times(0); + flow_controller_->MaybeSendBlocked(); // If the flow controller was enabled, then a WINDOW_UPDATE would be sent if // (receive window) < (max receive window / 2) @@ -164,8 +172,8 @@ TEST_F(QuicFlowControllerTest, max_receive_window_ / 10); EXPECT_TRUE(QuicFlowControllerPeer::ReceiveWindowSize( flow_controller_.get()) < (max_receive_window_ / 2)); - EXPECT_CALL(connection, SendWindowUpdate(_, _)).Times(0); - flow_controller_->MaybeSendWindowUpdate(&connection); + EXPECT_CALL(connection_, SendWindowUpdate(_, _)).Times(0); + flow_controller_->AddBytesConsumed(0); // Should not be enabled, and should not report as blocked. EXPECT_FALSE(flow_controller_->IsEnabled()); @@ -189,18 +197,17 @@ TEST_F(QuicFlowControllerTest, OnlySendBlockedFrameOncePerOffset) { EXPECT_EQ(0u, flow_controller_->SendWindowSize()); // Expect that 2 BLOCKED frames should get sent in total. - MockConnection connection(false); - EXPECT_CALL(connection, SendBlocked(stream_id_)).Times(2); + EXPECT_CALL(connection_, SendBlocked(stream_id_)).Times(2); // BLOCKED frame should get sent. - flow_controller_->MaybeSendBlocked(&connection); + flow_controller_->MaybeSendBlocked(); // BLOCKED frame should not get sent again until our send offset changes. - flow_controller_->MaybeSendBlocked(&connection); - flow_controller_->MaybeSendBlocked(&connection); - flow_controller_->MaybeSendBlocked(&connection); - flow_controller_->MaybeSendBlocked(&connection); - flow_controller_->MaybeSendBlocked(&connection); + flow_controller_->MaybeSendBlocked(); + flow_controller_->MaybeSendBlocked(); + flow_controller_->MaybeSendBlocked(); + flow_controller_->MaybeSendBlocked(); + flow_controller_->MaybeSendBlocked(); // Update the send window, then send enough bytes to block again. EXPECT_TRUE(flow_controller_->UpdateSendWindowOffset(2 * send_window_)); @@ -211,7 +218,7 @@ TEST_F(QuicFlowControllerTest, OnlySendBlockedFrameOncePerOffset) { EXPECT_EQ(0u, flow_controller_->SendWindowSize()); // BLOCKED frame should get sent as send offset has changed. - flow_controller_->MaybeSendBlocked(&connection); + flow_controller_->MaybeSendBlocked(); } } // namespace test diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h index d9de488..957477a 100644 --- a/net/quic/quic_packet_generator.h +++ b/net/quic/quic_packet_generator.h @@ -54,6 +54,7 @@ #define NET_QUIC_QUIC_PACKET_GENERATOR_H_ #include "net/quic/quic_packet_creator.h" +#include "net/quic/quic_types.h" namespace net { diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index 7502cdb..cd73694 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc @@ -144,7 +144,7 @@ uint32 MakeQuicTag(char a, char b, char c, char d) { static_cast<uint32>(d) << 24; } -bool ContainsQuicTag(QuicTagVector tag_vector, QuicTag tag) { +bool ContainsQuicTag(const QuicTagVector& tag_vector, QuicTag tag) { return std::find(tag_vector.begin(), tag_vector.end(), tag) != tag_vector.end(); } @@ -751,6 +751,7 @@ TransmissionInfo::TransmissionInfo() sent_time(QuicTime::Zero()), bytes_sent(0), nack_count(0), + transmission_type(NOT_RETRANSMISSION), all_transmissions(NULL), in_flight(false) { } @@ -763,6 +764,7 @@ TransmissionInfo::TransmissionInfo( sent_time(QuicTime::Zero()), bytes_sent(0), nack_count(0), + transmission_type(NOT_RETRANSMISSION), all_transmissions(new SequenceNumberSet), in_flight(false) { all_transmissions->insert(sequence_number); @@ -772,38 +774,17 @@ TransmissionInfo::TransmissionInfo( RetransmittableFrames* retransmittable_frames, QuicPacketSequenceNumber sequence_number, QuicSequenceNumberLength sequence_number_length, + TransmissionType transmission_type, SequenceNumberSet* all_transmissions) : retransmittable_frames(retransmittable_frames), sequence_number_length(sequence_number_length), sent_time(QuicTime::Zero()), bytes_sent(0), nack_count(0), + transmission_type(transmission_type), all_transmissions(all_transmissions), in_flight(false) { all_transmissions->insert(sequence_number); } -QuicConsumedData::QuicConsumedData(size_t bytes_consumed, - bool fin_consumed) - : bytes_consumed(bytes_consumed), - fin_consumed(fin_consumed) { -} - -ostream& operator<<(ostream& os, const QuicConsumedData& s) { - os << "bytes_consumed: " << s.bytes_consumed - << " fin_consumed: " << s.fin_consumed; - return os; -} - -WriteResult::WriteResult() - : status(WRITE_STATUS_ERROR), - bytes_written(0) { -} - -WriteResult::WriteResult(WriteStatus status, - int bytes_written_or_error_code) - : status(status), - bytes_written(bytes_written_or_error_code) { -} - } // namespace net diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index 6dd8ef3..76b31f4 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -319,7 +319,7 @@ NET_EXPORT_PRIVATE std::string QuicVersionVectorToString( NET_EXPORT_PRIVATE QuicTag MakeQuicTag(char a, char b, char c, char d); // Returns true if the tag vector contains the specified tag. -bool ContainsQuicTag(QuicTagVector tag_vector, QuicTag tag); +bool ContainsQuicTag(const QuicTagVector& tag_vector, QuicTag tag); // Size in bytes of the data or fec packet header. NET_EXPORT_PRIVATE size_t GetPacketHeaderSize(const QuicPacketHeader& header); @@ -454,8 +454,12 @@ enum QuicErrorCode { QUIC_INVALID_STREAM_FRAME = 50, // We received invalid data on the headers stream. QUIC_INVALID_HEADERS_STREAM_DATA = 56, - // The peer violated the flow control protocol. - QUIC_FLOW_CONTROL_ERROR = 59, + // The peer received too much data, violating flow control. + QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA = 59, + // The peer sent too much data, violating flow control. + QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA = 63, + // The peer received an invalid flow control window. + QUIC_FLOW_CONTROL_INVALID_WINDOW = 64, // The connection has been IP pooled into an existing connection. QUIC_CONNECTION_IP_POOLED = 62, @@ -513,7 +517,7 @@ enum QuicErrorCode { QUIC_VERSION_NEGOTIATION_MISMATCH = 55, // No error. Used as bound while iterating. - QUIC_LAST_ERROR = 63, + QUIC_LAST_ERROR = 65, }; struct NET_EXPORT_PRIVATE QuicPacketPublicHeader { @@ -1030,6 +1034,7 @@ struct NET_EXPORT_PRIVATE TransmissionInfo { TransmissionInfo(RetransmittableFrames* retransmittable_frames, QuicPacketSequenceNumber sequence_number, QuicSequenceNumberLength sequence_number_length, + TransmissionType transmission_type, SequenceNumberSet* all_transmissions); RetransmittableFrames* retransmittable_frames; @@ -1039,6 +1044,8 @@ struct NET_EXPORT_PRIVATE TransmissionInfo { // Zero when the packet is serialized, non-zero once it's sent. QuicByteCount bytes_sent; size_t nack_count; + // Reason why this packet was transmitted. + TransmissionType transmission_type; // Stores the sequence numbers of all transmissions of this packet. // Can never be null. SequenceNumberSet* all_transmissions; @@ -1046,43 +1053,6 @@ struct NET_EXPORT_PRIVATE TransmissionInfo { bool in_flight; }; -// A struct for functions which consume data payloads and fins. -struct NET_EXPORT_PRIVATE QuicConsumedData { - QuicConsumedData(size_t bytes_consumed, bool fin_consumed); - - // By default, gtest prints the raw bytes of an object. The bool data - // member causes this object to have padding bytes, which causes the - // default gtest object printer to read uninitialize memory. So we need - // to teach gtest how to print this object. - NET_EXPORT_PRIVATE friend std::ostream& operator<<( - std::ostream& os, const QuicConsumedData& s); - - // How many bytes were consumed. - size_t bytes_consumed; - - // True if an incoming fin was consumed. - bool fin_consumed; -}; - -enum WriteStatus { - WRITE_STATUS_OK, - WRITE_STATUS_BLOCKED, - WRITE_STATUS_ERROR, -}; - -// A struct used to return the result of write calls including either the number -// of bytes written or the error code, depending upon the status. -struct NET_EXPORT_PRIVATE WriteResult { - WriteResult(WriteStatus status, int bytes_written_or_error_code); - WriteResult(); - - WriteStatus status; - union { - int bytes_written; // only valid when status is OK - int error_code; // only valid when status is ERROR - }; -}; - } // namespace net #endif // NET_QUIC_QUIC_PROTOCOL_H_ diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index 286ef56..8c41b9c 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc @@ -62,6 +62,7 @@ QuicSentPacketManager::QuicSentPacketManager(bool is_server, is_server_(is_server), clock_(clock), stats_(stats), + debug_delegate_(NULL), send_algorithm_( SendAlgorithmInterface::Create(clock, &rtt_stats_, type, stats)), loss_algorithm_(LossDetectionInterface::Create(loss_type)), @@ -113,9 +114,17 @@ void QuicSentPacketManager::OnSerializedPacket( void QuicSentPacketManager::OnRetransmittedPacket( QuicPacketSequenceNumber old_sequence_number, QuicPacketSequenceNumber new_sequence_number) { - DCHECK(ContainsKey(pending_retransmissions_, old_sequence_number)); - - pending_retransmissions_.erase(old_sequence_number); + TransmissionType transmission_type; + PendingRetransmissionMap::iterator it = + pending_retransmissions_.find(old_sequence_number); + if (it != pending_retransmissions_.end()) { + transmission_type = it->second; + pending_retransmissions_.erase(it); + } else { + DLOG(DFATAL) << "Expected sequence number to be in " + "pending_retransmissions_. sequence_number: " << old_sequence_number; + transmission_type = NOT_RETRANSMISSION; + } // A notifier may be waiting to hear about ACKs for the original sequence // number. Inform them that the sequence number has changed. @@ -123,7 +132,8 @@ void QuicSentPacketManager::OnRetransmittedPacket( new_sequence_number); unacked_packets_.OnRetransmittedPacket(old_sequence_number, - new_sequence_number); + new_sequence_number, + transmission_type); } void QuicSentPacketManager::OnIncomingAck( @@ -276,6 +286,27 @@ void QuicSentPacketManager::MarkForRetransmission( pending_retransmissions_[sequence_number] = transmission_type; } +void QuicSentPacketManager::RecordSpuriousRetransmissions( + const SequenceNumberSet& all_transmissions, + QuicPacketSequenceNumber acked_sequence_number) { + for (SequenceNumberSet::const_iterator + it = all_transmissions.upper_bound(acked_sequence_number), + end = all_transmissions.end(); + it != end; + ++it) { + const TransmissionInfo& retransmit_info = + unacked_packets_.GetTransmissionInfo(*it); + + stats_->bytes_spuriously_retransmitted += retransmit_info.bytes_sent; + ++stats_->packets_spuriously_retransmitted; + if (debug_delegate_ != NULL) { + debug_delegate_->OnSpuriousPacketRetransmition( + retransmit_info.transmission_type, + retransmit_info.bytes_sent); + } + } +} + bool QuicSentPacketManager::HasPendingRetransmissions() const { return !pending_retransmissions_.empty(); } @@ -348,19 +379,22 @@ QuicUnackedPacketMap::const_iterator QuicSentPacketManager::MarkPacketHandled( // Remove the most recent packet, if it is pending retransmission. pending_retransmissions_.erase(newest_transmission); + // Notify observers about the ACKed packet. + { + // The AckNotifierManager needs to be notified about the most recent + // transmission, since that's the one only one it tracks. + ack_notifier_manager_.OnPacketAcked(newest_transmission, + delta_largest_observed); + if (newest_transmission != sequence_number) { + RecordSpuriousRetransmissions(*transmission_info.all_transmissions, + sequence_number); + } + } + // Two cases for MarkPacketHandled: // 1) Handle the most recent or a crypto packet, so remove all transmissions. // 2) Handle old transmission, keep all other pending transmissions, // but disassociate them from one another. - if (newest_transmission != sequence_number) { - stats_->bytes_spuriously_retransmitted += transmission_info.bytes_sent; - ++stats_->packets_spuriously_retransmitted; - } - - // The AckNotifierManager needs to be notified about the most recent - // transmission, since that's the one only one it tracks. - ack_notifier_manager_.OnPacketAcked(newest_transmission, - delta_largest_observed); // If it's a crypto handshake packet, discard it and all retransmissions, // since they won't be acked now that one has been processed. diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h index 5823942..395d212 100644 --- a/net/quic/quic_sent_packet_manager.h +++ b/net/quic/quic_sent_packet_manager.h @@ -41,6 +41,19 @@ struct QuicConnectionStats; // previous transmission is acked, the data will not be retransmitted. class NET_EXPORT_PRIVATE QuicSentPacketManager { public: + // Interface which gets callbacks from the QuicSentPacketManager at + // interesting points. Implementations must not mutate the state of + // the packet manager or connection as a result of these callbacks. + class NET_EXPORT_PRIVATE DebugDelegate { + public: + virtual ~DebugDelegate() {} + + // Called when a spurious retransmission is detected. + virtual void OnSpuriousPacketRetransmition( + TransmissionType transmission_type, + QuicByteCount byte_size) {} + }; + // Struct to store the pending retransmission information. struct PendingRetransmission { PendingRetransmission(QuicPacketSequenceNumber sequence_number, @@ -159,6 +172,10 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager { bool using_pacing() const { return using_pacing_; } + void set_debug_delegate(DebugDelegate* debug_delegate) { + debug_delegate_ = debug_delegate; + } + private: friend class test::QuicConnectionPeer; friend class test::QuicSentPacketManagerPeer; @@ -239,6 +256,11 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager { void MarkForRetransmission(QuicPacketSequenceNumber sequence_number, TransmissionType transmission_type); + // Notify observers about spurious retransmits. + void RecordSpuriousRetransmissions( + const SequenceNumberSet& all_transmissions, + QuicPacketSequenceNumber acked_sequence_number); + // Newly serialized retransmittable and fec packets are added to this map, // which contains owning pointers to any contained frames. If a packet is // retransmitted, this map will contain entries for both the old and the new @@ -262,6 +284,7 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager { const QuicClock* clock_; QuicConnectionStats* stats_; + DebugDelegate* debug_delegate_; RttStats rtt_stats_; scoped_ptr<SendAlgorithmInterface> send_algorithm_; scoped_ptr<LossDetectionInterface> loss_algorithm_; diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc index b3c1fdc..ef13a22 100644 --- a/net/quic/quic_sent_packet_manager_test.cc +++ b/net/quic/quic_sent_packet_manager_test.cc @@ -32,6 +32,13 @@ MATCHER(KeyEq, "") { return std::tr1::get<0>(arg).first == std::tr1::get<1>(arg); } +class MockDebugDelegate : public QuicSentPacketManager::DebugDelegate { + public: + MOCK_METHOD2(OnSpuriousPacketRetransmition, + void(TransmissionType transmission_type, + QuicByteCount byte_size)); +}; + class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> { protected: QuicSentPacketManagerTest() @@ -129,7 +136,8 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> { EXPECT_EQ(old_sequence_number, next_retransmission.sequence_number); EXPECT_EQ(TLP_RETRANSMISSION, next_retransmission.transmission_type); - manager_.OnRetransmittedPacket(old_sequence_number, new_sequence_number); + manager_.OnRetransmittedPacket(old_sequence_number, + new_sequence_number); EXPECT_TRUE(QuicSentPacketManagerPeer::IsRetransmission( &manager_, new_sequence_number)); } @@ -232,8 +240,8 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> { .Times(1).WillOnce(Return(true)); const QuicSentPacketManager::PendingRetransmission pending = manager_.NextPendingRetransmission(); - manager_.OnRetransmittedPacket( - pending.sequence_number, retransmission_sequence_number); + manager_.OnRetransmittedPacket(pending.sequence_number, + retransmission_sequence_number); manager_.OnPacketSent(retransmission_sequence_number, clock_.Now(), kDefaultLength, pending.transmission_type, HAS_RETRANSMITTABLE_DATA); @@ -428,6 +436,11 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckPreviousBeforeSend) { } TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { + StrictMock<MockDebugDelegate> debug_delegate; + EXPECT_CALL(debug_delegate, OnSpuriousPacketRetransmition( + TLP_RETRANSMISSION, kDefaultLength)).Times(2); + manager_.set_debug_delegate(&debug_delegate); + SendDataPacket(1); RetransmitAndSendPacket(1, 2); RetransmitAndSendPacket(2, 3); @@ -465,7 +478,7 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { VerifyUnackedPackets(NULL, 0); EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); - EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted); + EXPECT_EQ(2u, stats_.packets_spuriously_retransmitted); } TEST_F(QuicSentPacketManagerTest, LoseButDontRetransmitRevivedPacket) { diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index 9b28103..e0bddfe 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc @@ -118,8 +118,8 @@ QuicSession::QuicSession(QuicConnection* connection, max_flow_control_receive_window_bytes_ = kDefaultFlowControlSendWindow; } flow_controller_.reset(new QuicFlowController( - connection_->supported_versions().front(), 0, is_server(), - kDefaultFlowControlSendWindow, max_flow_control_receive_window_bytes_, + connection_.get(), 0, is_server(), kDefaultFlowControlSendWindow, + max_flow_control_receive_window_bytes_, max_flow_control_receive_window_bytes_)); connection_->set_visitor(visitor_shim_.get()); @@ -422,7 +422,7 @@ void QuicSession::OnConfigNegotiated() { << "Peer sent us an invalid flow control send window: " << new_flow_control_send_window << ", below default: " << kDefaultFlowControlSendWindow; - connection_->SendConnectionClose(QUIC_FLOW_CONTROL_ERROR); + connection_->SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW); return; } DataStreamMap::iterator it = stream_map_.begin(); @@ -643,6 +643,15 @@ void QuicSession::OnSuccessfulVersionNegotiation(const QuicVersion& version) { if (version < QUIC_VERSION_19) { flow_controller_->Disable(); } + + // Inform all streams about the negotiated version. They may have been created + // with a different version. + for (DataStreamMap::iterator it = stream_map_.begin(); + it != stream_map_.end(); ++it) { + if (version < QUIC_VERSION_17) { + it->second->flow_controller()->Disable(); + } + } } } // namespace net diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc index 92c3cab..b70be5a 100644 --- a/net/quic/quic_session_test.cc +++ b/net/quic/quic_session_test.cc @@ -168,6 +168,8 @@ class TestSession : public QuicSession { return WritevData(id, IOVector(), 0, true, NULL); } + using QuicSession::PostProcessAfterData; + private: StrictMock<TestCryptoStream> crypto_stream_; @@ -661,7 +663,8 @@ TEST_P(QuicSessionTest, InvalidFlowControlWindowInHandshake) { session_.config()->ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); - EXPECT_CALL(*connection_, SendConnectionClose(QUIC_FLOW_CONTROL_ERROR)); + EXPECT_CALL(*connection_, + SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW)); session_.OnConfigNegotiated(); } @@ -676,6 +679,101 @@ TEST_P(QuicSessionTest, InvalidFlowControlWindow) { session.max_flow_control_receive_window_bytes()); } +TEST_P(QuicSessionTest, ConnectionFlowControlAccountingRstOutOfOrder) { + FLAGS_enable_quic_stream_flow_control_2 = true; + FLAGS_enable_quic_connection_flow_control = true; + if (version() < QUIC_VERSION_19) { + return; + } + + // Test that when we receive an out of order stream RST we correctly adjust + // our connection level flow control receive window. + // On close, the stream should mark as consumed all bytes between the highest + // byte consumed so far and the final byte offset from the RST frame. + TestStream* stream = session_.CreateOutgoingDataStream(); + + const QuicStreamOffset kByteOffset = 1 + kInitialFlowControlWindowForTest / 2; + // Expect no stream WINDOW_UPDATE frames, as stream read side closed. + EXPECT_CALL(*connection_, SendWindowUpdate(stream->id(), _)).Times(0); + // We do expect a connection level WINDOW_UPDATE when the stream is reset. + EXPECT_CALL(*connection_, + SendWindowUpdate( + 0, kInitialFlowControlWindowForTest + kByteOffset)).Times(1); + + QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED, + kByteOffset); + session_.OnRstStream(rst_frame); + session_.PostProcessAfterData(); + EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed()); +} + +TEST_P(QuicSessionTest, ConnectionFlowControlAccountingFinAndLocalReset) { + FLAGS_enable_quic_stream_flow_control_2 = true; + FLAGS_enable_quic_connection_flow_control = true; + if (version() < QUIC_VERSION_19) { + return; + } + + // Test the situation where we receive a FIN on a stream, and before we fully + // consume all the data from the sequencer buffer we locally RST the stream. + // The bytes between highest consumed byte, and the final byte offset that we + // determined when the FIN arrived, should be marked as consumed at the + // connection level flow controller when the stream is reset. + TestStream* stream = session_.CreateOutgoingDataStream(); + + const QuicStreamOffset kByteOffset = 1 + kInitialFlowControlWindowForTest / 2; + QuicStreamFrame frame(stream->id(), true, kByteOffset, IOVector()); + vector<QuicStreamFrame> frames; + frames.push_back(frame); + session_.OnStreamFrames(frames); + session_.PostProcessAfterData(); + + EXPECT_EQ(0u, stream->flow_controller()->bytes_consumed()); + EXPECT_EQ(kByteOffset, + stream->flow_controller()->highest_received_byte_offset()); + + // Expect no stream WINDOW_UPDATE frames, as stream read side closed. + EXPECT_CALL(*connection_, SendWindowUpdate(stream->id(), _)).Times(0); + // We do expect a connection level WINDOW_UPDATE when the stream is reset. + EXPECT_CALL(*connection_, + SendWindowUpdate( + 0, kInitialFlowControlWindowForTest + kByteOffset)).Times(1); + + // Reset stream locally. + stream->Reset(QUIC_STREAM_CANCELLED); + + EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed()); +} + +TEST_P(QuicSessionTest, VersionNegotiationDisablesFlowControl) { + ValueRestore<bool> old_stream_flag( + &FLAGS_enable_quic_stream_flow_control_2, true); + ValueRestore<bool> old_connection_flag( + &FLAGS_enable_quic_connection_flow_control, true); + if (version() < QUIC_VERSION_19) { + return; + } + + // Test that after successful version negotiation, flow control is disabled + // appropriately at both the connection and stream level. + + // Initially both stream and connection flow control are enabled. + TestStream* stream = session_.CreateOutgoingDataStream(); + EXPECT_TRUE(stream->flow_controller()->IsEnabled()); + EXPECT_TRUE(session_.flow_controller()->IsEnabled()); + + // Version 17 implies that stream flow control is enabled, but connection + // level is disabled. + session_.OnSuccessfulVersionNegotiation(QUIC_VERSION_17); + EXPECT_FALSE(session_.flow_controller()->IsEnabled()); + EXPECT_TRUE(stream->flow_controller()->IsEnabled()); + + // Version 16 means all flow control is disabled. + session_.OnSuccessfulVersionNegotiation(QUIC_VERSION_16); + EXPECT_FALSE(session_.flow_controller()->IsEnabled()); + EXPECT_FALSE(stream->flow_controller()->IsEnabled()); +} + } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_types.cc b/net/quic/quic_types.cc new file mode 100644 index 0000000..cdfb36d --- /dev/null +++ b/net/quic/quic_types.cc @@ -0,0 +1,34 @@ +// 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_types.h" + +using std::ostream; + +namespace net { + +QuicConsumedData::QuicConsumedData(size_t bytes_consumed, + bool fin_consumed) + : bytes_consumed(bytes_consumed), + fin_consumed(fin_consumed) { +} + +ostream& operator<<(ostream& os, const QuicConsumedData& s) { + os << "bytes_consumed: " << s.bytes_consumed + << " fin_consumed: " << s.fin_consumed; + return os; +} + +WriteResult::WriteResult() + : status(WRITE_STATUS_ERROR), + bytes_written(0) { +} + +WriteResult::WriteResult(WriteStatus status, + int bytes_written_or_error_code) + : status(status), + bytes_written(bytes_written_or_error_code) { +} + +} // namespace net diff --git a/net/quic/quic_types.h b/net/quic/quic_types.h new file mode 100644 index 0000000..01415bc3 --- /dev/null +++ b/net/quic/quic_types.h @@ -0,0 +1,69 @@ +// 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_TYPES_H_ +#define NET_QUIC_QUIC_TYPES_H_ + +// This header defines some basic types that don't depend on quic_protocol.h, +// so that classes not directly related to the protocol wire format can avoid +// including quic_protocol.h. + +#include <stddef.h> +#include <ostream> + +#include "net/base/net_export.h" + +namespace net { + +// A struct for functions which consume data payloads and fins. +struct NET_EXPORT_PRIVATE QuicConsumedData { + QuicConsumedData(size_t bytes_consumed, bool fin_consumed); + + // By default, gtest prints the raw bytes of an object. The bool data + // member causes this object to have padding bytes, which causes the + // default gtest object printer to read uninitialize memory. So we need + // to teach gtest how to print this object. + NET_EXPORT_PRIVATE friend std::ostream& operator<<( + std::ostream& os, const QuicConsumedData& s); + + // How many bytes were consumed. + size_t bytes_consumed; + + // True if an incoming fin was consumed. + bool fin_consumed; +}; + +// QuicAsyncStatus enumerates the possible results of an asynchronous +// operation. +enum QuicAsyncStatus { + QUIC_SUCCESS = 0, + QUIC_FAILURE = 1, + // QUIC_PENDING results from an operation that will occur asynchonously. When + // the operation is complete, a callback's |Run| method will be called. + QUIC_PENDING = 2, +}; + +// TODO(wtc): see if WriteStatus can be replaced by QuicAsyncStatus. +enum WriteStatus { + WRITE_STATUS_OK, + WRITE_STATUS_BLOCKED, + WRITE_STATUS_ERROR, +}; + +// A struct used to return the result of write calls including either the number +// of bytes written or the error code, depending upon the status. +struct NET_EXPORT_PRIVATE WriteResult { + WriteResult(WriteStatus status, int bytes_written_or_error_code); + WriteResult(); + + WriteStatus status; + union { + int bytes_written; // only valid when status is WRITE_STATUS_OK + int error_code; // only valid when status is WRITE_STATUS_ERROR + }; +}; + +} // namespace net + +#endif // NET_QUIC_QUIC_TYPES_H_ diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc index b230485..e9dd136 100644 --- a/net/quic/quic_unacked_packet_map.cc +++ b/net/quic/quic_unacked_packet_map.cc @@ -57,7 +57,8 @@ void QuicUnackedPacketMap::AddPacket( void QuicUnackedPacketMap::OnRetransmittedPacket( QuicPacketSequenceNumber old_sequence_number, - QuicPacketSequenceNumber new_sequence_number) { + QuicPacketSequenceNumber new_sequence_number, + TransmissionType transmission_type) { DCHECK(ContainsKey(unacked_packets_, old_sequence_number)); DCHECK(unacked_packets_.empty() || unacked_packets_.rbegin()->first < new_sequence_number); @@ -77,6 +78,7 @@ void QuicUnackedPacketMap::OnRetransmittedPacket( TransmissionInfo(frames, new_sequence_number, transmission_info->sequence_number_length, + transmission_type, transmission_info->all_transmissions); } diff --git a/net/quic/quic_unacked_packet_map.h b/net/quic/quic_unacked_packet_map.h index 0263422..ae72548 100644 --- a/net/quic/quic_unacked_packet_map.h +++ b/net/quic/quic_unacked_packet_map.h @@ -27,7 +27,8 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap { // retransmittable data associated with it. |new_sequence_number| will // be both unacked and associated with retransmittable data. void OnRetransmittedPacket(QuicPacketSequenceNumber old_sequence_number, - QuicPacketSequenceNumber new_sequence_number); + QuicPacketSequenceNumber new_sequence_number, + TransmissionType transmission_type); // Returns true if the packet |sequence_number| is unacked. bool IsUnacked(QuicPacketSequenceNumber sequence_number) const; diff --git a/net/quic/quic_unacked_packet_map_test.cc b/net/quic/quic_unacked_packet_map_test.cc index 0ff0cf0..c5264fd1 100644 --- a/net/quic/quic_unacked_packet_map_test.cc +++ b/net/quic/quic_unacked_packet_map_test.cc @@ -130,7 +130,7 @@ TEST_F(QuicUnackedPacketMapTest, RetransmittedPacket) { // transmission being acked. unacked_packets_.AddPacket(CreateRetransmittablePacket(1)); unacked_packets_.SetSent(1, now_, kDefaultLength, true); - unacked_packets_.OnRetransmittedPacket(1, 2); + unacked_packets_.OnRetransmittedPacket(1, 2, LOSS_RETRANSMISSION); unacked_packets_.SetSent(2, now_, kDefaultLength, true); QuicPacketSequenceNumber unacked[] = { 1, 2 }; diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc index 3abc226..ae4bb2e 100644 --- a/net/quic/quic_utils.cc +++ b/net/quic/quic_utils.cc @@ -202,7 +202,9 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_PACKET_READ_ERROR); RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_FRAME); RETURN_STRING_LITERAL(QUIC_INVALID_HEADERS_STREAM_DATA); - RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_ERROR); + RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); + RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA); + RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_INVALID_WINDOW); RETURN_STRING_LITERAL(QUIC_CONNECTION_IP_POOLED); RETURN_STRING_LITERAL(QUIC_PROOF_INVALID); RETURN_STRING_LITERAL(QUIC_CRYPTO_DUPLICATE_TAG); diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index 64d8aae..b73185b 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc @@ -124,7 +124,7 @@ ReliableQuicStream::ReliableQuicStream(QuicStreamId id, QuicSession* session) rst_sent_(false), is_server_(session_->is_server()), flow_controller_( - session_->connection()->version(), + session_->connection(), id_, is_server_, session_->config()->HasReceivedInitialFlowControlWindowBytes() ? @@ -155,17 +155,18 @@ bool ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) { stream_bytes_read_ += frame_payload_size; // Flow control is interested in tracking highest received offset. - MaybeIncreaseHighestReceivedOffset(frame.offset + frame_payload_size); - - bool accepted = sequencer_.OnStreamFrame(frame); - - if (flow_controller_.FlowControlViolation() || - connection_flow_controller_->FlowControlViolation()) { - session_->connection()->SendConnectionClose(QUIC_FLOW_CONTROL_ERROR); - return false; + if (MaybeIncreaseHighestReceivedOffset(frame.offset + frame_payload_size)) { + // As the highest received offset has changed, we should check to see if + // this is a violation of flow control. + if (flow_controller_.FlowControlViolation() || + connection_flow_controller_->FlowControlViolation()) { + session_->connection()->SendConnectionClose( + QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); + return false; + } } - return accepted; + return sequencer_.OnStreamFrame(frame); } int ReliableQuicStream::num_frames_received() const { @@ -298,8 +299,8 @@ void ReliableQuicStream::OnCanWrite() { } void ReliableQuicStream::MaybeSendBlocked() { - flow_controller_.MaybeSendBlocked(session()->connection()); - connection_flow_controller_->MaybeSendBlocked(session()->connection()); + flow_controller_.MaybeSendBlocked(); + connection_flow_controller_->MaybeSendBlocked(); // If we are connection level flow control blocked, then add the stream // to the write blocked list. It will be given a chance to write when a // connection level WINDOW_UPDATE arrives. @@ -417,6 +418,14 @@ void ReliableQuicStream::OnClose() { stream_bytes_written_); rst_sent_ = true; } + + // We are closing the stream and will not process any further incoming bytes. + // As there may be more bytes in flight and we need to ensure that both + // endpoints have the same connection level flow control state, mark all + // unreceived or buffered bytes as consumed. + uint64 bytes_to_consume = flow_controller_.highest_received_byte_offset() - + flow_controller_.bytes_consumed(); + AddBytesConsumed(bytes_to_consume); } void ReliableQuicStream::OnWindowUpdateFrame( @@ -436,7 +445,7 @@ void ReliableQuicStream::OnWindowUpdateFrame( } } -void ReliableQuicStream::MaybeIncreaseHighestReceivedOffset(uint64 new_offset) { +bool ReliableQuicStream::MaybeIncreaseHighestReceivedOffset(uint64 new_offset) { if (flow_controller_.IsEnabled()) { uint64 increment = new_offset - flow_controller_.highest_received_byte_offset(); @@ -447,8 +456,10 @@ void ReliableQuicStream::MaybeIncreaseHighestReceivedOffset(uint64 new_offset) { connection_flow_controller_->UpdateHighestReceivedOffset( connection_flow_controller_->highest_received_byte_offset() + increment); + return true; } } + return false; } void ReliableQuicStream::AddBytesSent(uint64 bytes) { @@ -460,11 +471,12 @@ void ReliableQuicStream::AddBytesSent(uint64 bytes) { void ReliableQuicStream::AddBytesConsumed(uint64 bytes) { if (flow_controller_.IsEnabled()) { - flow_controller_.AddBytesConsumed(bytes); - flow_controller_.MaybeSendWindowUpdate(session()->connection()); + // Only adjust stream level flow controller if we are still reading. + if (!read_side_closed_) { + flow_controller_.AddBytesConsumed(bytes); + } connection_flow_controller_->AddBytesConsumed(bytes); - connection_flow_controller_->MaybeSendWindowUpdate(session()->connection()); } } diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h index 68ff6dd..9d8fe88 100644 --- a/net/quic/reliable_quic_stream.h +++ b/net/quic/reliable_quic_stream.h @@ -20,6 +20,7 @@ #include "net/quic/quic_flow_controller.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_stream_sequencer.h" +#include "net/quic/quic_types.h" namespace net { @@ -99,7 +100,8 @@ class NET_EXPORT_PRIVATE ReliableQuicStream { QuicFlowController* flow_controller() { return &flow_controller_; } // Called when we see a frame which could increase the highest offset. - void MaybeIncreaseHighestReceivedOffset(uint64 new_offset); + // Returns true if the highest offset did increase. + bool MaybeIncreaseHighestReceivedOffset(uint64 new_offset); // Called when bytese are sent to the peer. void AddBytesSent(uint64 bytes); // Called by the stream sequencer as bytes are consumed from the buffer. diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc index 2fc4e9d..5d1ea9d 100644 --- a/net/quic/reliable_quic_stream_test.cc +++ b/net/quic/reliable_quic_stream_test.cc @@ -557,6 +557,33 @@ TEST_F(ReliableQuicStreamTest, WriteAndBufferDataWithAckNotiferOnlyFinRemains) { proxy_delegate->OnAckNotification(10, 20, 30, 40, zero_); } + +// Verify that when we receive a packet which violates flow control (i.e. sends +// too much data on the stream) that the stream sequencer never sees this frame, +// as we check for violation and close the connection early. +TEST_F(ReliableQuicStreamTest, + StreamSequencerNeverSeesPacketsViolatingFlowControl) { + ValueRestore<bool> old_stream_flag( + &FLAGS_enable_quic_stream_flow_control_2, true); + ValueRestore<bool> old_connection_flag( + &FLAGS_enable_quic_connection_flow_control, true); + + Initialize(kShouldProcessData); + + // Receive a stream frame that violates flow control: the byte offset is + // higher than the receive window offset. + QuicStreamFrame frame(stream_->id(), false, + kInitialFlowControlWindowForTest + 1, + MakeIOVector(".")); + EXPECT_GT(frame.offset, QuicFlowControllerPeer::ReceiveWindowOffset( + stream_->flow_controller())); + + // Stream should not accept the frame, and the connection should be closed. + EXPECT_CALL(*connection_, + SendConnectionClose(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA)); + EXPECT_FALSE(stream_->OnStreamFrame(frame)); +} + } // namespace } // namespace test } // namespace net diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc index a8e1db5..9d7c83f 100644 --- a/net/quic/test_tools/quic_connection_peer.cc +++ b/net/quic/test_tools/quic_connection_peer.cc @@ -215,5 +215,11 @@ QuicEncryptedPacket* QuicConnectionPeer::GetConnectionClosePacket( return connection->connection_close_packet_.get(); } +// static +void QuicConnectionPeer::SetSupportedVersions(QuicConnection* connection, + QuicVersionVector versions) { + connection->framer_.SetSupportedVersions(versions); +} + } // namespace test } // namespace net diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h index 8c74c1a..cf0ea38a 100644 --- a/net/quic/test_tools/quic_connection_peer.h +++ b/net/quic/test_tools/quic_connection_peer.h @@ -108,6 +108,9 @@ class QuicConnectionPeer { static QuicEncryptedPacket* GetConnectionClosePacket( QuicConnection* connection); + static void SetSupportedVersions(QuicConnection* connection, + QuicVersionVector versions); + private: DISALLOW_COPY_AND_ASSIGN(QuicConnectionPeer); }; diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index 30bf282..39458e1 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc @@ -410,6 +410,12 @@ IPAddressNumber Loopback4() { return addr; } +IPAddressNumber Loopback6() { + IPAddressNumber addr; + CHECK(ParseIPLiteralToNumber("::1", &addr)); + return addr; +} + void GenerateBody(string* body, int length) { body->clear(); body->reserve(length); diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 5367c76..83d2837 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h @@ -49,6 +49,9 @@ QuicVersion QuicVersionMin(); // Returns an address for 127.0.0.1. IPAddressNumber Loopback4(); +// Returns an address for ::1. +IPAddressNumber Loopback6(); + void GenerateBody(std::string* body, int length); // Create an encrypted packet for testing. @@ -426,9 +429,10 @@ class MockSendAlgorithm : public SendAlgorithmInterface { bool(QuicTime, QuicByteCount, QuicPacketSequenceNumber, QuicByteCount, HasRetransmittableData)); MOCK_METHOD1(OnRetransmissionTimeout, void(bool)); - MOCK_METHOD3(TimeUntilSend, QuicTime::Delta(QuicTime now, - QuicByteCount bytes_in_flight, - HasRetransmittableData)); + MOCK_CONST_METHOD3(TimeUntilSend, + QuicTime::Delta(QuicTime now, + QuicByteCount bytes_in_flight, + HasRetransmittableData)); MOCK_CONST_METHOD0(BandwidthEstimate, QuicBandwidth(void)); MOCK_METHOD1(OnRttUpdated, void(QuicPacketSequenceNumber)); MOCK_CONST_METHOD0(RetransmissionDelay, QuicTime::Delta(void)); diff --git a/net/tools/quic/quic_packet_writer_wrapper.cc b/net/tools/quic/quic_packet_writer_wrapper.cc index e4e8a40..3d1b03d 100644 --- a/net/tools/quic/quic_packet_writer_wrapper.cc +++ b/net/tools/quic/quic_packet_writer_wrapper.cc @@ -4,7 +4,7 @@ #include "net/tools/quic/quic_packet_writer_wrapper.h" -#include "net/quic/quic_protocol.h" +#include "net/quic/quic_types.h" namespace net { namespace tools { diff --git a/net/tools/quic/quic_socket_utils.h b/net/tools/quic/quic_socket_utils.h index de4f7af..697e955 100644 --- a/net/tools/quic/quic_socket_utils.h +++ b/net/tools/quic/quic_socket_utils.h @@ -11,8 +11,9 @@ #include <sys/socket.h> #include <string> +#include "base/basictypes.h" #include "net/base/ip_endpoint.h" -#include "net/quic/quic_protocol.h" +#include "net/quic/quic_types.h" namespace net { namespace tools { diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc index 625cf1a..51f599d 100644 --- a/net/tools/quic/test_tools/quic_test_client.cc +++ b/net/tools/quic/test_tools/quic_test_client.cc @@ -38,17 +38,18 @@ namespace { class RecordingProofVerifier : public ProofVerifier { public: // ProofVerifier interface. - virtual Status VerifyProof(const string& hostname, - const string& server_config, - const vector<string>& certs, - const string& signature, - const ProofVerifyContext* context, - string* error_details, - scoped_ptr<ProofVerifyDetails>* details, - ProofVerifierCallback* callback) OVERRIDE { + virtual QuicAsyncStatus VerifyProof( + const string& hostname, + const string& server_config, + const vector<string>& certs, + const string& signature, + const ProofVerifyContext* context, + string* error_details, + scoped_ptr<ProofVerifyDetails>* details, + ProofVerifierCallback* callback) OVERRIDE { common_name_.clear(); if (certs.empty()) { - return FAILURE; + return QUIC_FAILURE; } // Convert certs to X509Certificate. @@ -59,11 +60,11 @@ class RecordingProofVerifier : public ProofVerifier { scoped_refptr<net::X509Certificate> cert = net::X509Certificate::CreateFromDERCertChain(cert_pieces); if (!cert.get()) { - return FAILURE; + return QUIC_FAILURE; } common_name_ = cert->subject().GetDisplayName(); - return SUCCESS; + return QUIC_SUCCESS; } const string& common_name() const { return common_name_; } |