diff options
Diffstat (limited to 'net/quic')
80 files changed, 4307 insertions, 1500 deletions
diff --git a/net/quic/congestion_control/cubic.cc b/net/quic/congestion_control/cubic.cc index c1faeb3..1c41500 100644 --- a/net/quic/congestion_control/cubic.cc +++ b/net/quic/congestion_control/cubic.cc @@ -134,12 +134,11 @@ QuicTcpCongestionWindow Cubic::CongestionWindowAfterAck( QuicTcpCongestionWindow current_congestion_window, QuicTime::Delta delay_min) { acked_packets_count_ += 1; // Packets acked. - QuicTime current_time = clock_->Now(); + QuicTime current_time = clock_->ApproximateNow(); // Cubic is "independent" of RTT, the update is limited by the time elapsed. if (last_congestion_window_ == current_congestion_window && (current_time.Subtract(last_update_time_) <= MaxCubicTimeInterval())) { - DCHECK(epoch_.IsInitialized()); return std::max(last_target_congestion_window_, estimated_tcp_congestion_window_); } diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc index 2738526..34addfc 100644 --- a/net/quic/congestion_control/fix_rate_sender.cc +++ b/net/quic/congestion_control/fix_rate_sender.cc @@ -18,21 +18,23 @@ namespace net { FixRateSender::FixRateSender(const QuicClock* clock) : bitrate_(QuicBandwidth::FromBytesPerSecond(kInitialBitrate)), - fix_rate_leaky_bucket_(clock, bitrate_), - paced_sender_(clock, bitrate_), + fix_rate_leaky_bucket_(bitrate_), + paced_sender_(bitrate_), data_in_flight_(0) { DLOG(INFO) << "FixRateSender"; } void FixRateSender::OnIncomingQuicCongestionFeedbackFrame( const QuicCongestionFeedbackFrame& feedback, + QuicTime feedback_receive_time, + QuicBandwidth /*sent_bandwidth*/, const SentPacketsMap& /*sent_packets*/) { DCHECK(feedback.type == kFixRate) << "Invalid incoming CongestionFeedbackType:" << feedback.type; if (feedback.type == kFixRate) { bitrate_ = feedback.fix_rate.bitrate; - fix_rate_leaky_bucket_.SetDrainingRate(bitrate_); - paced_sender_.UpdateBandwidthEstimate(bitrate_); + fix_rate_leaky_bucket_.SetDrainingRate(feedback_receive_time, bitrate_); + paced_sender_.UpdateBandwidthEstimate(feedback_receive_time, bitrate_); } // Silently ignore invalid messages in release mode. } @@ -44,34 +46,36 @@ void FixRateSender::OnIncomingAck( data_in_flight_ -= bytes_acked; } -void FixRateSender::OnIncomingLoss(int /*number_of_lost_packets*/) { +void FixRateSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) { // Ignore losses for fix rate sender. } -void FixRateSender::SentPacket(QuicPacketSequenceNumber /*sequence_number*/, +void FixRateSender::SentPacket(QuicTime sent_time, + QuicPacketSequenceNumber /*sequence_number*/, QuicByteCount bytes, bool is_retransmission) { - fix_rate_leaky_bucket_.Add(bytes); - paced_sender_.SentPacket(bytes); + fix_rate_leaky_bucket_.Add(sent_time, bytes); + paced_sender_.SentPacket(sent_time, bytes); if (!is_retransmission) { data_in_flight_ += bytes; } } -QuicTime::Delta FixRateSender::TimeUntilSend(bool /*is_retransmission*/) { - if (CongestionWindow() > fix_rate_leaky_bucket_.BytesPending()) { +QuicTime::Delta FixRateSender::TimeUntilSend(QuicTime now, + bool /*is_retransmission*/) { + if (CongestionWindow() > fix_rate_leaky_bucket_.BytesPending(now)) { if (CongestionWindow() <= data_in_flight_) { // We need an ack before we send more. return QuicTime::Delta::Infinite(); } - return paced_sender_.TimeUntilSend(QuicTime::Delta::Zero()); + return paced_sender_.TimeUntilSend(now, QuicTime::Delta::Zero()); } - QuicTime::Delta time_remaining = fix_rate_leaky_bucket_.TimeRemaining(); + 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(time_remaining); + return paced_sender_.TimeUntilSend(now, time_remaining); } QuicByteCount FixRateSender::CongestionWindow() { @@ -81,16 +85,6 @@ QuicByteCount FixRateSender::CongestionWindow() { return std::max(kMaxPacketSize, window_size_bytes); } -QuicByteCount FixRateSender::AvailableCongestionWindow() { - QuicByteCount congestion_window = CongestionWindow(); - if (data_in_flight_ >= congestion_window) { - return 0; - } - QuicByteCount available_congestion_window = congestion_window - - data_in_flight_; - return paced_sender_.AvailableWindow(available_congestion_window); -} - QuicBandwidth FixRateSender::BandwidthEstimate() { return bitrate_; } diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h index 4e864b7..336352f 100644 --- a/net/quic/congestion_control/fix_rate_sender.h +++ b/net/quic/congestion_control/fix_rate_sender.h @@ -18,33 +18,31 @@ namespace net { -namespace test { -class FixRateSenderPeer; -} // namespace test - class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface { + public: explicit FixRateSender(const QuicClock* clock); // Start implementation of SendAlgorithmInterface. virtual void OnIncomingQuicCongestionFeedbackFrame( const QuicCongestionFeedbackFrame& feedback, + QuicTime feedback_receive_time, + QuicBandwidth sent_bandwidth, const SentPacketsMap& sent_packets) OVERRIDE; virtual void OnIncomingAck(QuicPacketSequenceNumber acked_sequence_number, QuicByteCount acked_bytes, QuicTime::Delta rtt) OVERRIDE; - virtual void OnIncomingLoss(int number_of_lost_packets) OVERRIDE; - virtual void SentPacket(QuicPacketSequenceNumber equence_number, + virtual void OnIncomingLoss(QuicTime ack_receive_time) OVERRIDE; + virtual void SentPacket(QuicTime sent_time, + QuicPacketSequenceNumber equence_number, QuicByteCount bytes, bool is_retransmission) OVERRIDE; - virtual QuicTime::Delta TimeUntilSend(bool is_retransmission) OVERRIDE; + virtual QuicTime::Delta TimeUntilSend(QuicTime now, + bool is_retransmission) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() OVERRIDE; // End implementation of SendAlgorithmInterface. private: - friend class test::FixRateSenderPeer; - - QuicByteCount AvailableCongestionWindow(); QuicByteCount CongestionWindow(); QuicBandwidth bitrate_; diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc index 2c0770a..a4ff5ba 100644 --- a/net/quic/congestion_control/fix_rate_test.cc +++ b/net/quic/congestion_control/fix_rate_test.cc @@ -1,8 +1,6 @@ // 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. -// -// Test for FixRate sender and receiver. #include "base/logging.h" #include "base/memory/scoped_ptr.h" @@ -10,19 +8,12 @@ #include "net/quic/congestion_control/fix_rate_sender.h" #include "net/quic/test_tools/mock_clock.h" #include "net/quic/quic_protocol.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { namespace test { -class FixRateSenderPeer : public FixRateSender { - public: - explicit FixRateSenderPeer(const QuicClock* clock) - : FixRateSender(clock) { - } - using FixRateSender::AvailableCongestionWindow; -}; - class FixRateReceiverPeer : public FixRateReceiver { public: FixRateReceiverPeer() @@ -37,15 +28,17 @@ class FixRateTest : public ::testing::Test { protected: FixRateTest() : rtt_(QuicTime::Delta::FromMilliseconds(30)), - sender_(new FixRateSenderPeer(&clock_)), + unused_bandwidth_(QuicBandwidth::Zero()), + sender_(new FixRateSender(&clock_)), receiver_(new FixRateReceiverPeer()) { // Make sure clock does not start at 0. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2)); } const QuicTime::Delta rtt_; + const QuicBandwidth unused_bandwidth_; MockClock clock_; - SendAlgorithmInterface::SentPacketsMap not_used_; - scoped_ptr<FixRateSenderPeer> sender_; + SendAlgorithmInterface::SentPacketsMap unused_packet_map_; + scoped_ptr<FixRateSender> sender_; scoped_ptr<FixRateReceiverPeer> receiver_; }; @@ -63,27 +56,24 @@ TEST_F(FixRateTest, SenderAPI) { QuicCongestionFeedbackFrame feedback; feedback.type = kFixRate; feedback.fix_rate.bitrate = QuicBandwidth::FromKBytesPerSecond(300); - sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_); + sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(), + unused_bandwidth_, unused_packet_map_); EXPECT_EQ(300000, sender_->BandwidthEstimate().ToBytesPerSecond()); - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); - EXPECT_EQ(kMaxPacketSize * 2, - sender_->AvailableCongestionWindow()); - sender_->SentPacket(1, kMaxPacketSize, false); - EXPECT_EQ(3000u - kMaxPacketSize, - sender_->AvailableCongestionWindow()); - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); - sender_->SentPacket(2, kMaxPacketSize, false); - sender_->SentPacket(3, 600, false); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); + sender_->SentPacket(clock_.Now(), 1, kMaxPacketSize, false); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); + sender_->SentPacket(clock_.Now(), 2, kMaxPacketSize, false); + sender_->SentPacket(clock_.Now(), 3, 600, false); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), - sender_->TimeUntilSend(false)); - EXPECT_EQ(0u, sender_->AvailableCongestionWindow()); + sender_->TimeUntilSend(clock_.Now(), false)); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2)); - EXPECT_EQ(QuicTime::Delta::Infinite(), sender_->TimeUntilSend(false)); + EXPECT_EQ(QuicTime::Delta::Infinite(), + sender_->TimeUntilSend(clock_.Now(), false)); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8)); sender_->OnIncomingAck(1, kMaxPacketSize, rtt_); sender_->OnIncomingAck(2, kMaxPacketSize, rtt_); sender_->OnIncomingAck(3, 600, rtt_); - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); } TEST_F(FixRateTest, FixRatePacing) { @@ -93,17 +83,16 @@ TEST_F(FixRateTest, FixRatePacing) { QuicCongestionFeedbackFrame feedback; receiver_->SetBitrate(QuicBandwidth::FromKBytesPerSecond(240)); ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); - sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_); + sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(), + unused_bandwidth_, unused_packet_map_); QuicTime acc_advance_time(QuicTime::Zero()); QuicPacketSequenceNumber sequence_number = 0; - for (int64 i = 0; i < num_packets; i += 2) { - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); - EXPECT_EQ(kMaxPacketSize * 2, - sender_->AvailableCongestionWindow()); - sender_->SentPacket(sequence_number++, packet_size, false); - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); - sender_->SentPacket(sequence_number++, packet_size, false); - QuicTime::Delta advance_time = sender_->TimeUntilSend(false); + for (int i = 0; i < num_packets; i += 2) { + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); + sender_->SentPacket(clock_.Now(), sequence_number++, packet_size, false); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); + sender_->SentPacket(clock_.Now(), sequence_number++, packet_size, false); + QuicTime::Delta advance_time = sender_->TimeUntilSend(clock_.Now(), false); clock_.AdvanceTime(advance_time); sender_->OnIncomingAck(sequence_number - 1, packet_size, rtt_); sender_->OnIncomingAck(sequence_number - 2, packet_size, rtt_); diff --git a/net/quic/congestion_control/hybrid_slow_start.cc b/net/quic/congestion_control/hybrid_slow_start.cc index cbdd1bb..8a42524 100644 --- a/net/quic/congestion_control/hybrid_slow_start.cc +++ b/net/quic/congestion_control/hybrid_slow_start.cc @@ -33,7 +33,7 @@ void HybridSlowStart::Restart() { void HybridSlowStart::Reset(QuicPacketSequenceNumber end_sequence_number) { DLOG(INFO) << "Reset hybrid slow start @" << end_sequence_number; - round_start_ = last_time_ = clock_->Now(); + round_start_ = last_time_ = clock_->ApproximateNow(); end_sequence_number_ = end_sequence_number; current_rtt_ = QuicTime::Delta::Zero(); sample_count_ = 0; @@ -52,7 +52,7 @@ void HybridSlowStart::Update(QuicTime::Delta rtt, QuicTime::Delta delay_min) { if (found_ack_train_ || found_delay_) { return; } - QuicTime current_time = clock_->Now(); + QuicTime current_time = clock_->ApproximateNow(); // First detection parameter - ack-train detection. // Since slow start burst out packets we can indirectly estimate the inter- diff --git a/net/quic/congestion_control/leaky_bucket.cc b/net/quic/congestion_control/leaky_bucket.cc index 0012ae8..8556810 100644 --- a/net/quic/congestion_control/leaky_bucket.cc +++ b/net/quic/congestion_control/leaky_bucket.cc @@ -8,37 +8,35 @@ namespace net { -LeakyBucket::LeakyBucket(const QuicClock* clock, QuicBandwidth draining_rate) - : clock_(clock), - bytes_(0), +LeakyBucket::LeakyBucket(QuicBandwidth draining_rate) + : bytes_(0), time_last_updated_(QuicTime::Zero()), draining_rate_(draining_rate) { } -void LeakyBucket::SetDrainingRate(QuicBandwidth draining_rate) { - Update(); +void LeakyBucket::SetDrainingRate(QuicTime now, QuicBandwidth draining_rate) { + Update(now); draining_rate_ = draining_rate; } -void LeakyBucket::Add(QuicByteCount bytes) { - Update(); +void LeakyBucket::Add(QuicTime now, QuicByteCount bytes) { + Update(now); bytes_ += bytes; } -QuicTime::Delta LeakyBucket::TimeRemaining() { - Update(); +QuicTime::Delta LeakyBucket::TimeRemaining(QuicTime now) { + Update(now); return QuicTime::Delta::FromMicroseconds( (bytes_ * base::Time::kMicrosecondsPerSecond) / draining_rate_.ToBytesPerSecond()); } -QuicByteCount LeakyBucket::BytesPending() { - Update(); +QuicByteCount LeakyBucket::BytesPending(QuicTime now) { + Update(now); return bytes_; } -void LeakyBucket::Update() { - QuicTime now = clock_->Now(); +void LeakyBucket::Update(QuicTime now) { QuicTime::Delta elapsed_time = now.Subtract(time_last_updated_); QuicByteCount bytes_cleared = draining_rate_.ToBytesPerPeriod(elapsed_time); if (bytes_cleared >= bytes_) { diff --git a/net/quic/congestion_control/leaky_bucket.h b/net/quic/congestion_control/leaky_bucket.h index be138982..63ef810 100644 --- a/net/quic/congestion_control/leaky_bucket.h +++ b/net/quic/congestion_control/leaky_bucket.h @@ -21,25 +21,23 @@ namespace net { class NET_EXPORT_PRIVATE LeakyBucket { public: - // clock is not owned by this class. - LeakyBucket(const QuicClock* clock, QuicBandwidth draining_rate); + explicit LeakyBucket(QuicBandwidth draining_rate); // Set the rate at which the bytes leave the buffer. - void SetDrainingRate(QuicBandwidth draining_rate); + void SetDrainingRate(QuicTime now, QuicBandwidth draining_rate); // Add data to the buffer. - void Add(QuicByteCount bytes); + void Add(QuicTime now, QuicByteCount bytes); - // Time until the buffer is empty in us. - QuicTime::Delta TimeRemaining(); + // Time until the buffer is empty. + QuicTime::Delta TimeRemaining(QuicTime now); // Number of bytes in the buffer. - QuicByteCount BytesPending(); + QuicByteCount BytesPending(QuicTime now); private: - void Update(); + void Update(QuicTime now); - const QuicClock* clock_; QuicByteCount bytes_; QuicTime time_last_updated_; QuicBandwidth draining_rate_; diff --git a/net/quic/congestion_control/leaky_bucket_test.cc b/net/quic/congestion_control/leaky_bucket_test.cc index 89ab5db..b542370 100644 --- a/net/quic/congestion_control/leaky_bucket_test.cc +++ b/net/quic/congestion_control/leaky_bucket_test.cc @@ -13,8 +13,8 @@ namespace test { class LeakyBucketTest : public ::testing::Test { protected: - virtual void SetUp() { - leaky_bucket_.reset(new LeakyBucket(&clock_, QuicBandwidth::Zero())); + void SetUp() { + leaky_bucket_.reset(new LeakyBucket(QuicBandwidth::Zero())); } MockClock clock_; scoped_ptr<LeakyBucket> leaky_bucket_; @@ -22,53 +22,53 @@ class LeakyBucketTest : public ::testing::Test { TEST_F(LeakyBucketTest, Basic) { QuicBandwidth draining_rate = QuicBandwidth::FromBytesPerSecond(200000); - leaky_bucket_->SetDrainingRate(draining_rate); - leaky_bucket_->Add(2000); - EXPECT_EQ(2000u, leaky_bucket_->BytesPending()); + leaky_bucket_->SetDrainingRate(clock_.Now(), draining_rate); + leaky_bucket_->Add(clock_.Now(), 2000); + EXPECT_EQ(2000u, leaky_bucket_->BytesPending(clock_.Now())); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), - leaky_bucket_->TimeRemaining()); + leaky_bucket_->TimeRemaining(clock_.Now())); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - EXPECT_EQ(1000u, leaky_bucket_->BytesPending()); + EXPECT_EQ(1000u, leaky_bucket_->BytesPending(clock_.Now())); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(5), - leaky_bucket_->TimeRemaining()); + leaky_bucket_->TimeRemaining(clock_.Now())); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - EXPECT_EQ(0u, leaky_bucket_->BytesPending()); - EXPECT_TRUE(leaky_bucket_->TimeRemaining().IsZero()); + EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now())); + EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero()); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - EXPECT_EQ(0u, leaky_bucket_->BytesPending()); - EXPECT_TRUE(leaky_bucket_->TimeRemaining().IsZero()); - leaky_bucket_->Add(2000); + EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now())); + EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero()); + leaky_bucket_->Add(clock_.Now(), 2000); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(11)); - EXPECT_EQ(0u, leaky_bucket_->BytesPending()); - EXPECT_TRUE(leaky_bucket_->TimeRemaining().IsZero()); - leaky_bucket_->Add(2000); + EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now())); + EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero()); + leaky_bucket_->Add(clock_.Now(), 2000); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - leaky_bucket_->Add(2000); + leaky_bucket_->Add(clock_.Now(), 2000); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - EXPECT_EQ(2000u, leaky_bucket_->BytesPending()); + EXPECT_EQ(2000u, leaky_bucket_->BytesPending(clock_.Now())); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), - leaky_bucket_->TimeRemaining()); + leaky_bucket_->TimeRemaining(clock_.Now())); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); - EXPECT_EQ(0u, leaky_bucket_->BytesPending()); - EXPECT_TRUE(leaky_bucket_->TimeRemaining().IsZero()); + EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now())); + EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero()); } TEST_F(LeakyBucketTest, ChangeDrainRate) { QuicBandwidth draining_rate = QuicBandwidth::FromBytesPerSecond(200000); - leaky_bucket_->SetDrainingRate(draining_rate); - leaky_bucket_->Add(2000); - EXPECT_EQ(2000u, leaky_bucket_->BytesPending()); + leaky_bucket_->SetDrainingRate(clock_.Now(), draining_rate); + leaky_bucket_->Add(clock_.Now(), 2000); + EXPECT_EQ(2000u, leaky_bucket_->BytesPending(clock_.Now())); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), - leaky_bucket_->TimeRemaining()); + leaky_bucket_->TimeRemaining(clock_.Now())); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - EXPECT_EQ(1000u, leaky_bucket_->BytesPending()); + EXPECT_EQ(1000u, leaky_bucket_->BytesPending(clock_.Now())); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(5), - leaky_bucket_->TimeRemaining()); + leaky_bucket_->TimeRemaining(clock_.Now())); draining_rate = draining_rate.Scale(0.5f); // Cut drain rate in half. - leaky_bucket_->SetDrainingRate(draining_rate); - EXPECT_EQ(1000u, leaky_bucket_->BytesPending()); + leaky_bucket_->SetDrainingRate(clock_.Now(), draining_rate); + EXPECT_EQ(1000u, leaky_bucket_->BytesPending(clock_.Now())); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), - leaky_bucket_->TimeRemaining()); + leaky_bucket_->TimeRemaining(clock_.Now())); } } // namespace test diff --git a/net/quic/congestion_control/paced_sender.cc b/net/quic/congestion_control/paced_sender.cc index f44aa33..dd116a8 100644 --- a/net/quic/congestion_control/paced_sender.cc +++ b/net/quic/congestion_control/paced_sender.cc @@ -14,21 +14,23 @@ const int64 kMinPacketBurstSize = 2; // AvailableCongestionWindow. const int64 kMaxSchedulingDelayUs = 2000; -PacedSender::PacedSender(const QuicClock* clock, QuicBandwidth estimate) - : leaky_bucket_(clock, estimate), +PacedSender::PacedSender(QuicBandwidth estimate) + : leaky_bucket_(estimate), pace_(estimate) { } -void PacedSender::UpdateBandwidthEstimate(QuicBandwidth estimate) { - leaky_bucket_.SetDrainingRate(estimate); +void PacedSender::UpdateBandwidthEstimate(QuicTime now, + QuicBandwidth estimate) { + leaky_bucket_.SetDrainingRate(now, estimate); pace_ = estimate; } -void PacedSender::SentPacket(QuicByteCount bytes) { - leaky_bucket_.Add(bytes); +void PacedSender::SentPacket(QuicTime now, QuicByteCount bytes) { + leaky_bucket_.Add(now, bytes); } -QuicTime::Delta PacedSender::TimeUntilSend(QuicTime::Delta time_until_send) { +QuicTime::Delta PacedSender::TimeUntilSend(QuicTime now, + QuicTime::Delta time_until_send) { if (time_until_send.ToMicroseconds() >= kMaxSchedulingDelayUs) { return time_until_send; } @@ -38,36 +40,11 @@ QuicTime::Delta PacedSender::TimeUntilSend(QuicTime::Delta time_until_send) { QuicByteCount min_window_size = kMinPacketBurstSize * kMaxPacketSize; pacing_window = std::max(pacing_window, min_window_size); - if (pacing_window > leaky_bucket_.BytesPending()) { + if (pacing_window > leaky_bucket_.BytesPending(now)) { // We have not filled our pacing window yet. return time_until_send; } - return leaky_bucket_.TimeRemaining(); -} - -QuicByteCount PacedSender::AvailableWindow( - QuicByteCount available_congestion_window) { - QuicByteCount accuracy_window = pace_.ToBytesPerPeriod( - QuicTime::Delta::FromMicroseconds(kMaxSchedulingDelayUs)); - QuicByteCount min_burst_window = kMinPacketBurstSize * kMaxPacketSize; - DLOG(INFO) << "Available congestion window:" << available_congestion_window - << " accuracy window:" << accuracy_window - << " min burst window:" << min_burst_window; - - // Should we limit the window to pace the data? - if (available_congestion_window > min_burst_window && - available_congestion_window > accuracy_window) { - // Max window depends on estimated bandwidth; higher bandwidth => larger - // burst we also consider our timing accuracy. An accuracy of 1 ms will - // allow us to send up to 19.2Mbit/s with 2 packets per burst. - available_congestion_window = std::max(min_burst_window, accuracy_window); - QuicByteCount bytes_pending = leaky_bucket_.BytesPending(); - if (bytes_pending > available_congestion_window) { - return 0; - } - available_congestion_window -= bytes_pending; - } - return available_congestion_window; + 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 index af3adaf..5f61b76 100644 --- a/net/quic/congestion_control/paced_sender.h +++ b/net/quic/congestion_control/paced_sender.h @@ -11,28 +11,22 @@ #include "net/base/net_export.h" #include "net/quic/congestion_control/leaky_bucket.h" #include "net/quic/quic_bandwidth.h" -#include "net/quic/quic_clock.h" #include "net/quic/quic_time.h" namespace net { class NET_EXPORT_PRIVATE PacedSender { public: - PacedSender(const QuicClock* clock, QuicBandwidth bandwidth_estimate); + explicit PacedSender(QuicBandwidth bandwidth_estimate); // The estimated bandidth from the congestion algorithm changed. - void UpdateBandwidthEstimate(QuicBandwidth bandwidth_estimate); + void UpdateBandwidthEstimate(QuicTime now, QuicBandwidth bandwidth_estimate); // A packet of size bytes was sent. - void SentPacket(QuicByteCount bytes); + void SentPacket(QuicTime now, QuicByteCount bytes); // Return time until we can send based on the pacing. - QuicTime::Delta TimeUntilSend(QuicTime::Delta time_until_send); - - // Return the amount of data in bytes we can send based on the pacing. - // available_congestion_window is the congestion algorithms available - // congestion window in bytes. - QuicByteCount AvailableWindow(QuicByteCount available_congestion_window); + QuicTime::Delta TimeUntilSend(QuicTime now, QuicTime::Delta time_until_send); private: // Helper object to track the rate data can leave the buffer for pacing. diff --git a/net/quic/congestion_control/paced_sender_test.cc b/net/quic/congestion_control/paced_sender_test.cc index d2432aa..cc9297f 100644 --- a/net/quic/congestion_control/paced_sender_test.cc +++ b/net/quic/congestion_control/paced_sender_test.cc @@ -19,7 +19,7 @@ class PacedSenderTest : public ::testing::Test { protected: PacedSenderTest() : zero_time_(QuicTime::Delta::Zero()), - paced_sender_(new PacedSender(&clock_, + paced_sender_(new PacedSender( QuicBandwidth::FromKBytesPerSecond(kHundredKBytesPerS))) { } @@ -29,59 +29,48 @@ class PacedSenderTest : public ::testing::Test { }; TEST_F(PacedSenderTest, Basic) { - paced_sender_->UpdateBandwidthEstimate( + paced_sender_->UpdateBandwidthEstimate(clock_.Now(), QuicBandwidth::FromKBytesPerSecond(kHundredKBytesPerS * 10)); - EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero()); - EXPECT_EQ(kMaxPacketSize * 2, - paced_sender_->AvailableWindow(kMaxPacketSize * 4)); - paced_sender_->SentPacket(kMaxPacketSize); - EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero()); - paced_sender_->SentPacket(kMaxPacketSize); + EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); + paced_sender_->SentPacket(clock_.Now(), kMaxPacketSize); + EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); + paced_sender_->SentPacket(clock_.Now(), kMaxPacketSize); EXPECT_EQ(static_cast<int64>(kMaxPacketSize * 2), - paced_sender_->TimeUntilSend(zero_time_).ToMicroseconds()); - EXPECT_EQ(0u, paced_sender_->AvailableWindow(kMaxPacketSize * 4)); + paced_sender_->TimeUntilSend( + clock_.Now(), zero_time_).ToMicroseconds()); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(24)); - EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero()); - EXPECT_EQ(kMaxPacketSize * 2u, - paced_sender_->AvailableWindow(kMaxPacketSize * 4)); + EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); } TEST_F(PacedSenderTest, LowRate) { - paced_sender_->UpdateBandwidthEstimate( + paced_sender_->UpdateBandwidthEstimate(clock_.Now(), QuicBandwidth::FromKBytesPerSecond(kHundredKBytesPerS)); - EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero()); - size_t window = paced_sender_->AvailableWindow(kMaxPacketSize * 4); - EXPECT_EQ(kMaxPacketSize * 2, window); - paced_sender_->SentPacket(kMaxPacketSize); - EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero()); - paced_sender_->SentPacket(kMaxPacketSize); + EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); + paced_sender_->SentPacket(clock_.Now(), kMaxPacketSize); + EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); + paced_sender_->SentPacket(clock_.Now(), kMaxPacketSize); EXPECT_EQ(static_cast<int64>(kMaxPacketSize * 20), - paced_sender_->TimeUntilSend(zero_time_).ToMicroseconds()); - EXPECT_EQ(0u, paced_sender_->AvailableWindow(kMaxPacketSize * 4)); + paced_sender_->TimeUntilSend( + clock_.Now(), zero_time_).ToMicroseconds()); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(24)); - EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero()); - EXPECT_EQ(kMaxPacketSize * 2, - paced_sender_->AvailableWindow(kMaxPacketSize * 4)); + EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); } TEST_F(PacedSenderTest, HighRate) { QuicBandwidth bandwidth_estimate = QuicBandwidth::FromKBytesPerSecond( kHundredKBytesPerS * 100); - paced_sender_->UpdateBandwidthEstimate(bandwidth_estimate); - EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero()); - EXPECT_EQ(static_cast<uint64>(bandwidth_estimate.ToBytesPerSecond() / 500u), - paced_sender_->AvailableWindow(kMaxPacketSize * 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_->SentPacket(kMaxPacketSize); - EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero()); + paced_sender_->SentPacket(clock_.Now(), kMaxPacketSize); + EXPECT_TRUE(paced_sender_->TimeUntilSend( + clock_.Now(), zero_time_).IsZero()); } - paced_sender_->SentPacket(kMaxPacketSize); - EXPECT_EQ(0u, paced_sender_->AvailableWindow(kMaxPacketSize * 100)); - EXPECT_EQ(2040, paced_sender_->TimeUntilSend(zero_time_).ToMicroseconds()); + paced_sender_->SentPacket(clock_.Now(), kMaxPacketSize); + EXPECT_EQ(2040, paced_sender_->TimeUntilSend( + clock_.Now(), zero_time_).ToMicroseconds()); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(20400)); - EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero()); - EXPECT_EQ(static_cast<uint64>(bandwidth_estimate.ToBytesPerSecond() / 500u), - paced_sender_->AvailableWindow(kMaxPacketSize * 100)); + EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero()); } } // namespace test diff --git a/net/quic/congestion_control/quic_congestion_manager.cc b/net/quic/congestion_control/quic_congestion_manager.cc index 238b5c7..64e73bb 100644 --- a/net/quic/congestion_control/quic_congestion_manager.cc +++ b/net/quic/congestion_control/quic_congestion_manager.cc @@ -12,12 +12,13 @@ #include "net/quic/congestion_control/send_algorithm_interface.h" namespace { -const int kBitrateSmoothingPeriodMs = 3000; +const int kBitrateSmoothingPeriodMs = 1000; const int kMinBitrateSmoothingPeriodMs = 500; const int kHistoryPeriodMs = 5000; const int kDefaultRetransmissionTimeMs = 500; -const size_t kMaxRetransmissions = 15; +const size_t kMaxRetransmissions = 10; +const size_t kTailDropWindowSize = 5; COMPILE_ASSERT(kHistoryPeriodMs >= kBitrateSmoothingPeriodMs, history_must_be_longer_or_equal_to_the_smoothing_period); @@ -33,7 +34,8 @@ QuicCongestionManager::QuicCongestionManager( CongestionFeedbackType type) : clock_(clock), receive_algorithm_(ReceiveAlgorithmInterface::Create(clock, type)), - send_algorithm_(SendAlgorithmInterface::Create(clock, type)) { + send_algorithm_(SendAlgorithmInterface::Create(clock, type)), + largest_missing_(0) { } QuicCongestionManager::~QuicCongestionManager() { @@ -41,32 +43,36 @@ QuicCongestionManager::~QuicCongestionManager() { } void QuicCongestionManager::SentPacket(QuicPacketSequenceNumber sequence_number, + QuicTime sent_time, QuicByteCount bytes, bool is_retransmission) { DCHECK(!ContainsKey(pending_packets_, sequence_number)); - send_algorithm_->SentPacket(sequence_number, bytes, is_retransmission); + send_algorithm_->SentPacket(sent_time, sequence_number, bytes, + is_retransmission); packet_history_map_[sequence_number] = - new class SendAlgorithmInterface::SentPacket(bytes, clock_->Now()); + new class SendAlgorithmInterface::SentPacket(bytes, sent_time); pending_packets_[sequence_number] = bytes; CleanupPacketHistory(); - DLOG(INFO) << "Sent sequence number:" << sequence_number; } void QuicCongestionManager::OnIncomingQuicCongestionFeedbackFrame( - const QuicCongestionFeedbackFrame& frame) { - send_algorithm_->OnIncomingQuicCongestionFeedbackFrame(frame, - packet_history_map_); + const QuicCongestionFeedbackFrame& frame, QuicTime feedback_receive_time) { + QuicBandwidth sent_bandwidth = SentBandwidth(feedback_receive_time); + send_algorithm_->OnIncomingQuicCongestionFeedbackFrame( + frame, feedback_receive_time, sent_bandwidth, packet_history_map_); } -void QuicCongestionManager::OnIncomingAckFrame(const QuicAckFrame& frame) { +void QuicCongestionManager::OnIncomingAckFrame(const QuicAckFrame& frame, + QuicTime ack_receive_time) { // We calculate the RTT based on the highest ACKed sequence number, the lower // sequence numbers will include the ACK aggregation delay. QuicTime::Delta rtt = QuicTime::Delta::Zero(); SendAlgorithmInterface::SentPacketsMap::iterator history_it = packet_history_map_.find(frame.received_info.largest_observed); if (history_it != packet_history_map_.end()) { - rtt = clock_->Now().Subtract(history_it->second->SendTimestamp()); + // TODO(pwestin): we need to add the delta to the feedback message. + rtt = ack_receive_time.Subtract(history_it->second->SendTimestamp()); } // We want to. // * Get all packets lower(including) than largest_observed @@ -77,23 +83,32 @@ void QuicCongestionManager::OnIncomingAckFrame(const QuicAckFrame& frame) { it = pending_packets_.begin(); it_upper = pending_packets_.upper_bound(frame.received_info.largest_observed); + bool new_packet_loss_reported = false; while (it != it_upper) { QuicPacketSequenceNumber sequence_number = it->first; - if (!frame.received_info.IsAwaitingPacket(sequence_number)) { + if (!IsAwaitingPacket(frame.received_info, sequence_number)) { // Not missing, hence implicitly acked. send_algorithm_->OnIncomingAck(sequence_number, it->second, rtt); - DLOG(INFO) << "ACKed sequence number:" << sequence_number; pending_packets_.erase(it++); // Must be incremented post to work. } else { + if (sequence_number > largest_missing_) { + // We have a new loss reported. + new_packet_loss_reported = true; + largest_missing_ = sequence_number; + } ++it; } } + if (new_packet_loss_reported) { + send_algorithm_->OnIncomingLoss(ack_receive_time); + } } -QuicTime::Delta QuicCongestionManager::TimeUntilSend(bool is_retransmission) { - return send_algorithm_->TimeUntilSend(is_retransmission); +QuicTime::Delta QuicCongestionManager::TimeUntilSend(QuicTime now, + bool is_retransmission) { + return send_algorithm_->TimeUntilSend(now, is_retransmission); } bool QuicCongestionManager::GenerateCongestionFeedback( @@ -117,19 +132,24 @@ const QuicTime::Delta QuicCongestionManager::DefaultRetransmissionTime() { // static const QuicTime::Delta QuicCongestionManager::GetRetransmissionDelay( + size_t unacked_packets_count, size_t number_retransmissions) { + if (unacked_packets_count <= kTailDropWindowSize) { + return QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs); + } + return QuicTime::Delta::FromMilliseconds( kDefaultRetransmissionTimeMs * (1 << min<size_t>(number_retransmissions, kMaxRetransmissions))); } -QuicBandwidth QuicCongestionManager::SentBandwidth() const { +QuicBandwidth QuicCongestionManager::SentBandwidth( + QuicTime feedback_receive_time) const { const QuicTime::Delta kBitrateSmoothingPeriod = QuicTime::Delta::FromMilliseconds(kBitrateSmoothingPeriodMs); const QuicTime::Delta kMinBitrateSmoothingPeriod = QuicTime::Delta::FromMilliseconds(kMinBitrateSmoothingPeriodMs); - QuicTime now = clock_->Now(); QuicByteCount sum_bytes_sent = 0; // Sum packet from new until they are kBitrateSmoothingPeriod old. @@ -138,7 +158,8 @@ QuicBandwidth QuicCongestionManager::SentBandwidth() const { QuicTime::Delta max_diff = QuicTime::Delta::Zero(); for (; history_rit != packet_history_map_.rend(); ++history_rit) { - QuicTime::Delta diff = now.Subtract(history_rit->second->SendTimestamp()); + QuicTime::Delta diff = + feedback_receive_time.Subtract(history_rit->second->SendTimestamp()); if (diff > kBitrateSmoothingPeriod) { break; } @@ -159,16 +180,14 @@ QuicBandwidth QuicCongestionManager::BandwidthEstimate() { void QuicCongestionManager::CleanupPacketHistory() { const QuicTime::Delta kHistoryPeriod = QuicTime::Delta::FromMilliseconds(kHistoryPeriodMs); - QuicTime Now = clock_->Now(); + QuicTime now = clock_->ApproximateNow(); SendAlgorithmInterface::SentPacketsMap::iterator history_it = packet_history_map_.begin(); for (; history_it != packet_history_map_.end(); ++history_it) { - if (Now.Subtract(history_it->second->SendTimestamp()) <= kHistoryPeriod) { + if (now.Subtract(history_it->second->SendTimestamp()) <= kHistoryPeriod) { return; } - DLOG(INFO) << "Clear sequence number:" << history_it->first - << "from history"; delete history_it->second; packet_history_map_.erase(history_it); history_it = packet_history_map_.begin(); diff --git a/net/quic/congestion_control/quic_congestion_manager.h b/net/quic/congestion_control/quic_congestion_manager.h index 09a9c9c..c8e3a65 100644 --- a/net/quic/congestion_control/quic_congestion_manager.h +++ b/net/quic/congestion_control/quic_congestion_manager.h @@ -33,15 +33,18 @@ class QuicCongestionManager { virtual ~QuicCongestionManager(); // Called when we have received an ack frame from peer. - virtual void OnIncomingAckFrame(const QuicAckFrame& frame); + virtual void OnIncomingAckFrame(const QuicAckFrame& frame, + QuicTime ack_receive_time); // Called when a congestion feedback frame is received from peer. virtual void OnIncomingQuicCongestionFeedbackFrame( - const QuicCongestionFeedbackFrame& frame); + const QuicCongestionFeedbackFrame& frame, + QuicTime feedback_receive_time); // Called when we have sent bytes to the peer. This informs the manager both // the number of bytes sent and if they were retransmitted. virtual void SentPacket(QuicPacketSequenceNumber sequence_number, + QuicTime sent_time, QuicByteCount bytes, bool is_retransmission); @@ -50,7 +53,8 @@ class QuicCongestionManager { // TimeUntilSend again until we receive an OnIncomingAckFrame event. // Note 2: Send algorithms may or may not use |retransmit| in their // calculations. - virtual QuicTime::Delta TimeUntilSend(bool is_retransmission); + virtual QuicTime::Delta TimeUntilSend(QuicTime now, + bool is_retransmission); // Should be called before sending an ACK packet, to decide if we need // to attach a QuicCongestionFeedbackFrame block. @@ -73,6 +77,7 @@ class QuicCongestionManager { const QuicTime::Delta DefaultRetransmissionTime(); const QuicTime::Delta GetRetransmissionDelay( + size_t unacked_packets_count, size_t number_retransmissions); private: @@ -80,8 +85,7 @@ class QuicCongestionManager { friend class test::QuicCongestionManagerPeer; typedef std::map<QuicPacketSequenceNumber, size_t> PendingPacketsMap; - // TODO(pwestin): Currently only used for testing. How do we surface this? - QuicBandwidth SentBandwidth() const; + QuicBandwidth SentBandwidth(QuicTime feedback_receive_time) const; // TODO(pwestin): Currently only used for testing. How do we surface this? QuicBandwidth BandwidthEstimate(); void CleanupPacketHistory(); @@ -91,6 +95,7 @@ class QuicCongestionManager { scoped_ptr<SendAlgorithmInterface> send_algorithm_; SendAlgorithmInterface::SentPacketsMap packet_history_map_; PendingPacketsMap pending_packets_; + QuicPacketSequenceNumber largest_missing_; DISALLOW_COPY_AND_ASSIGN(QuicCongestionManager); }; diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h index efcc172..9478bb4 100644 --- a/net/quic/congestion_control/send_algorithm_interface.h +++ b/net/quic/congestion_control/send_algorithm_interface.h @@ -42,6 +42,8 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface { // Called when we receive congestion feedback from remote peer. virtual void OnIncomingQuicCongestionFeedbackFrame( const QuicCongestionFeedbackFrame& feedback, + QuicTime feedback_receive_time, + QuicBandwidth sent_bandwidth, const SentPacketsMap& sent_packets) = 0; // Called for each received ACK, with sequence number from remote peer. @@ -49,18 +51,18 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface { QuicByteCount acked_bytes, QuicTime::Delta rtt) = 0; - virtual void OnIncomingLoss(int number_of_lost_packets) = 0; + virtual void OnIncomingLoss(QuicTime ack_receive_time) = 0; // Inform that we sent x bytes to the wire, and if that was a retransmission. // Note: this function must be called for every packet sent to the wire. - virtual void SentPacket(QuicPacketSequenceNumber sequence_number, + virtual void SentPacket(QuicTime sent_time, + QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, bool is_retransmission) = 0; // Calculate the time until we can send the next packet. - // Usage: When this returns 0, CongestionWindow returns the number of bytes - // of the congestion window. - virtual QuicTime::Delta TimeUntilSend(bool is_retransmission) = 0; + virtual QuicTime::Delta TimeUntilSend(QuicTime now, + bool is_retransmission) = 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 f309c77..2b32d24 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.cc +++ b/net/quic/congestion_control/tcp_cubic_sender.cc @@ -4,18 +4,18 @@ #include "net/quic/congestion_control/tcp_cubic_sender.h" +namespace net { + namespace { // Constants based on TCP defaults. const int64 kHybridStartLowWindow = 16; -const net::QuicByteCount kMaxSegmentSize = net::kMaxPacketSize; -const net::QuicByteCount kDefaultReceiveWindow = 64000; +const QuicByteCount kMaxSegmentSize = kMaxPacketSize; +const QuicByteCount kDefaultReceiveWindow = 64000; const int64 kInitialCongestionWindow = 10; const int64 kMaxCongestionWindow = 10000; const int kMaxBurstLength = 3; }; -namespace net { - TcpCubicSender::TcpCubicSender(const QuicClock* clock, bool reno) : hybrid_slow_start_(clock), cubic_(clock), @@ -33,6 +33,8 @@ TcpCubicSender::TcpCubicSender(const QuicClock* clock, bool reno) void TcpCubicSender::OnIncomingQuicCongestionFeedbackFrame( const QuicCongestionFeedbackFrame& feedback, + QuicTime feedback_receive_time, + QuicBandwidth /*sent_bandwidth*/, const SentPacketsMap& /*sent_packets*/) { if (last_received_accumulated_number_of_lost_packets_ != feedback.tcp.accumulated_number_of_lost_packets) { @@ -42,7 +44,7 @@ void TcpCubicSender::OnIncomingQuicCongestionFeedbackFrame( last_received_accumulated_number_of_lost_packets_ = feedback.tcp.accumulated_number_of_lost_packets; if (recovered_lost_packets > 0) { - OnIncomingLoss(recovered_lost_packets); + OnIncomingLoss(feedback_receive_time); } } receiver_congestion_window_ = feedback.tcp.receive_window; @@ -60,7 +62,7 @@ void TcpCubicSender::OnIncomingAck( } } -void TcpCubicSender::OnIncomingLoss(int /*number_of_lost_packets*/) { +void TcpCubicSender::OnIncomingLoss(QuicTime /*ack_receive_time*/) { // In a normal TCP we would need to know the lowest missing packet to detect // if we receive 3 missing packets. Here we get a missing packet for which we // enter TCP Fast Retransmit immediately. @@ -76,9 +78,11 @@ void TcpCubicSender::OnIncomingLoss(int /*number_of_lost_packets*/) { if (congestion_window_ == 0) { congestion_window_ = 1; } + DLOG(INFO) << "Incoming loss; congestion window:" << congestion_window_; } -void TcpCubicSender::SentPacket(QuicPacketSequenceNumber sequence_number, +void TcpCubicSender::SentPacket(QuicTime /*sent_time*/, + QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, bool is_retransmission) { if (!is_retransmission) { @@ -93,7 +97,8 @@ void TcpCubicSender::SentPacket(QuicPacketSequenceNumber sequence_number, } } -QuicTime::Delta TcpCubicSender::TimeUntilSend(bool is_retransmission) { +QuicTime::Delta TcpCubicSender::TimeUntilSend(QuicTime now, + bool is_retransmission) { if (is_retransmission) { // For TCP we can always send a retransmission immediately. return QuicTime::Delta::Zero(); @@ -146,7 +151,6 @@ void TcpCubicSender::CongestionAvoidance(QuicPacketSequenceNumber ack) { if (!IsCwndLimited()) { // We don't update the congestion window unless we are close to using the // window we have available. - DLOG(INFO) << "Congestion avoidance window not limited"; return; } if (congestion_window_ < slowstart_threshold_) { diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h index c91642c..2761e5e 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.h +++ b/net/quic/congestion_control/tcp_cubic_sender.h @@ -15,7 +15,6 @@ #include "net/quic/congestion_control/hybrid_slow_start.h" #include "net/quic/congestion_control/send_algorithm_interface.h" #include "net/quic/quic_bandwidth.h" -#include "net/quic/quic_clock.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_time.h" @@ -33,15 +32,19 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { // Start implementation of SendAlgorithmInterface. virtual void OnIncomingQuicCongestionFeedbackFrame( const QuicCongestionFeedbackFrame& feedback, + QuicTime feedback_receive_time, + QuicBandwidth sent_bandwidth, const SentPacketsMap& sent_packets) OVERRIDE; virtual void OnIncomingAck(QuicPacketSequenceNumber acked_sequence_number, QuicByteCount acked_bytes, QuicTime::Delta rtt) OVERRIDE; - virtual void OnIncomingLoss(int number_of_lost_packets) OVERRIDE; - virtual void SentPacket(QuicPacketSequenceNumber sequence_number, + virtual void OnIncomingLoss(QuicTime ack_receive_time) OVERRIDE; + virtual void SentPacket(QuicTime sent_time, + QuicPacketSequenceNumber sequence_number, QuicByteCount bytes, bool is_retransmission) OVERRIDE; - virtual QuicTime::Delta TimeUntilSend(bool is_retransmission) OVERRIDE; + virtual QuicTime::Delta TimeUntilSend(QuicTime now, + bool is_retransmission) OVERRIDE; virtual QuicBandwidth BandwidthEstimate() OVERRIDE; // End implementation of SendAlgorithmInterface. diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc index 5e3edc4..fc9a2d7 100644 --- a/net/quic/congestion_control/tcp_cubic_sender_test.cc +++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc @@ -29,6 +29,7 @@ class TcpCubicSenderTest : public ::testing::Test { TcpCubicSenderTest() : rtt_(QuicTime::Delta::FromMilliseconds(60)), one_ms_(QuicTime::Delta::FromMilliseconds(1)), + fake_bandwidth_(QuicBandwidth::Zero()), sender_(new TcpCubicSenderPeer(&clock_, true)), receiver_(new TcpReceiver()), sequence_number_(1), @@ -38,10 +39,11 @@ class TcpCubicSenderTest : public ::testing::Test { QuicByteCount bytes_to_send = sender_->AvailableCongestionWindow(); while (bytes_to_send > 0) { QuicByteCount bytes_in_packet = std::min(kMaxPacketSize, bytes_to_send); - sender_->SentPacket(sequence_number_++, bytes_in_packet, false); + sender_->SentPacket(clock_.Now(), sequence_number_++, bytes_in_packet, + false); bytes_to_send -= bytes_in_packet; if (bytes_to_send > 0) { - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); } } } @@ -56,6 +58,7 @@ class TcpCubicSenderTest : public ::testing::Test { const QuicTime::Delta rtt_; const QuicTime::Delta one_ms_; + const QuicBandwidth fake_bandwidth_; MockClock clock_; SendAlgorithmInterface::SentPacketsMap not_used_; scoped_ptr<TcpCubicSenderPeer> sender_; @@ -70,29 +73,31 @@ TEST_F(TcpCubicSenderTest, SimpleSender) { EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableCongestionWindow()); // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); // Get default QuicCongestionFeedbackFrame from receiver. ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); - sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_); + sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(), + fake_bandwidth_, not_used_); // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); // And that window is un-affected. EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableCongestionWindow()); // A retransmitt should always retun 0. - EXPECT_TRUE(sender_->TimeUntilSend(true).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), true).IsZero()); } TEST_F(TcpCubicSenderTest, ExponentialSlowStart) { const int kNumberOfAck = 20; QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); // Get default QuicCongestionFeedbackFrame from receiver. ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); - sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_); + sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(), + fake_bandwidth_, not_used_); // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); for (int n = 0; n < kNumberOfAck; ++n) { // Send our full congestion window. @@ -113,12 +118,13 @@ TEST_F(TcpCubicSenderTest, SlowStartAckTrain) { const int kNumberOfAck = 65; QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); // Get default QuicCongestionFeedbackFrame from receiver. ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); - sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_); + sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(), + fake_bandwidth_, not_used_); // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); for (int n = 0; n < kNumberOfAck; ++n) { // Send our full congestion window. @@ -153,12 +159,13 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) { const int kNumberOfAck = 10; QuicCongestionFeedbackFrame feedback; // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); // Get default QuicCongestionFeedbackFrame from receiver. ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); - sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_); + sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(), + fake_bandwidth_, not_used_); // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsZero()); for (int i = 0; i < kNumberOfAck; ++i) { // Send our full congestion window. @@ -170,10 +177,10 @@ TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) { (kMaxPacketSize * 2 * kNumberOfAck); EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow()); - sender_->OnIncomingLoss(1); + sender_->OnIncomingLoss(clock_.Now()); // Make sure that we should not send right now. - EXPECT_TRUE(sender_->TimeUntilSend(false).IsInfinite()); + EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), false).IsInfinite()); // We should now have fallen out of slow start. // We expect window to be cut in half. diff --git a/net/quic/crypto/null_decrypter.cc b/net/quic/crypto/null_decrypter.cc index 072c684..92b9204 100644 --- a/net/quic/crypto/null_decrypter.cc +++ b/net/quic/crypto/null_decrypter.cc @@ -11,7 +11,16 @@ using std::string; namespace net { -QuicData* NullDecrypter::Decrypt(StringPiece associated_data, +bool NullDecrypter::SetKey(StringPiece key) { + return key.empty(); +} + +bool NullDecrypter::SetNoncePrefix(StringPiece nonce_prefix) { + return nonce_prefix.empty(); +} + +QuicData* NullDecrypter::Decrypt(QuicPacketSequenceNumber /*sequence_number*/, + StringPiece associated_data, StringPiece ciphertext) { QuicDataReader reader(ciphertext.data(), ciphertext.length()); diff --git a/net/quic/crypto/null_decrypter.h b/net/quic/crypto/null_decrypter.h index 5495092..93315a8 100644 --- a/net/quic/crypto/null_decrypter.h +++ b/net/quic/crypto/null_decrypter.h @@ -19,7 +19,10 @@ class NET_EXPORT_PRIVATE NullDecrypter : public QuicDecrypter { virtual ~NullDecrypter() {} // QuicDecrypter implementation - virtual QuicData* Decrypt(base::StringPiece associated_data, + virtual bool SetKey(base::StringPiece key) OVERRIDE; + virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) OVERRIDE; + virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number, + base::StringPiece associated_data, base::StringPiece ciphertext) OVERRIDE; }; diff --git a/net/quic/crypto/null_decrypter_test.cc b/net/quic/crypto/null_decrypter_test.cc index ad73cea..3d201fe 100644 --- a/net/quic/crypto/null_decrypter_test.cc +++ b/net/quic/crypto/null_decrypter_test.cc @@ -23,7 +23,7 @@ TEST(NullDecrypterTest, Decrypt) { }; NullDecrypter decrypter; scoped_ptr<QuicData> decrypted( - decrypter.Decrypt("hello world!", + decrypter.Decrypt(0, "hello world!", StringPiece(reinterpret_cast<const char*>(expected), arraysize(expected)))); ASSERT_TRUE(decrypted.get()); @@ -43,7 +43,7 @@ TEST(NullDecrypterTest, BadHash) { }; NullDecrypter decrypter; scoped_ptr<QuicData> decrypted( - decrypter.Decrypt("hello world!", + decrypter.Decrypt(0, "hello world!", StringPiece(reinterpret_cast<const char*>(expected), arraysize(expected)))); ASSERT_FALSE(decrypted.get()); @@ -59,7 +59,7 @@ TEST(NullDecrypterTest, ShortInput) { }; NullDecrypter decrypter; scoped_ptr<QuicData> decrypted( - decrypter.Decrypt("hello world!", + decrypter.Decrypt(0, "hello world!", StringPiece(reinterpret_cast<const char*>(expected), arraysize(expected)))); ASSERT_FALSE(decrypted.get()); diff --git a/net/quic/crypto/null_encrypter.cc b/net/quic/crypto/null_encrypter.cc index fda844b..49fc927 100644 --- a/net/quic/crypto/null_encrypter.cc +++ b/net/quic/crypto/null_encrypter.cc @@ -13,7 +13,16 @@ namespace net { const size_t kHashSize = 16; // size of uint128 serialized -QuicData* NullEncrypter::Encrypt(StringPiece associated_data, +bool NullEncrypter::SetKey(StringPiece key) { + return key.empty(); +} + +bool NullEncrypter::SetNoncePrefix(StringPiece nonce_prefix) { + return nonce_prefix.empty(); +} + +QuicData* NullEncrypter::Encrypt(QuicPacketSequenceNumber /*sequence_number*/, + StringPiece associated_data, StringPiece plaintext) { // TODO(rch): avoid buffer copy here string buffer = associated_data.as_string(); @@ -26,11 +35,19 @@ QuicData* NullEncrypter::Encrypt(StringPiece associated_data, return new QuicData(writer.take(), len, true); } -size_t NullEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) { +size_t NullEncrypter::GetKeySize() const { + return 0; +} + +size_t NullEncrypter::GetNoncePrefixSize() const { + return 0; +} + +size_t NullEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { return ciphertext_size - kHashSize; } -size_t NullEncrypter::GetCiphertextSize(size_t plaintext_size) { +size_t NullEncrypter::GetCiphertextSize(size_t plaintext_size) const { return plaintext_size + kHashSize; } diff --git a/net/quic/crypto/null_encrypter.h b/net/quic/crypto/null_encrypter.h index e73423d..62f4ef6 100644 --- a/net/quic/crypto/null_encrypter.h +++ b/net/quic/crypto/null_encrypter.h @@ -19,10 +19,15 @@ class NET_EXPORT_PRIVATE NullEncrypter : public QuicEncrypter { virtual ~NullEncrypter() {} // QuicEncrypter implementation - virtual QuicData* Encrypt(base::StringPiece associated_data, + virtual bool SetKey(base::StringPiece key) OVERRIDE; + virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) OVERRIDE; + virtual QuicData* Encrypt(QuicPacketSequenceNumber sequence_number, + base::StringPiece associated_data, base::StringPiece plaintext) OVERRIDE; - virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) OVERRIDE; - virtual size_t GetCiphertextSize(size_t plaintext_size) OVERRIDE; + virtual size_t GetKeySize() const OVERRIDE; + virtual size_t GetNoncePrefixSize() const OVERRIDE; + virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) const OVERRIDE; + virtual size_t GetCiphertextSize(size_t plaintext_size) const OVERRIDE; }; } // namespace net diff --git a/net/quic/crypto/null_encrypter_test.cc b/net/quic/crypto/null_encrypter_test.cc index 9f2cec2..328c738 100644 --- a/net/quic/crypto/null_encrypter_test.cc +++ b/net/quic/crypto/null_encrypter_test.cc @@ -22,7 +22,7 @@ TEST(NullEncrypterTest, Encrypt) { 'b', 'y', 'e', '!', }; NullEncrypter encrypter; - scoped_ptr<QuicData> encrypted(encrypter.Encrypt("hello world!", + scoped_ptr<QuicData> encrypted(encrypter.Encrypt(0, "hello world!", "goodbye!")); ASSERT_TRUE(encrypted.get()); test::CompareCharArraysWithHexError( diff --git a/net/quic/crypto/quic_decrypter.h b/net/quic/crypto/quic_decrypter.h index e5c5635..c8b691d 100644 --- a/net/quic/crypto/quic_decrypter.h +++ b/net/quic/crypto/quic_decrypter.h @@ -17,9 +17,37 @@ class NET_EXPORT_PRIVATE QuicDecrypter { static QuicDecrypter* Create(CryptoTag algorithm); + // Sets the encryption key. Returns true on success, false on failure. + // + // NOTE: The key is the client_write_key or server_write_key derived from + // the master secret. + virtual bool SetKey(base::StringPiece key) = 0; + + // Sets the fixed initial bytes of the nonce. Returns true on success, + // false on failure. + // + // NOTE: The nonce prefix is the client_write_iv or server_write_iv + // derived from the master secret. A 64-bit packet sequence number will + // be appended to form the nonce. + // + // <------------ 64 bits -----------> + // +---------------------+----------------------------------+ + // | Fixed prefix | Packet sequence number | + // +---------------------+----------------------------------+ + // Nonce format + // + // The security of the nonce format requires that QUIC never reuse a + // packet sequence number, even when retransmitting a lost packet. + virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) = 0; + // Returns a newly created QuicData object containing the decrypted - // |ciphertext| or NULL if there is an error. - virtual QuicData* Decrypt(base::StringPiece associated_data, + // |ciphertext| or NULL if there is an error. |sequence_number| is + // appended to the |nonce_prefix| value provided in SetNoncePrefix() + // to form the nonce. + // TODO(wtc): add a way for Decrypt to report decryption failure due + // to non-authentic inputs, as opposed to other reasons for failure. + virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number, + base::StringPiece associated_data, base::StringPiece ciphertext) = 0; }; diff --git a/net/quic/crypto/quic_encrypter.h b/net/quic/crypto/quic_encrypter.h index f077c1f..214ce2d 100644 --- a/net/quic/crypto/quic_encrypter.h +++ b/net/quic/crypto/quic_encrypter.h @@ -17,20 +17,55 @@ class NET_EXPORT_PRIVATE QuicEncrypter { static QuicEncrypter* Create(CryptoTag algorithm); + // Sets the encryption key. Returns true on success, false on failure. + // + // NOTE: The key is the client_write_key or server_write_key derived from + // the master secret. + virtual bool SetKey(base::StringPiece key) = 0; + + // Sets the fixed initial bytes of the nonce. Returns true on success, + // false on failure. + // + // NOTE: The nonce prefix is the client_write_iv or server_write_iv + // derived from the master secret. A 64-bit packet sequence number will + // be appended to form the nonce. + // + // <------------ 64 bits -----------> + // +---------------------+----------------------------------+ + // | Fixed prefix | Packet sequence number | + // +---------------------+----------------------------------+ + // Nonce format + // + // The security of the nonce format requires that QUIC never reuse a + // packet sequence number, even when retransmitting a lost packet. + virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) = 0; + // Returns a newly created QuicData object containing the encrypted // |plaintext| as well as a MAC over both |plaintext| and |associated_data|, - // or NULL if there is an error. - virtual QuicData* Encrypt(base::StringPiece associated_data, + // or NULL if there is an error. |sequence_number| is appended to the + // |nonce_prefix| value provided in SetNoncePrefix() to form the nonce. + virtual QuicData* Encrypt(QuicPacketSequenceNumber sequence_number, + base::StringPiece associated_data, base::StringPiece plaintext) = 0; + // GetKeySize() and GetNoncePrefixSize() tell the HKDF class how many bytes + // of key material needs to be derived from the master secret. + // NOTE: the sizes returned by GetKeySize() and GetNoncePrefixSize() are + // also correct for the QuicDecrypter of the same algorithm. So only + // QuicEncrypter has these two methods. + + // Returns the size in bytes of a key for the algorithm. + virtual size_t GetKeySize() const = 0; + // Returns the size in bytes of the fixed initial part of the nonce. + virtual size_t GetNoncePrefixSize() const = 0; + // Returns the maximum length of plaintext that can be encrypted // to ciphertext no larger than |ciphertext_size|. - virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) = 0; + virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) const = 0; // Returns the length of the ciphertext that would be generated by encrypting // to plaintext of size |plaintext_size|. - virtual size_t GetCiphertextSize(size_t plaintext_size) = 0; - + virtual size_t GetCiphertextSize(size_t plaintext_size) const = 0; }; } // namespace net diff --git a/net/quic/crypto/quic_random.cc b/net/quic/crypto/quic_random.cc index 9a67918..be1f3c0 100644 --- a/net/quic/crypto/quic_random.cc +++ b/net/quic/crypto/quic_random.cc @@ -19,6 +19,7 @@ class DefaultRandom : public QuicRandom { // QuicRandom implementation virtual void RandBytes(void* data, size_t len) OVERRIDE; virtual uint64 RandUint64() OVERRIDE; + virtual bool RandBool() OVERRIDE; virtual void Reseed(const void* additional_entropy, size_t entropy_len) OVERRIDE; @@ -44,6 +45,12 @@ uint64 DefaultRandom::RandUint64() { return value; } +bool DefaultRandom::RandBool() { + char value; + RandBytes(&value, sizeof(value)); + return (value & 1) == 1; +} + void DefaultRandom::Reseed(const void* additional_entropy, size_t entropy_len) { // No such function exists in crypto/random.h. } diff --git a/net/quic/crypto/quic_random.h b/net/quic/crypto/quic_random.h index ac69b85..68640c1 100644 --- a/net/quic/crypto/quic_random.h +++ b/net/quic/crypto/quic_random.h @@ -27,6 +27,9 @@ class NET_EXPORT_PRIVATE QuicRandom { // Returns a random number in the range [0, kuint64max]. virtual uint64 RandUint64() = 0; + // Returns a random boolean value. + virtual bool RandBool() = 0; + // Reseeds the random number generator with additional entropy input. // NOTE: the constructor of a QuicRandom object is responsible for seeding // itself with enough entropy input. diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc index 2154d66..d562080 100644 --- a/net/quic/quic_client_session.cc +++ b/net/quic/quic_client_session.cc @@ -53,6 +53,11 @@ QuicReliableClientStream* QuicClientSession::CreateOutgoingReliableStream() { << "Already " << GetNumOpenStreams() << " open."; return NULL; } + if (goaway_received()) { + DLOG(INFO) << "Failed to create a new outgoing stream. " + << "Already received goaway."; + return NULL; + } QuicReliableClientStream* stream = new QuicReliableClientStream(GetNextStreamId(), this, net_log_); ActivateStream(stream); diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc index 674b0a4..fbacd09 100644 --- a/net/quic/quic_client_session_test.cc +++ b/net/quic/quic_client_session_test.cc @@ -77,6 +77,20 @@ TEST_F(QuicClientSessionTest, MaxNumConnections) { EXPECT_TRUE(session_.CreateOutgoingReliableStream()); } +TEST_F(QuicClientSessionTest, GoAwayReceived) { + // Initialize crypto before the client session will create a stream. + ASSERT_TRUE(session_.CryptoConnect(callback_.callback())); + // Simulate the server crypto handshake. + CryptoHandshakeMessage server_message; + server_message.tag = kSHLO; + session_.GetCryptoStream()->OnHandshakeMessage(server_message); + + // After receiving a GoAway, I should no longer be able to create outgoing + // streams. + session_.OnGoAway(QuicGoAwayFrame(QUIC_PEER_GOING_AWAY, 1u, "Going away.")); + EXPECT_EQ(NULL, session_.CreateOutgoingReliableStream()); +} + TEST_F(QuicClientSessionTest, Logging) { // Initialize crypto before the client session will create a stream. ASSERT_EQ(ERR_IO_PENDING, session_.CryptoConnect(callback_.callback())); @@ -91,7 +105,6 @@ TEST_F(QuicClientSessionTest, Logging) { QuicFramer framer(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); QuicRstStreamFrame frame; frame.stream_id = 2; - frame.offset = 7; frame.error_code = QUIC_CONNECTION_TIMED_OUT; frame.error_details = "doh!"; @@ -99,12 +112,16 @@ TEST_F(QuicClientSessionTest, Logging) { frames.push_back(QuicFrame(&frame)); QuicPacketHeader header; header.public_header.guid = 1; - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; header.packet_sequence_number = 1; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.entropy_flag = false; + header.fec_flag = false; + header.fec_entropy_flag = false; header.fec_group = 0; - scoped_ptr<QuicPacket> p(framer.ConstructFrameDataPacket(header, frames)); - scoped_ptr<QuicEncryptedPacket> packet(framer.EncryptPacket(*p)); + scoped_ptr<QuicPacket> p( + framer.ConstructFrameDataPacket(header, frames).packet); + scoped_ptr<QuicEncryptedPacket> packet(framer.EncryptPacket(1, *p)); IPAddressNumber ip; CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip)); IPEndPoint peer_addr = IPEndPoint(ip, 443); @@ -134,9 +151,6 @@ TEST_F(QuicClientSessionTest, Logging) { int stream_id; ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id)); EXPECT_EQ(frame.stream_id, static_cast<QuicStreamId>(stream_id)); - int offset; - ASSERT_TRUE(entries[pos].GetIntegerValue("offset", &offset)); - EXPECT_EQ(frame.offset, static_cast<QuicStreamOffset>(offset)); int error_code; ASSERT_TRUE(entries[pos].GetIntegerValue("error_code", &error_code)); EXPECT_EQ(frame.error_code, static_cast<QuicErrorCode>(error_code)); diff --git a/net/quic/quic_clock.cc b/net/quic/quic_clock.cc index 32d9991..26c1a65 100644 --- a/net/quic/quic_clock.cc +++ b/net/quic/quic_clock.cc @@ -13,6 +13,11 @@ QuicClock::QuicClock() { QuicClock::~QuicClock() {} +QuicTime QuicClock::ApproximateNow() const { + // Chrome does not have a distinct notion of ApproximateNow(). + return Now(); +} + QuicTime QuicClock::Now() const { return QuicTime(base::TimeTicks::Now()); } diff --git a/net/quic/quic_clock.h b/net/quic/quic_clock.h index dca211e..6b6cb31 100644 --- a/net/quic/quic_clock.h +++ b/net/quic/quic_clock.h @@ -21,6 +21,10 @@ class NET_EXPORT_PRIVATE QuicClock { virtual ~QuicClock(); // Returns the approximate current time as a QuicTime object. + virtual QuicTime ApproximateNow() const; + + // Returns the current time as a QuicTime object. + // Note: this use significant resources please use only if needed. virtual QuicTime Now() const; // Returns the current time as an offset from the Unix epoch (1970-01-01 diff --git a/net/quic/quic_clock_test.cc b/net/quic/quic_clock_test.cc index 9a9914d..1f285942 100644 --- a/net/quic/quic_clock_test.cc +++ b/net/quic/quic_clock_test.cc @@ -13,7 +13,7 @@ TEST(QuicClockTest, Now) { QuicClock clock; QuicTime start(base::TimeTicks::Now()); - QuicTime now = clock.Now(); + QuicTime now = clock.ApproximateNow(); QuicTime end(base::TimeTicks::Now()); EXPECT_LE(start, now); diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 8dc1994..c04c0dd 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -17,6 +17,7 @@ using base::StringPiece; using std::list; using std::make_pair; using std::min; +using std::max; using std::vector; using std::set; using std::string; @@ -34,7 +35,12 @@ const QuicPacketSequenceNumber kMaxPacketGap = 5000; // The maximum number of nacks which can be transmitted in a single ack packet // without exceeding kMaxPacketSize. -const QuicPacketSequenceNumber kMaxUnackedPackets = 192u; +// TODO(satyamshekhar): Get rid of magic numbers and move this to protocol.h +// 16 - Min ack frame size. +// 16 - Crypto hash for integrity. Not a static value. Use +// QuicEncrypter::GetMaxPlaintextSize. +const QuicPacketSequenceNumber kMaxUnackedPackets = + (kMaxPacketSize - kPacketHeaderSize - 16 - 16) / kSequenceNumberSize; // We want to make sure if we get a large nack packet, we don't queue up too // many packets at once. 10 is arbitrary. @@ -55,9 +61,7 @@ const int kMaxPacketsToSerializeAtOnce = 6; // eventually cede. 10 is arbitrary. const int kMaxPacketsPerRetransmissionAlarm = 10; -// Named constant for WriteQueuedData(). -const bool kFlush = true; -// Named constant for WritePacket(), SendOrQueuePacket(). +// Named constant for WritePacket() const bool kForce = true; // Named constant for CanWrite(). const bool kIsRetransmission = true; @@ -69,19 +73,6 @@ bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) { } // namespace -QuicConnection::UnackedPacket::UnackedPacket(QuicFrames unacked_frames) - : frames(unacked_frames) { -} - -QuicConnection::UnackedPacket::UnackedPacket(QuicFrames unacked_frames, - std::string data) - : frames(unacked_frames), - data(data) { -} - -QuicConnection::UnackedPacket::~UnackedPacket() { -} - QuicConnection::QuicConnection(QuicGuid guid, IPEndPoint address, QuicConnectionHelperInterface* helper) @@ -91,17 +82,18 @@ QuicConnection::QuicConnection(QuicGuid guid, random_generator_(helper->GetRandomGenerator()), guid_(guid), peer_address_(address), - should_send_ack_(false), - should_send_congestion_feedback_(false), largest_seen_packet_with_ack_(0), peer_largest_observed_packet_(0), + least_packet_awaited_by_peer_(1), peer_least_packet_awaiting_ack_(0), handling_retransmission_timeout_(false), write_blocked_(false), debug_visitor_(NULL), - packet_creator_(guid_, &framer_), + packet_creator_(guid_, &framer_, random_generator_), + packet_generator_(this, &packet_creator_), timeout_(QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs)), - time_of_last_packet_(clock_->Now()), + time_of_last_received_packet_(clock_->ApproximateNow()), + time_of_last_sent_packet_(clock_->ApproximateNow()), congestion_manager_(clock_, kTCP), connected_(true), received_truncated_ack_(false), @@ -109,9 +101,12 @@ QuicConnection::QuicConnection(QuicGuid guid, helper_->SetConnection(this); helper_->SetTimeoutAlarm(timeout_); framer_.set_visitor(this); + framer_.set_entropy_calculator(&entropy_manager_); memset(&last_header_, 0, sizeof(last_header_)); outgoing_ack_.sent_info.least_unacked = 0; + outgoing_ack_.sent_info.entropy_hash = 0; outgoing_ack_.received_info.largest_observed = 0; + outgoing_ack_.received_info.entropy_hash = 0; /* if (FLAGS_fake_packet_loss_percentage > 0) { @@ -123,12 +118,6 @@ QuicConnection::QuicConnection(QuicGuid guid, } QuicConnection::~QuicConnection() { - // Call DeleteEnclosedFrames on each QuicPacket because the destructor does - // not delete enclosed frames. - for (UnackedPacketMap::iterator it = unacked_packets_.begin(); - it != unacked_packets_.end(); ++it) { - DeleteEnclosedFrames(it->second); - } STLDeleteValues(&unacked_packets_); STLDeleteValues(&group_map_); for (QueuedPacketList::iterator it = queued_packets_.begin(); @@ -137,45 +126,14 @@ QuicConnection::~QuicConnection() { } } -void QuicConnection::DeleteEnclosedFrame(QuicFrame* frame) { - switch (frame->type) { - case PADDING_FRAME: - delete frame->padding_frame; - break; - case STREAM_FRAME: - delete frame->stream_frame; - break; - case ACK_FRAME: - delete frame->ack_frame; - break; - case CONGESTION_FEEDBACK_FRAME: - delete frame->congestion_feedback_frame; - break; - case RST_STREAM_FRAME: - delete frame->rst_stream_frame; - break; - case CONNECTION_CLOSE_FRAME: - delete frame->connection_close_frame; - break; - case NUM_FRAME_TYPES: - DCHECK(false) << "Cannot delete type: " << frame->type; - } -} - -void QuicConnection::DeleteEnclosedFrames(UnackedPacket* unacked) { - for (QuicFrames::iterator it = unacked->frames.begin(); - it != unacked->frames.end(); ++it) { - DeleteEnclosedFrame(&(*it)); - } -} - void QuicConnection::OnError(QuicFramer* framer) { SendConnectionClose(framer->error()); } void QuicConnection::OnPacket() { - time_of_last_packet_ = clock_->Now(); - DVLOG(1) << "last packet: " << time_of_last_packet_.ToMicroseconds(); + time_of_last_received_packet_ = clock_->Now(); + DVLOG(1) << "time of last received packet: " + << time_of_last_received_packet_.ToMicroseconds(); // TODO(alyssar, rch) handle migration! self_address_ = last_self_address_; @@ -213,11 +171,12 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { // If this packet has already been seen, or that the sender // has told us will not be retransmitted, then stop processing the packet. - if (!outgoing_ack_.received_info.IsAwaitingPacket( - header.packet_sequence_number)) { + if (!IsAwaitingPacket(outgoing_ack_.received_info, + header.packet_sequence_number)) { return false; } + DVLOG(1) << "Received packet header: " << header; last_header_ = header; return true; } @@ -239,7 +198,7 @@ void QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) { if (debug_visitor_) { debug_visitor_->OnAckFrame(incoming_ack); } - DVLOG(1) << "Ack packet: " << incoming_ack; + DVLOG(1) << "OnAckFrame: " << incoming_ack; if (last_header_.packet_sequence_number <= largest_seen_packet_with_ack_) { DLOG(INFO) << "Received an old ack frame: ignoring"; @@ -252,19 +211,28 @@ void QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) { return; } + // TODO(satyamshekhar): Not true if missing_packets.size() was actually + // kMaxUnackedPackets. This can result in a dead connection if all the + // missing packets get lost during retransmission. Now the new packets(or the + // older packets) will not be retransmitted due to RTO + // since received_truncated_ack_ is true and their sequence_number is > + // peer_largest_observed_packet. Fix either by resetting it in + // MaybeRetransmitPacketForRTO or keeping an explicit flag for ack truncation. received_truncated_ack_ = incoming_ack.received_info.missing_packets.size() >= kMaxUnackedPackets; UpdatePacketInformationReceivedByPeer(incoming_ack); UpdatePacketInformationSentByPeer(incoming_ack); - congestion_manager_.OnIncomingAckFrame(incoming_ack); + congestion_manager_.OnIncomingAckFrame(incoming_ack, + time_of_last_received_packet_); // Now the we have received an ack, we might be able to send queued packets. if (queued_packets_.empty()) { return; } - QuicTime::Delta delay = congestion_manager_.TimeUntilSend(false); + QuicTime::Delta delay = congestion_manager_.TimeUntilSend( + time_of_last_received_packet_, false); if (delay.IsZero()) { helper_->UnregisterSendAlarmIfRegistered(); if (!write_blocked_) { @@ -280,7 +248,8 @@ void QuicConnection::OnCongestionFeedbackFrame( if (debug_visitor_) { debug_visitor_->OnCongestionFeedbackFrame(feedback); } - congestion_manager_.OnIncomingQuicCongestionFeedbackFrame(feedback); + congestion_manager_.OnIncomingQuicCongestionFeedbackFrame( + feedback, time_of_last_received_packet_); } bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) { @@ -308,19 +277,47 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) { kMaxUnackedPackets); if (incoming_ack.sent_info.least_unacked < peer_least_packet_awaiting_ack_) { - DLOG(INFO) << "Client sent low least_unacked: " - << incoming_ack.sent_info.least_unacked - << " vs " << peer_least_packet_awaiting_ack_; + DLOG(ERROR) << "Client sent low least_unacked: " + << incoming_ack.sent_info.least_unacked + << " vs " << peer_least_packet_awaiting_ack_; // We never process old ack frames, so this number should only increase. return false; } if (incoming_ack.sent_info.least_unacked > last_header_.packet_sequence_number) { - DLOG(INFO) << "Client sent least_unacked:" - << incoming_ack.sent_info.least_unacked - << " greater than the enclosing packet sequence number:" - << last_header_.packet_sequence_number; + DLOG(ERROR) << "Client sent least_unacked:" + << incoming_ack.sent_info.least_unacked + << " greater than the enclosing packet sequence number:" + << last_header_.packet_sequence_number; + return false; + } + + if (!incoming_ack.received_info.missing_packets.empty() && + *incoming_ack.received_info.missing_packets.rbegin() > + incoming_ack.received_info.largest_observed) { + DLOG(ERROR) << "Client sent missing packet: " + << *incoming_ack.received_info.missing_packets.rbegin() + << " greater than largest observed: " + << incoming_ack.received_info.largest_observed; + return false; + } + + if (!incoming_ack.received_info.missing_packets.empty() && + *incoming_ack.received_info.missing_packets.begin() < + least_packet_awaited_by_peer_) { + DLOG(ERROR) << "Client sent missing packet: " + << *incoming_ack.received_info.missing_packets.begin() + << "smaller than least_packet_awaited_by_peer_: " + << least_packet_awaited_by_peer_; + return false; + } + + if (!entropy_manager_.IsValidEntropy( + incoming_ack.received_info.largest_observed, + incoming_ack.received_info.missing_packets, + incoming_ack.received_info.entropy_hash)) { + DLOG(ERROR) << "Client sent invalid entropy."; return false; } @@ -329,46 +326,36 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) { void QuicConnection::UpdatePacketInformationReceivedByPeer( const QuicAckFrame& incoming_ack) { - QuicConnectionVisitorInterface::AckedPackets acked_packets; + SequenceNumberSet acked_packets; // ValidateAck should fail if largest_observed ever shrinks. DCHECK_LE(peer_largest_observed_packet_, incoming_ack.received_info.largest_observed); peer_largest_observed_packet_ = incoming_ack.received_info.largest_observed; - // Pick an upper bound for the lowest_unacked; we'll then loop through the - // unacked packets and lower it if necessary. - QuicPacketSequenceNumber lowest_unacked = min( - packet_creator_.sequence_number() + 1, - peer_largest_observed_packet_ + 1); + if (incoming_ack.received_info.missing_packets.empty()) { + least_packet_awaited_by_peer_ = peer_largest_observed_packet_ + 1; + } else { + least_packet_awaited_by_peer_ = + *(incoming_ack.received_info.missing_packets.begin()); + } - int retransmitted_packets = 0; + entropy_manager_.ClearSentEntropyBefore(least_packet_awaited_by_peer_ - 1); + int retransmitted_packets = 0; // Go through the packets we have not received an ack for and see if this // incoming_ack shows they've been seen by the peer. UnackedPacketMap::iterator it = unacked_packets_.begin(); while (it != unacked_packets_.end()) { QuicPacketSequenceNumber sequence_number = it->first; - UnackedPacket* unacked = it->second; - if (!incoming_ack.received_info.IsAwaitingPacket(sequence_number)) { + if (sequence_number > peer_largest_observed_packet_) { + break; + } + RetransmittableFrames* unacked = it->second; + if (!IsAwaitingPacket(incoming_ack.received_info, sequence_number)) { // Packet was acked, so remove it from our unacked packet list. DVLOG(1) << "Got an ack for " << sequence_number; - // TODO(rch): This is inefficient and should be sped up. - // TODO(ianswett): Ensure this inner loop is applicable now that we're - // always sending packets with new sequence numbers. I believe it may - // only be relevant for the first crypto connect packet, which doesn't - // get a new packet sequence number. - // The acked packet might be queued (if a retransmission had been - // attempted). - for (QueuedPacketList::iterator q = queued_packets_.begin(); - q != queued_packets_.end(); ++q) { - if (q->sequence_number == sequence_number) { - queued_packets_.erase(q); - break; - } - } acked_packets.insert(sequence_number); - DeleteEnclosedFrames(unacked); delete unacked; UnackedPacketMap::iterator it_tmp = it; ++it; @@ -379,70 +366,66 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer( // seen at the time of this ack being sent out. See if it's our new // lowest unacked packet. DVLOG(1) << "still missing " << sequence_number; - if (sequence_number < lowest_unacked) { - lowest_unacked = sequence_number; - } ++it; - // Determine if this packet is being explicitly nacked and, if so, if it - // is worth retransmitting. - if (sequence_number <= peer_largest_observed_packet_) { - // The peer got packets after this sequence number. This is an explicit - // nack. - RetransmissionMap::iterator retransmission_it = - retransmission_map_.find(sequence_number); - ++(retransmission_it->second.number_nacks); - if (retransmission_it->second.number_nacks >= - kNumberOfNacksBeforeRetransmission && - retransmitted_packets < kMaxRetransmissionsPerAck) { - ++retransmitted_packets; - DVLOG(1) << "Trying to retransmit packet " << sequence_number - << " as it has been nacked 3 or more times."; - // TODO(satyamshekhar): save in a vector and retransmit after the - // loop. - RetransmitPacket(sequence_number); - } + // The peer got packets after this sequence number. This is an explicit + // nack. + RetransmissionMap::iterator retransmission_it = + retransmission_map_.find(sequence_number); + ++(retransmission_it->second.number_nacks); + if (retransmission_it->second.number_nacks >= + kNumberOfNacksBeforeRetransmission && + retransmitted_packets < kMaxRetransmissionsPerAck) { + ++retransmitted_packets; + DVLOG(1) << "Trying to retransmit packet " << sequence_number + << " as it has been nacked 3 or more times."; + // TODO(satyamshekhar): save in a vector and retransmit after the + // loop. + RetransmitPacket(sequence_number); } } } if (acked_packets.size() > 0) { visitor_->OnAck(acked_packets); } - SetLeastUnacked(lowest_unacked); -} - -void QuicConnection::SetLeastUnacked(QuicPacketSequenceNumber lowest_unacked) { - // If we've gotten an ack for the lowest packet we were waiting on, - // update that and the list of packets we advertise we will not retransmit. - if (lowest_unacked > outgoing_ack_.sent_info.least_unacked) { - outgoing_ack_.sent_info.least_unacked = lowest_unacked; - } } -void QuicConnection::UpdateLeastUnacked( - QuicPacketSequenceNumber acked_sequence_number) { - if (acked_sequence_number != outgoing_ack_.sent_info.least_unacked) { - return; - } - QuicPacketSequenceNumber least_unacked = - packet_creator_.sequence_number() + 1; - for (UnackedPacketMap::iterator it = unacked_packets_.begin(); - it != unacked_packets_.end(); ++it) { - least_unacked = min<int>(least_unacked, it->first); - } - - SetLeastUnacked(least_unacked); +bool QuicConnection::DontWaitForPacketsBefore( + QuicPacketSequenceNumber least_unacked) { + size_t missing_packets_count = + outgoing_ack_.received_info.missing_packets.size(); + outgoing_ack_.received_info.missing_packets.erase( + outgoing_ack_.received_info.missing_packets.begin(), + outgoing_ack_.received_info.missing_packets.lower_bound(least_unacked)); + return missing_packets_count != + outgoing_ack_.received_info.missing_packets.size(); } void QuicConnection::UpdatePacketInformationSentByPeer( const QuicAckFrame& incoming_ack) { - // Make sure we also don't ack any packets lower than the peer's - // last-packet-awaiting-ack. + // ValidateAck() should fail if peer_least_packet_awaiting_ack_ shrinks. + DCHECK_LE(peer_least_packet_awaiting_ack_, + incoming_ack.sent_info.least_unacked); if (incoming_ack.sent_info.least_unacked > peer_least_packet_awaiting_ack_) { - outgoing_ack_.received_info.ClearMissingBefore( - incoming_ack.sent_info.least_unacked); + bool missed_packets = + DontWaitForPacketsBefore(incoming_ack.sent_info.least_unacked); + if (missed_packets || incoming_ack.sent_info.least_unacked > + outgoing_ack_.received_info.largest_observed + 1) { + DVLOG(1) << "Updating entropy hashed since we missed packets"; + // There were some missing packets that we won't ever get now. Recalculate + // the received entropy hash. + entropy_manager_.RecalculateReceivedEntropyHash( + incoming_ack.sent_info.least_unacked, + incoming_ack.sent_info.entropy_hash); + } peer_least_packet_awaiting_ack_ = incoming_ack.sent_info.least_unacked; - } - + // TODO(satyamshekhar): We get this iterator O(logN) in + // RecalculateReceivedEntropyHash also. + entropy_manager_.ClearReceivedEntropyBefore( + peer_least_packet_awaiting_ack_); + } + DCHECK(outgoing_ack_.received_info.missing_packets.empty() || + *outgoing_ack_.received_info.missing_packets.begin() >= + peer_least_packet_awaiting_ack_); // Possibly close any FecGroups which are now irrelevant CloseFecGroupsBefore(incoming_ack.sent_info.least_unacked + 1); } @@ -450,7 +433,8 @@ void QuicConnection::UpdatePacketInformationSentByPeer( void QuicConnection::OnFecData(const QuicFecData& fec) { DCHECK_NE(0u, last_header_.fec_group); QuicFecGroup* group = GetFecGroup(); - group->UpdateFec(last_header_.packet_sequence_number, fec); + group->UpdateFec(last_header_.packet_sequence_number, + last_header_.fec_entropy_flag, fec); } void QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) { @@ -472,22 +456,31 @@ void QuicConnection::OnConnectionCloseFrame( CloseConnection(frame.error_code, true); } +void QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) { + DLOG(INFO) << "Go away received with error " + << QuicUtils::ErrorToString(frame.error_code) + << " and reason:" << frame.reason_phrase; + visitor_->OnGoAway(frame); +} + void QuicConnection::OnPacketComplete() { + // TODO(satyamshekhar): Don't do anything if this packet closed the + // connection. if (!last_packet_revived_) { DLOG(INFO) << "Got packet " << last_header_.packet_sequence_number << " with " << last_stream_frames_.size() << " stream frames for " << last_header_.public_header.guid; congestion_manager_.RecordIncomingPacket( last_size_, last_header_.packet_sequence_number, - clock_->Now(), last_packet_revived_); + time_of_last_received_packet_, last_packet_revived_); } else { DLOG(INFO) << "Got revived packet with " << last_stream_frames_.size() << " frames."; } - if (last_stream_frames_.empty() || - visitor_->OnPacket(self_address_, peer_address_, - last_header_, last_stream_frames_)) { + if ((last_stream_frames_.empty() || + visitor_->OnPacket(self_address_, peer_address_, + last_header_, last_stream_frames_))) { RecordPacketReceived(last_header_); } @@ -495,6 +488,14 @@ void QuicConnection::OnPacketComplete() { last_stream_frames_.clear(); } +QuicAckFrame* QuicConnection::CreateAckFrame() { + return new QuicAckFrame(outgoing_ack_); +} + +QuicCongestionFeedbackFrame* QuicConnection::CreateFeedbackFrame() { + return new QuicCongestionFeedbackFrame(outgoing_congestion_feedback_); +} + void QuicConnection::MaybeSendAckInResponseToPacket() { if (send_ack_in_response_to_packet_) { SendAck(); @@ -507,62 +508,16 @@ void QuicConnection::MaybeSendAckInResponseToPacket() { } QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id, - StringPiece data, - QuicStreamOffset offset, - bool fin) { - size_t total_bytes_consumed = 0; - bool fin_consumed = false; - - while (queued_packets_.empty()) { - packet_creator_.MaybeStartFEC(); - QuicFrame frame; - size_t bytes_consumed = packet_creator_.CreateStreamFrame( - id, data, offset, fin, &frame); - bool success = packet_creator_.AddFrame(frame); - DCHECK(success); - - total_bytes_consumed += bytes_consumed; - offset += bytes_consumed; - fin_consumed = fin && bytes_consumed == data.size(); - data.remove_prefix(bytes_consumed); - - // TODO(ianswett): Currently this does not pack stream data together, - // because SendStreamData does not know if there are more streams to write. - // TODO(ianswett): Restore packet reordering. - SendOrQueueCurrentPacket(); - - if (packet_creator_.ShouldSendFec(false)) { - PacketPair fec_pair = packet_creator_.SerializeFec(); - // Never retransmit FEC packets. - SendOrQueuePacket(fec_pair.first, fec_pair.second, !kForce); - } - - if (data.empty()) { - // We're done writing the data. Exit the loop. - // We don't make this a precondition because we could have 0 bytes of data - // if we're simply writing a fin. - break; - } - } - // Ensure the FEC group is closed at the end of this method. - if (packet_creator_.ShouldSendFec(true)) { - PacketPair fec_pair = packet_creator_.SerializeFec(); - // Never retransmit FEC packets. - SendOrQueuePacket(fec_pair.first, fec_pair.second, !kForce); - } - return QuicConsumedData(total_bytes_consumed, fin_consumed); + base::StringPiece data, + QuicStreamOffset offset, + bool fin) { + return packet_generator_.ConsumeData(id, data, offset, fin); } void QuicConnection::SendRstStream(QuicStreamId id, - QuicErrorCode error, - QuicStreamOffset offset) { - queued_control_frames_.push_back(QuicFrame( - new QuicRstStreamFrame(id, offset, error))); - - // Try to write immediately if possible. - if (CanWrite(!kIsRetransmission)) { - WriteQueuedData(kFlush); - } + QuicErrorCode error) { + packet_generator_.AddControlFrame( + QuicFrame(new QuicRstStreamFrame(id, error))); } void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address, @@ -580,25 +535,24 @@ void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address, } bool QuicConnection::OnCanWrite() { + LOG(INFO) << "here!!!"; write_blocked_ = false; - WriteQueuedData(!kFlush); + WriteQueuedPackets(); - // Ensure there's enough room for a StreamFrame before calling the visitor. - if (packet_creator_.BytesFree() <= kMinStreamFrameLength) { - SendOrQueueCurrentPacket(); - } - - // If we've sent everything we had queued and we're still not blocked, let the - // visitor know it can write more. + // Sending queued packets may have caused the socket to become write blocked, + // or the congestion manager to prohibit sending. If we've sent everything + // we had queued and we're still not blocked, let the visitor know it can + // write more. + // TODO(rch): shouldn't this be "if (CanWrite(false))" if (!write_blocked_) { + packet_generator_.StartBatchOperations(); bool all_bytes_written = visitor_->OnCanWrite(); - // If the latest write caused a socket-level blockage, return false: we will - // be rescheduled by the kernel. - if (write_blocked_) { - return false; - } - if (!all_bytes_written && !helper_->IsSendAlarmSet()) { + packet_generator_.FinishBatchOperations(); + + // After the visitor writes, it may have caused the socket to become write + // blocked or the congestion manager to prohibit sending, so check again. + if (!write_blocked_ && !all_bytes_written && !helper_->IsSendAlarmSet()) { // We're not write blocked, but some stream didn't write out all of its // bytes. Register for 'immediate' resumption so we'll keep writing after // other quic connections have had a chance to use the socket. @@ -606,20 +560,12 @@ bool QuicConnection::OnCanWrite() { } } - // If a write can still be performed, ensure there are no pending frames, - // even if they didn't fill a packet. - if (packet_creator_.HasPendingFrames() && CanWrite(!kIsRetransmission)) { - SendOrQueueCurrentPacket(); - } - return !write_blocked_; } -bool QuicConnection::WriteQueuedData(bool flush) { +bool QuicConnection::WriteQueuedPackets() { DCHECK(!write_blocked_); - DCHECK(!packet_creator_.HasPendingFrames()); - // Send all queued packets first. size_t num_queued_packets = queued_packets_.size() + 1; QueuedPacketList::iterator packet_iterator = queued_packets_.begin(); while (!write_blocked_ && !helper_->IsSendAlarmSet() && @@ -633,52 +579,37 @@ bool QuicConnection::WriteQueuedData(bool flush) { packet_iterator->packet, !kForce)) { packet_iterator = queued_packets_.erase(packet_iterator); } else { - // TODO(ianswett): Why not break or return false here? + // Continue, because some queued packets may still be writable. ++packet_iterator; } } - if (write_blocked_) { - return false; - } - - while ((!queued_control_frames_.empty() || should_send_ack_ || - should_send_congestion_feedback_) && CanWrite(!kIsRetransmission)) { - bool full_packet = false; - if (!queued_control_frames_.empty()) { - full_packet = !packet_creator_.AddFrame(queued_control_frames_.back()); - if (!full_packet) { - queued_control_frames_.pop_back(); - } - } else if (should_send_ack_) { - full_packet = !packet_creator_.AddFrame(QuicFrame(&outgoing_ack_)); - if (!full_packet) { - should_send_ack_ = false; - } - } else if (should_send_congestion_feedback_) { - full_packet = !packet_creator_.AddFrame( - QuicFrame(&outgoing_congestion_feedback_)); - if (!full_packet) { - should_send_congestion_feedback_ = false; - } - } - - if (full_packet) { - SendOrQueueCurrentPacket(); - } - } - - if (flush && packet_creator_.HasPendingFrames()) { - SendOrQueueCurrentPacket(); - } - return !write_blocked_; } void QuicConnection::RecordPacketReceived(const QuicPacketHeader& header) { + DLOG(INFO) << "Recording received packet: " << header.packet_sequence_number; QuicPacketSequenceNumber sequence_number = header.packet_sequence_number; - DCHECK(outgoing_ack_.received_info.IsAwaitingPacket(sequence_number)); - outgoing_ack_.received_info.RecordReceived(sequence_number); + DCHECK(IsAwaitingPacket(outgoing_ack_.received_info, sequence_number)); + + InsertMissingPacketsBetween( + &outgoing_ack_.received_info, + max(outgoing_ack_.received_info.largest_observed + 1, + peer_least_packet_awaiting_ack_), + header.packet_sequence_number); + + if (outgoing_ack_.received_info.largest_observed > + header.packet_sequence_number) { + // We've gotten one of the out of order packets - remove it from our + // "missing packets" list. + DVLOG(1) << "Removing " << sequence_number << " from missing list"; + outgoing_ack_.received_info.missing_packets.erase(sequence_number); + } + outgoing_ack_.received_info.largest_observed = max( + outgoing_ack_.received_info.largest_observed, + header.packet_sequence_number); + entropy_manager_.RecordReceivedPacketEntropyHash(sequence_number, + header.entropy_hash); } bool QuicConnection::MaybeRetransmitPacketForRTO( @@ -688,7 +619,7 @@ bool QuicConnection::MaybeRetransmitPacketForRTO( if (!ContainsKey(unacked_packets_, sequence_number)) { DVLOG(2) << "alarm fired for " << sequence_number - << " but it has been acked or already retransmitted with " + << " but it has been acked or already retransmitted with" << " different sequence number."; // So no extra delay is added for this packet. return true; @@ -719,25 +650,29 @@ void QuicConnection::RetransmitPacket( // ignored by MaybeRetransmitPacketForRTO. DCHECK(unacked_it != unacked_packets_.end()); DCHECK(retransmission_it != retransmission_map_.end()); - UnackedPacket* unacked = unacked_it->second; + RetransmittableFrames* unacked = unacked_it->second; // TODO(ianswett): Never change the sequence number of the connect packet. // Re-packetize the frames with a new sequence number for retransmission. // Retransmitted data packets do not use FEC, even when it's enabled. - PacketPair packetpair = packet_creator_.SerializeAllFrames(unacked->frames); - RetransmissionInfo retransmission_info(packetpair.first); + SerializedPacket serialized_packet = + packet_creator_.SerializeAllFrames(unacked->frames()); + RetransmissionInfo retransmission_info(serialized_packet.sequence_number); retransmission_info.number_retransmissions = retransmission_it->second.number_retransmissions + 1; - retransmission_map_.insert(make_pair(packetpair.first, retransmission_info)); + retransmission_map_.insert(make_pair(serialized_packet.sequence_number, + retransmission_info)); // Remove info with old sequence number. unacked_packets_.erase(unacked_it); retransmission_map_.erase(retransmission_it); DVLOG(1) << "Retransmitting unacked packet " << sequence_number << " as " - << packetpair.first; - unacked_packets_.insert(make_pair(packetpair.first, unacked)); - // Make sure if this was our least unacked packet, that we update our - // outgoing ack. If this wasn't the least unacked, this is a no-op. - UpdateLeastUnacked(sequence_number); - SendOrQueuePacket(packetpair.first, packetpair.second, !kForce); + << serialized_packet.sequence_number; + DCHECK(unacked_packets_.empty() || + unacked_packets_.rbegin()->first < serialized_packet.sequence_number); + unacked_packets_.insert(make_pair(serialized_packet.sequence_number, + unacked)); + SendOrQueuePacket(serialized_packet.sequence_number, + serialized_packet.packet, + serialized_packet.entropy_hash); } bool QuicConnection::CanWrite(bool is_retransmission) { @@ -746,7 +681,8 @@ bool QuicConnection::CanWrite(bool is_retransmission) { if (write_blocked_ || helper_->IsSendAlarmSet()) { return false; } - QuicTime::Delta delay = congestion_manager_.TimeUntilSend(is_retransmission); + QuicTime::Delta delay = congestion_manager_.TimeUntilSend(clock_->Now(), + is_retransmission); // If the scheduler requires a delay, then we can not send this packet now. if (!delay.IsZero() && !delay.IsInfinite()) { // TODO(pwestin): we need to handle delay.IsInfinite() separately. @@ -774,8 +710,10 @@ void QuicConnection::MaybeSetupRetransmission( RetransmissionInfo retransmission_info = it->second; QuicTime::Delta retransmission_delay = congestion_manager_.GetRetransmissionDelay( + unacked_packets_.size(), retransmission_info.number_retransmissions); - retransmission_info.scheduled_time = clock_->Now().Add(retransmission_delay); + retransmission_info.scheduled_time = + clock_->ApproximateNow().Add(retransmission_delay); retransmission_timeouts_.push(retransmission_info); // Do not set the retransmisson alarm if we're already handling the @@ -784,13 +722,8 @@ void QuicConnection::MaybeSetupRetransmission( if (!handling_retransmission_timeout_) { helper_->SetRetransmissionAlarm(retransmission_delay); } - - // The second case should never happen in the real world, but does here - // because we sometimes send out of order to validate corner cases. - if (outgoing_ack_.sent_info.least_unacked == 0 || - sequence_number < outgoing_ack_.sent_info.least_unacked) { - outgoing_ack_.sent_info.least_unacked = sequence_number; - } + // TODO(satyamshekhar): restore pacekt reordering with Ian's TODO in + // SendStreamData(). } bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number, @@ -811,23 +744,30 @@ bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number, return false; } - scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*packet)); - DLOG(INFO) << "Sending packet : " + scoped_ptr<QuicEncryptedPacket> encrypted( + framer_.EncryptPacket(sequence_number, *packet)); + DLOG(INFO) << "Sending packet number " << sequence_number << " : " << (packet->is_fec_packet() ? "FEC " : (ContainsKey(retransmission_map_, sequence_number) ? - "data bearing " : " ack only ")) - << "packet " << sequence_number; + "data bearing " : " ack only ")); + DCHECK(encrypted->length() <= kMaxPacketSize) << "Packet " << sequence_number << " will not be read; too large: " << packet->length() << " " << encrypted->length() << " " << outgoing_ack_; int error; + QuicTime now = clock_->Now(); int rv = helper_->WritePacketToWire(*encrypted, &error); if (rv == -1 && error == ERR_IO_PENDING) { + // TODO(satyashekhar): It might be more efficient (fewer system calls), if + // all connections share this variable i.e this becomes a part of + // PacketWriterInterface. write_blocked_ = true; return false; } + time_of_last_sent_packet_ = now; + DVLOG(1) << "time of last sent packet: " << now.ToMicroseconds(); // TODO(wtc): Is it correct to continue if the write failed. // Set the retransmit alarm only when we have sent the packet to the client @@ -835,44 +775,36 @@ bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number, // an entry to retransmission_timeout_ every time we attempt a write. MaybeSetupRetransmission(sequence_number); - time_of_last_packet_ = clock_->Now(); - DVLOG(1) << "last packet: " << time_of_last_packet_.ToMicroseconds(); - - congestion_manager_.SentPacket(sequence_number, packet->length(), + congestion_manager_.SentPacket(sequence_number, now, packet->length(), is_retransmission); delete packet; return true; } -void QuicConnection::SendOrQueueCurrentPacket() { - QuicFrames retransmittable_frames; - PacketPair pair = packet_creator_.SerializePacket(&retransmittable_frames); - const bool should_retransmit = !retransmittable_frames.empty(); - if (should_retransmit) { - UnackedPacket* unacked = new UnackedPacket(retransmittable_frames); - for (size_t i = 0; i < retransmittable_frames.size(); ++i) { - if (retransmittable_frames[i].type == STREAM_FRAME) { - DCHECK(unacked->data.empty()); - // Make an owned copy of the StringPiece. - unacked->data = - retransmittable_frames[i].stream_frame->data.as_string(); - // Ensure the frame's StringPiece points to the owned copy of the data. - retransmittable_frames[i].stream_frame->data = - StringPiece(unacked->data); - } - } - unacked_packets_.insert(make_pair(pair.first, unacked)); +bool QuicConnection::OnSerializedPacket( + const SerializedPacket& serialized_packet) { + if (serialized_packet.retransmittable_frames != NULL) { + DCHECK(unacked_packets_.empty() || + unacked_packets_.rbegin()->first < + serialized_packet.sequence_number); + unacked_packets_.insert( + make_pair(serialized_packet.sequence_number, + serialized_packet.retransmittable_frames)); // All unacked packets might be retransmitted. - retransmission_map_.insert(make_pair(pair.first, - RetransmissionInfo(pair.first))); + retransmission_map_.insert( + make_pair(serialized_packet.sequence_number, + RetransmissionInfo(serialized_packet.sequence_number))); } - SendOrQueuePacket(pair.first, pair.second, !kForce); + return SendOrQueuePacket(serialized_packet.sequence_number, + serialized_packet.packet, + serialized_packet.entropy_hash); } bool QuicConnection::SendOrQueuePacket(QuicPacketSequenceNumber sequence_number, QuicPacket* packet, - bool force) { - if (!WritePacket(sequence_number, packet, force)) { + QuicPacketEntropyHash entropy_hash) { + entropy_manager_.RecordSentPacketEntropyHash(sequence_number, entropy_hash); + if (!WritePacket(sequence_number, packet, !kForce)) { queued_packets_.push_back(QueuedPacket(sequence_number, packet)); return false; } @@ -888,28 +820,39 @@ bool QuicConnection::ShouldSimulateLostPacket() { */ } -void QuicConnection::SendAck() { - helper_->ClearAckAlarm(); - - if (!ContainsKey(unacked_packets_, outgoing_ack_.sent_info.least_unacked)) { - // At some point, all packets were acked, and we set least_unacked to a - // packet we will not retransmit. Make sure we update it. - UpdateLeastUnacked(outgoing_ack_.sent_info.least_unacked); +void QuicConnection::UpdateOutgoingAck() { + if (!unacked_packets_.empty()) { + outgoing_ack_.sent_info.least_unacked = unacked_packets_.begin()->first; + } else { + // If there are no unacked packets, set the least unacked packet to + // sequence_number() + 1 since that will be the sequence number of this + // ack packet whenever it is sent. + outgoing_ack_.sent_info.least_unacked = + packet_creator_.sequence_number() + 1; } + outgoing_ack_.sent_info.entropy_hash = entropy_manager_.SentEntropyHash( + outgoing_ack_.sent_info.least_unacked - 1); + outgoing_ack_.received_info.entropy_hash = + entropy_manager_.ReceivedEntropyHash( + outgoing_ack_.received_info.largest_observed); +} - DVLOG(1) << "Sending ack " << outgoing_ack_; - - should_send_ack_ = true; +void QuicConnection::SendAck() { + helper_->ClearAckAlarm(); + UpdateOutgoingAck(); + DVLOG(1) << "Sending ack: " << outgoing_ack_; + // TODO(rch): delay this until the CreateFeedbackFrame + // method is invoked. This requires changes SetShouldSendAck + // to be a no-arg method, and re-jiggering its implementation. + bool send_feedback = false; if (congestion_manager_.GenerateCongestionFeedback( &outgoing_congestion_feedback_)) { DVLOG(1) << "Sending feedback " << outgoing_congestion_feedback_; - should_send_congestion_feedback_ = true; - } - // Try to write immediately if possible. - if (CanWrite(!kIsRetransmission)) { - WriteQueuedData(kFlush); + send_feedback = true; } + + packet_generator_.SetShouldSendAck(send_feedback); } QuicTime QuicConnection::OnRetransmissionTimeout() { @@ -926,7 +869,7 @@ QuicTime QuicConnection::OnRetransmissionTimeout() { !retransmission_timeouts_.empty(); ++i) { RetransmissionInfo retransmission_info = retransmission_timeouts_.top(); DCHECK(retransmission_info.scheduled_time.IsInitialized()); - if (retransmission_info.scheduled_time > clock_->Now()) { + if (retransmission_info.scheduled_time > clock_->ApproximateNow()) { break; } retransmission_timeouts_.pop(); @@ -934,7 +877,7 @@ QuicTime QuicConnection::OnRetransmissionTimeout() { DLOG(INFO) << "MaybeRetransmitPacketForRTO failed: " << "adding an extra delay for " << retransmission_info.sequence_number; - retransmission_info.scheduled_time = clock_->Now().Add( + retransmission_info.scheduled_time = clock_->ApproximateNow().Add( congestion_manager_.DefaultRetransmissionTime()); retransmission_timeouts_.push(retransmission_info); } @@ -960,8 +903,9 @@ void QuicConnection::MaybeProcessRevivedPacket() { char revived_payload[kMaxPacketSize]; size_t len = group->Revive(&revived_header, revived_payload, kMaxPacketSize); revived_header.public_header.guid = guid_; - revived_header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - revived_header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + revived_header.public_header.version_flag = false; + revived_header.public_header.reset_flag = false; + revived_header.fec_flag = false; revived_header.fec_group = kNoFecOffset; group_map_.erase(last_header_.fec_group); delete group; @@ -971,7 +915,7 @@ void QuicConnection::MaybeProcessRevivedPacket() { debug_visitor_->OnRevivedPacket(revived_header, StringPiece(revived_payload, len)); } - framer_.ProcessRevivedPacket(revived_header, + framer_.ProcessRevivedPacket(&revived_header, StringPiece(revived_payload, len)); } @@ -991,19 +935,25 @@ void QuicConnection::SendConnectionClose(QuicErrorCode error) { SendConnectionCloseWithDetails(error, string()); } -void QuicConnection::SendConnectionCloseWithDetails(QuicErrorCode error, - const string& details) { +void QuicConnection::SendConnectionClosePacket(QuicErrorCode error, + const string& details) { DLOG(INFO) << "Force closing with error " << QuicUtils::ErrorToString(error) << " (" << error << ")"; QuicConnectionCloseFrame frame; frame.error_code = error; frame.error_details = details; + UpdateOutgoingAck(); frame.ack_frame = outgoing_ack_; - PacketPair packetpair = packet_creator_.CloseConnection(&frame); - // There's no point in retransmitting/queueing this: we're closing the - // connection. - WritePacket(packetpair.first, packetpair.second, kForce); + SerializedPacket serialized_packet = + packet_creator_.SerializeConnectionClose(&frame); + SendOrQueuePacket(serialized_packet.sequence_number, serialized_packet.packet, + serialized_packet.entropy_hash); +} + +void QuicConnection::SendConnectionCloseWithDetails(QuicErrorCode error, + const string& details) { + SendConnectionClosePacket(error, details); CloseConnection(error, false); } @@ -1014,6 +964,15 @@ void QuicConnection::CloseConnection(QuicErrorCode error, bool from_peer) { visitor_->ConnectionClose(error, from_peer); } +void QuicConnection::SendGoAway(QuicErrorCode error, + QuicStreamId last_good_stream_id, + const string& reason) { + DLOG(INFO) << "Going away with error " << QuicUtils::ErrorToString(error) + << " (" << error << ")"; + packet_generator_.AddControlFrame( + QuicFrame(new QuicGoAwayFrame(error, last_good_stream_id, reason))); +} + void QuicConnection::CloseFecGroupsBefore( QuicPacketSequenceNumber sequence_number) { FecGroupMap::iterator it = group_map_.begin(); @@ -1036,14 +995,16 @@ void QuicConnection::CloseFecGroupsBefore( } bool QuicConnection::HasQueuedData() const { - return !queued_packets_.empty() || should_send_ack_ || - should_send_congestion_feedback_; + return !queued_packets_.empty() || packet_generator_.HasQueuedData(); } bool QuicConnection::CheckForTimeout() { - QuicTime now = clock_->Now(); - QuicTime::Delta delta = now.Subtract(time_of_last_packet_); - DVLOG(1) << "last_packet " << time_of_last_packet_.ToMicroseconds() + QuicTime now = clock_->ApproximateNow(); + QuicTime time_of_last_packet = std::max(time_of_last_received_packet_, + time_of_last_sent_packet_); + + QuicTime::Delta delta = now.Subtract(time_of_last_packet); + DVLOG(1) << "last packet " << time_of_last_packet.ToMicroseconds() << " now:" << now.ToMicroseconds() << " delta:" << delta.ToMicroseconds(); if (delta >= timeout_) { diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index 5e046ad..dd009ae 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -17,17 +17,21 @@ #define NET_QUIC_QUIC_CONNECTION_H_ #include <list> +#include <map> #include <queue> #include <set> #include <vector> #include "base/hash_tables.h" #include "net/base/ip_endpoint.h" +#include "net/base/linked_hash_map.h" #include "net/quic/congestion_control/quic_congestion_manager.h" #include "net/quic/quic_blocked_writer_interface.h" #include "net/quic/quic_fec_group.h" #include "net/quic/quic_framer.h" #include "net/quic/quic_packet_creator.h" +#include "net/quic/quic_packet_entropy_manager.h" +#include "net/quic/quic_packet_generator.h" #include "net/quic/quic_protocol.h" namespace net { @@ -44,8 +48,6 @@ class QuicConnectionPeer; class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface { public: - typedef std::set<QuicPacketSequenceNumber> AckedPackets; - virtual ~QuicConnectionVisitorInterface() {} // A simple visitor interface for dealing with data frames. The session @@ -60,12 +62,15 @@ class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface { // Called when the stream is reset by the peer. virtual void OnRstStream(const QuicRstStreamFrame& frame) = 0; + // Called when the connection is going away according to the peer. + virtual void OnGoAway(const QuicGoAwayFrame& frame) = 0; + // Called when the connection is closed either locally by the framer, or // remotely by the peer. virtual void ConnectionClose(QuicErrorCode error, bool from_peer) = 0; // Called when packets are acked by the peer. - virtual void OnAck(AckedPackets acked_packets) = 0; + virtual void OnAck(const SequenceNumberSet& acked_packets) = 0; // Called when a blocked socket becomes writable. If all pending bytes for // this visitor are consumed by the connection successfully this should @@ -170,8 +175,10 @@ class NET_EXPORT_PRIVATE QuicConnectionHelperInterface { virtual void ClearAckAlarm() = 0; }; -class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface, - public QuicBlockedWriterInterface { +class NET_EXPORT_PRIVATE QuicConnection + : public QuicFramerVisitorInterface, + public QuicBlockedWriterInterface, + public QuicPacketGenerator::DelegateInterface { public: // Constructs a new QuicConnection for the specified |guid| and |address|. // |helper| will be owned by this connection. @@ -193,8 +200,14 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface, bool fin); // Send a stream reset frame to the peer. virtual void SendRstStream(QuicStreamId id, - QuicErrorCode error, - QuicStreamOffset offset); + QuicErrorCode error); + + // Sends the connection close packet without affecting the state of the + // connection. This should only be called if the session is actively being + // destroyed: otherwise call SendConnectionCloseWithDetails instead. + virtual void SendConnectionClosePacket(QuicErrorCode error, + const std::string& details); + // Sends a connection close frame to the peer, and closes the connection by // calling CloseConnection(notifying the visitor as it does so). virtual void SendConnectionClose(QuicErrorCode error); @@ -202,6 +215,9 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface, const std::string& details); // Notifies the visitor of the close and marks the connection as disconnected. void CloseConnection(QuicErrorCode error, bool from_peer); + virtual void SendGoAway(QuicErrorCode error, + QuicStreamId last_good_stream_id, + const std::string& reason); // Processes an incoming UDP packet (consisting of a QuicEncryptedPacket) from // the peer. If processing this packet permits a packet to be revived from @@ -228,11 +244,17 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface, virtual void OnCongestionFeedbackFrame( const QuicCongestionFeedbackFrame& frame) OVERRIDE; virtual void OnRstStreamFrame(const QuicRstStreamFrame& frame) OVERRIDE; + virtual void OnGoAwayFrame(const QuicGoAwayFrame& frame) OVERRIDE; virtual void OnConnectionCloseFrame( const QuicConnectionCloseFrame& frame) OVERRIDE; virtual void OnFecData(const QuicFecData& fec) OVERRIDE; virtual void OnPacketComplete() OVERRIDE; + // QuicPacketGenerator::DelegateInterface + virtual QuicAckFrame* CreateAckFrame() OVERRIDE; + virtual QuicCongestionFeedbackFrame* CreateFeedbackFrame() OVERRIDE; + virtual bool OnSerializedPacket(const SerializedPacket& packet) OVERRIDE; + // Accessors void set_visitor(QuicConnectionVisitorInterface* visitor) { visitor_ = visitor; @@ -286,19 +308,22 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface, QuicTime OnRetransmissionTimeout(); protected: - // Serializes then sends or queues the packet currently open. - void SendOrQueueCurrentPacket(); + // Deletes all missing packets before least unacked. The connection won't + // process any packets with sequence number before |least_unacked| that it + // received after this call. Returns true if there were missing packets before + // |least_unacked| unacked, false otherwise. + bool DontWaitForPacketsBefore(QuicPacketSequenceNumber least_unacked); // Send a packet to the peer. If |sequence_number| is present in the // |retransmission_map_|, then contents of this packet will be retransmitted // with a new sequence number if it's not acked by the peer. Deletes // |packet| via WritePacket call or transfers ownership to QueuedPacket, - // ultimately deleted via WritePacket. If |force| is true, then the packet - // will be sent immediately and the send scheduler will not be consulted. + // ultimately deleted via WritePacket. Also, it updates the entropy map + // corresponding to |sequence_number| using |entropy_hash|. // TODO(wtc): none of the callers check the return value. virtual bool SendOrQueuePacket(QuicPacketSequenceNumber sequence_number, QuicPacket* packet, - bool force); + QuicPacketEntropyHash entropy_hash); // Writes the given packet to socket with the help of helper. Returns true on // successful write, false otherwise. However, behavior is undefined if @@ -324,15 +349,6 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface, // Updates internal state based in incoming_ack.sent_info void UpdatePacketInformationSentByPeer(const QuicAckFrame& incoming_ack); - // Utility which sets SetLeastUnacked to least_unacked, and updates the list - // of non-retransmitting packets accordingly. - void SetLeastUnacked(QuicPacketSequenceNumber least_unacked); - - // Helper to update least unacked. If acked_sequence_number was not the least - // unacked packet, this is a no-op. If it was the least unacked packet, - // this finds the new least unacked packet and updates the outgoing ack frame. - void UpdateLeastUnacked(QuicPacketSequenceNumber acked_sequence_number); - QuicConnectionHelperInterface* helper() { return helper_; } private: @@ -351,16 +367,6 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface, QuicPacket* packet; }; - struct UnackedPacket { - explicit UnackedPacket(QuicFrames unacked_frames); - UnackedPacket(QuicFrames unacked_frames, std::string data); - ~UnackedPacket(); - - QuicFrames frames; - // Data referenced by the StringPiece of a QuicStreamFrame. - std::string data; - }; - struct RetransmissionInfo { explicit RetransmissionInfo(QuicPacketSequenceNumber sequence_number) : sequence_number(sequence_number), @@ -386,8 +392,8 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface, }; typedef std::list<QueuedPacket> QueuedPacketList; - typedef base::hash_map<QuicPacketSequenceNumber, - UnackedPacket*> UnackedPacketMap; + typedef linked_hash_map<QuicPacketSequenceNumber, + RetransmittableFrames*> UnackedPacketMap; typedef std::map<QuicFecGroupNumber, QuicFecGroup*> FecGroupMap; typedef base::hash_map<QuicPacketSequenceNumber, RetransmissionInfo> RetransmissionMap; @@ -396,24 +402,22 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface, RetransmissionInfoComparator> RetransmissionTimeouts; - static void DeleteEnclosedFrames(UnackedPacket* unacked); - // Checks if a packet can be written now, and sets the timer if necessary. - bool CanWrite(bool is_retransmission); + virtual bool CanWrite(bool is_retransmission) OVERRIDE; void MaybeSetupRetransmission(QuicPacketSequenceNumber sequence_number); bool IsRetransmission(QuicPacketSequenceNumber sequence_number); - // Writes as much queued data as possible. The connection must not be - // blocked when this is called. Will leave queued frames in the PacketCreator - // if the queued data was not enough to fill a packet and |force_send| is - // false. - bool WriteQueuedData(bool flush); + // Writes as many queued packets as possible. The connection must not be + // blocked when this is called. + bool WriteQueuedPackets(); // If a packet can be revived from the current FEC group, then // revive and process the packet. void MaybeProcessRevivedPacket(); + void UpdateOutgoingAck(); + void MaybeSendAckInResponseToPacket(); // Get the FEC group associate with the last processed packet. @@ -442,14 +446,19 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface, QuicPacketHeader last_header_; std::vector<QuicStreamFrame> last_stream_frames_; - bool should_send_ack_; - bool should_send_congestion_feedback_; QuicAckFrame outgoing_ack_; QuicCongestionFeedbackFrame outgoing_congestion_feedback_; - // Track some client state so we can do less bookkeeping + // Track some peer state so we can do less bookkeeping + // Largest sequence sent by the peer which had an ack frame (latest ack info). QuicPacketSequenceNumber largest_seen_packet_with_ack_; + // Largest sequence number that the peer has observed. Mostly received, + // missing in case of truncated acks. QuicPacketSequenceNumber peer_largest_observed_packet_; + // Least sequence number which the peer is still waiting for. + QuicPacketSequenceNumber least_packet_awaited_by_peer_; + // Least sequence number of the the packet sent by the peer for which it + // hasn't received an ack. QuicPacketSequenceNumber peer_least_packet_awaiting_ack_; // When new packets are created which may be retransmitted, they are added @@ -476,22 +485,26 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface, // unacked_packets_ if they are to be retransmitted. QueuedPacketList queued_packets_; - // Pending control frames, besides the ack and congestion control frames. - QuicFrames queued_control_frames_; - // True when the socket becomes unwritable. bool write_blocked_; FecGroupMap group_map_; + QuicPacketEntropyManager entropy_manager_; + QuicConnectionVisitorInterface* visitor_; QuicConnectionDebugVisitorInterface* debug_visitor_; QuicPacketCreator packet_creator_; + QuicPacketGenerator packet_generator_; // Network idle time before we kill of this connection. const QuicTime::Delta timeout_; - // The time that we got or tried to send a packet for this connection. - QuicTime time_of_last_packet_; + + // The time that we got a packet for this connection. + QuicTime time_of_last_received_packet_; + + // The time that we last sent a packet for this connection. + QuicTime time_of_last_sent_packet_; // Congestion manager which controls the rate the connection sends packets // as well as collecting and generating congestion feedback. diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc index f64f867..ea0637b 100644 --- a/net/quic/quic_connection_helper_test.cc +++ b/net/quic/quic_connection_helper_test.cc @@ -37,6 +37,8 @@ class TestConnection : public QuicConnection { void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) { QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm); } + + using QuicConnection::SendOrQueuePacket; }; class QuicConnectionHelperTest : public ::testing::Test { @@ -55,7 +57,7 @@ class QuicConnectionHelperTest : public ::testing::Test { QuicConnectionHelperTest() : guid_(2), framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)), - creator_(guid_, &framer_), + creator_(guid_, &framer_, QuicRandom::GetInstance()), net_log_(BoundNetLog()), frame_(1, false, 0, kData) { Initialize(); @@ -100,7 +102,7 @@ class QuicConnectionHelperTest : public ::testing::Test { helper_.reset(new QuicConnectionHelper(runner_.get(), &clock_, &random_generator_, socket)); send_algorithm_ = new testing::StrictMock<MockSendAlgorithm>(); - EXPECT_CALL(*send_algorithm_, TimeUntilSend(_)). + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _)). WillRepeatedly(testing::Return(QuicTime::Delta::Zero())); connection_.reset(new TestConnection(guid_, IPEndPoint(), helper_.get())); connection_->set_visitor(&visitor_); @@ -115,12 +117,24 @@ class QuicConnectionHelperTest : public ::testing::Test { return ConstructPacket(header_, QuicFrame(&frame_)); } + // Returns a newly created packet to send kData on stream 1. + QuicPacket* ConstructRawDataPacket( + QuicPacketSequenceNumber sequence_number) { + InitializeHeader(sequence_number); + + QuicFrames frames; + frames.push_back(QuicFrame(&frame_)); + return framer_.ConstructFrameDataPacket(header_, frames).packet; + } + // Returns a newly created packet to send ack data. QuicEncryptedPacket* ConstructAckPacket( QuicPacketSequenceNumber sequence_number) { InitializeHeader(sequence_number); QuicAckFrame ack(0, sequence_number); + ack.sent_info.entropy_hash = 0; + ack.received_info.entropy_hash = 0; QuicCongestionFeedbackFrame feedback; feedback.type = kTCP; @@ -131,8 +145,8 @@ class QuicConnectionHelperTest : public ::testing::Test { frames.push_back(QuicFrame(&ack)); frames.push_back(QuicFrame(&feedback)); scoped_ptr<QuicPacket> packet( - framer_.ConstructFrameDataPacket(header_, frames)); - return framer_.EncryptPacket(*packet); + framer_.ConstructFrameDataPacket(header_, frames).packet); + return framer_.EncryptPacket(header_.packet_sequence_number, *packet); } // Returns a newly created packet to send a connection close frame. @@ -142,7 +156,9 @@ class QuicConnectionHelperTest : public ::testing::Test { InitializeHeader(sequence_number); QuicFrames frames; - QuicAckFrame ack(0, least_waiting); + QuicAckFrame ack(0, least_waiting + 1); + ack.sent_info.entropy_hash = 0; + ack.received_info.entropy_hash = 0; QuicConnectionCloseFrame close; close.error_code = QUIC_CONNECTION_TIMED_OUT; close.ack_frame = ack; @@ -162,9 +178,12 @@ class QuicConnectionHelperTest : public ::testing::Test { private: void InitializeHeader(QuicPacketSequenceNumber sequence_number) { header_.public_header.guid = guid_; - header_.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header_.public_header.reset_flag = false; + header_.public_header.version_flag = false; header_.packet_sequence_number = sequence_number; - header_.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header_.entropy_flag = false; + header_.fec_entropy_flag = false; + header_.fec_flag = false; header_.fec_group = 0; } @@ -173,8 +192,8 @@ class QuicConnectionHelperTest : public ::testing::Test { QuicFrames frames; frames.push_back(frame); scoped_ptr<QuicPacket> packet( - framer_.ConstructFrameDataPacket(header_, frames)); - return framer_.EncryptPacket(*packet); + framer_.ConstructFrameDataPacket(header_, frames).packet); + return framer_.EncryptPacket(header_.packet_sequence_number, *packet); } QuicGuid guid_; @@ -225,9 +244,9 @@ TEST_F(QuicConnectionHelperTest, SetAckAlarm) { EXPECT_EQ(base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()), runner_->GetPostedTasks()[1].delay); - EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false)); runner_->RunNextTask(); - EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now()); + EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.ApproximateNow()); } TEST_F(QuicConnectionHelperTest, ClearAckAlarm) { @@ -243,7 +262,7 @@ TEST_F(QuicConnectionHelperTest, ClearAckAlarm) { // When the AckAlarm actually fires, no ack will be sent. runner_->RunNextTask(); - EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now()); + EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.ApproximateNow()); } TEST_F(QuicConnectionHelperTest, ResetAckAlarm) { @@ -264,14 +283,14 @@ TEST_F(QuicConnectionHelperTest, ResetAckAlarm) { // The task will execute at delta1, but will not send and ack, // but it will reschedule itself for delta2 runner_->RunNextTask(); - EXPECT_EQ(QuicTime::Zero().Add(delta1), clock_.Now()); + EXPECT_EQ(QuicTime::Zero().Add(delta1), clock_.ApproximateNow()); // Verify that the ack alarm task has been re-posted. ASSERT_EQ(2u, runner_->GetPostedTasks().size()); - EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false)); runner_->RunNextTask(); - EXPECT_EQ(QuicTime::Zero().Add(delta2), clock_.Now()); + EXPECT_EQ(QuicTime::Zero().Add(delta2), clock_.ApproximateNow()); } TEST_F(QuicConnectionHelperTest, TestRetransmission) { @@ -281,17 +300,18 @@ TEST_F(QuicConnectionHelperTest, TestRetransmission) { QuicTime::Delta kDefaultRetransmissionTime = QuicTime::Delta::FromMilliseconds(500); - QuicTime start = clock_.Now(); + QuicTime start = clock_.ApproximateNow(); - EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false)); // Send a packet. connection_->SendStreamData(1, kData, 0, false); - EXPECT_CALL(*send_algorithm_, SentPacket(2, _, true)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, true)); // Since no ack was received, the retransmission alarm will fire and // retransmit it. runner_->RunNextTask(); - EXPECT_EQ(kDefaultRetransmissionTime, clock_.Now().Subtract(start)); + EXPECT_EQ(kDefaultRetransmissionTime, + clock_.ApproximateNow().Subtract(start)); EXPECT_TRUE(AtEof()); } @@ -304,12 +324,13 @@ TEST_F(QuicConnectionHelperTest, InitialTimeout) { EXPECT_EQ(base::TimeDelta::FromMicroseconds(kDefaultTimeoutUs), runner_->GetPostedTasks().front().delay); - EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false)); // After we run the next task, we should close the connection. EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false)); runner_->RunNextTask(); - EXPECT_EQ(QuicTime::FromMicroseconds(kDefaultTimeoutUs), clock_.Now()); + EXPECT_EQ(QuicTime::FromMicroseconds(kDefaultTimeoutUs), + clock_.ApproximateNow()); EXPECT_FALSE(connection_->connected()); EXPECT_TRUE(AtEof()); } @@ -343,12 +364,12 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) { Initialize(); EXPECT_TRUE(connection_->connected()); - EXPECT_EQ(0u, clock_.Now().ToMicroseconds()); + EXPECT_EQ(0u, clock_.ApproximateNow().ToMicroseconds()); // When we send a packet, the timeout will change to 5000 + kDefaultTimeout. clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(5000)); - EXPECT_EQ(5000u, clock_.Now().ToMicroseconds()); - EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false)); + EXPECT_EQ(5000u, clock_.ApproximateNow().ToMicroseconds()); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false)); // Send an ack so we don't set the retransmission alarm. connection_->SendAck(); @@ -357,14 +378,15 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) { // network event at t=5000. The alarm will reregister. runner_->RunNextTask(); - EXPECT_EQ(QuicTime::FromMicroseconds(kDefaultTimeoutUs), clock_.Now()); + EXPECT_EQ(QuicTime::FromMicroseconds(kDefaultTimeoutUs), + clock_.ApproximateNow()); EXPECT_TRUE(connection_->connected()); // This time, we should time out. EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(2, _, false)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, false)); runner_->RunNextTask(); - EXPECT_EQ(kDefaultTimeoutUs + 5000, clock_.Now().ToMicroseconds()); + EXPECT_EQ(kDefaultTimeoutUs + 5000, clock_.ApproximateNow().ToMicroseconds()); EXPECT_FALSE(connection_->connected()); EXPECT_TRUE(AtEof()); } @@ -374,17 +396,18 @@ TEST_F(QuicConnectionHelperTest, SendSchedulerDelayThenSend) { Initialize(); // Test that if we send a packet with a delay, it ends up queued. - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::FromMicroseconds(1))); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, false)).WillOnce( + testing::Return(QuicTime::Delta::FromMicroseconds(1))); - connection_->SendStreamData(1, kData, 0, false); - EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false)); + QuicPacket* packet = ConstructRawDataPacket(1); + connection_->SendOrQueuePacket(1, packet, 0); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, false)); EXPECT_EQ(1u, connection_->NumQueuedPackets()); // Advance the clock to fire the alarm, and configure the scheduler // to permit the packet to be sent. - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::Zero())); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, false)).WillOnce( + testing::Return(QuicTime::Delta::Zero())); EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(testing::Return(true)); runner_->RunNextTask(); EXPECT_EQ(0u, connection_->NumQueuedPackets()); diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc index 42077ef..6545f2d 100644 --- a/net/quic/quic_connection_logger.cc +++ b/net/quic/quic_connection_logger.cc @@ -30,10 +30,13 @@ Value* NetLogQuicPacketHeaderCallback(const QuicPacketHeader* header, DictionaryValue* dict = new DictionaryValue(); dict->SetString("guid", base::Uint64ToString(header->public_header.guid)); - dict->SetInteger("public_flags", header->public_header.flags); + dict->SetInteger("reset_flag", header->public_header.reset_flag); + dict->SetInteger("version_flag", header->public_header.version_flag); dict->SetString("packet_sequence_number", base::Uint64ToString(header->packet_sequence_number)); - dict->SetInteger("private_flags", header->private_flags); + dict->SetInteger("entropy_flag", header->entropy_flag); + dict->SetInteger("fec_flag", header->fec_flag); + dict->SetInteger("fec_entropy_flag", header->fec_entropy_flag); dict->SetInteger("fec_group", header->fec_group); return dict; } @@ -62,8 +65,9 @@ Value* NetLogQuicAckFrameCallback(const QuicAckFrame* frame, base::Uint64ToString(frame->received_info.largest_observed)); ListValue* missing = new ListValue(); received_info->Set("missing_packets", missing); - const SequenceSet& missing_packets = frame->received_info.missing_packets; - for (SequenceSet::const_iterator it = missing_packets.begin(); + const SequenceNumberSet& missing_packets = + frame->received_info.missing_packets; + for (SequenceNumberSet::const_iterator it = missing_packets.begin(); it != missing_packets.end(); ++it) { missing->Append(new base::StringValue(base::Uint64ToString(*it))); } @@ -110,7 +114,6 @@ Value* NetLogQuicRstStreamFrameCallback(const QuicRstStreamFrame* frame, NetLog::LogLevel /* log_level */) { DictionaryValue* dict = new DictionaryValue(); dict->SetInteger("stream_id", frame->stream_id); - dict->SetInteger("offset", frame->offset); dict->SetInteger("error_code", frame->error_code); dict->SetString("details", frame->error_details); return dict; diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index 51a9784..a6e4e60 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -4,13 +4,16 @@ #include "net/quic/quic_connection.h" +#include "base/bind.h" #include "net/base/net_errors.h" #include "net/quic/congestion_control/receive_algorithm_interface.h" #include "net/quic/congestion_control/send_algorithm_interface.h" #include "net/quic/crypto/null_encrypter.h" #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" +#include "net/quic/crypto/quic_random.h" #include "net/quic/test_tools/mock_clock.h" +#include "net/quic/test_tools/mock_random.h" #include "net/quic/test_tools/quic_connection_peer.h" #include "net/quic/test_tools/quic_test_utils.h" #include "net/quic/quic_utils.h" @@ -19,11 +22,14 @@ using base::StringPiece; using std::map; +using std::vector; using testing::_; using testing::AnyNumber; using testing::Between; using testing::ContainerEq; +using testing::DoAll; using testing::InSequence; +using testing::InvokeWithoutArgs; using testing::Return; using testing::StrictMock; using testing::SaveArg; @@ -35,6 +41,13 @@ namespace { const char data1[] = "foo"; const char data2[] = "bar"; +const bool kFin = true; +const bool kForce = true; +const bool kIsRetransmission = true; +const bool kEntropyFlag = true; +const bool kFecEntropyFlag = true; +const QuicPacketEntropyHash kTestEntropyHash = 76; + class TestReceiveAlgorithm : public ReceiveAlgorithmInterface { public: explicit TestReceiveAlgorithm(QuicCongestionFeedbackFrame* feedback) @@ -65,7 +78,7 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { : clock_(clock), random_generator_(random_generator), retransmission_alarm_(QuicTime::Zero()), - send_alarm_(QuicTime::Zero()), + send_alarm_(QuicTime::FromMilliseconds(-1)), timeout_alarm_(QuicTime::Zero()), blocked_(false) { } @@ -85,16 +98,20 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { int* error) OVERRIDE { QuicFramer framer(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); - FramerVisitorCapturingAcks visitor; + FramerVisitorCapturingFrames visitor; framer.set_visitor(&visitor); EXPECT_TRUE(framer.ProcessPacket(packet)); header_ = *visitor.header(); + frame_count_ = visitor.frame_count(); if (visitor.ack()) { ack_.reset(new QuicAckFrame(*visitor.ack())); } if (visitor.feedback()) { feedback_.reset(new QuicCongestionFeedbackFrame(*visitor.feedback())); } + if (visitor.stream_frames() != NULL && !visitor.stream_frames()->empty()) { + stream_frames_ = *visitor.stream_frames(); + } if (blocked_) { *error = ERR_IO_PENDING; return -1; @@ -104,23 +121,23 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { } virtual void SetRetransmissionAlarm(QuicTime::Delta delay) OVERRIDE { - retransmission_alarm_ = clock_->Now().Add(delay); + retransmission_alarm_ = clock_->ApproximateNow().Add(delay); } virtual void SetSendAlarm(QuicTime::Delta delay) OVERRIDE { - send_alarm_ = clock_->Now().Add(delay); + send_alarm_ = clock_->ApproximateNow().Add(delay); } virtual void SetTimeoutAlarm(QuicTime::Delta delay) OVERRIDE { - timeout_alarm_ = clock_->Now().Add(delay); + timeout_alarm_ = clock_->ApproximateNow().Add(delay); } virtual bool IsSendAlarmSet() OVERRIDE { - return send_alarm_ > clock_->Now(); + return send_alarm_ >= clock_->ApproximateNow(); } virtual void UnregisterSendAlarmIfRegistered() OVERRIDE { - send_alarm_ = QuicTime::Zero(); + send_alarm_ = QuicTime::FromMilliseconds(-1); } virtual void SetAckAlarm(QuicTime::Delta delay) OVERRIDE {} @@ -134,10 +151,14 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { QuicPacketHeader* header() { return &header_; } + size_t frame_count() { return frame_count_; } + QuicAckFrame* ack() { return ack_.get(); } QuicCongestionFeedbackFrame* feedback() { return feedback_.get(); } + const vector<QuicStreamFrame>* stream_frames() { return &stream_frames_; } + void set_blocked(bool blocked) { blocked_ = blocked; } private: @@ -147,8 +168,10 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { QuicTime send_alarm_; QuicTime timeout_alarm_; QuicPacketHeader header_; + size_t frame_count_; scoped_ptr<QuicAckFrame> ack_; scoped_ptr<QuicCongestionFeedbackFrame> feedback_; + vector<QuicStreamFrame> stream_frames_; bool blocked_; DISALLOW_COPY_AND_ASSIGN(TestConnectionHelper); @@ -174,7 +197,16 @@ class TestConnection : public QuicConnection { QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm); } + QuicConsumedData SendStreamData1() { + return SendStreamData(1u, "food", 0, !kFin); + } + + QuicConsumedData SendStreamData2() { + return SendStreamData(2u, "food2", 0, !kFin); + } + using QuicConnection::SendOrQueuePacket; + using QuicConnection::DontWaitForPacketsBefore; private: DISALLOW_COPY_AND_ASSIGN(TestConnection); @@ -185,7 +217,7 @@ class QuicConnectionTest : public ::testing::Test { QuicConnectionTest() : guid_(42), framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)), - creator_(guid_, &framer_), + creator_(guid_, &framer_, QuicRandom::GetInstance()), send_algorithm_(new StrictMock<MockSendAlgorithm>), helper_(new TestConnectionHelper(&clock_, &random_generator_)), connection_(guid_, IPEndPoint(), helper_.get()), @@ -196,11 +228,11 @@ class QuicConnectionTest : public ::testing::Test { connection_.SetSendAlgorithm(send_algorithm_); // Simplify tests by not sending feedback unless specifically configured. SetFeedback(NULL); - EXPECT_CALL(*send_algorithm_, TimeUntilSend(_)).WillRepeatedly(Return( + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _)).WillRepeatedly(Return( QuicTime::Delta::Zero())); EXPECT_CALL(*receive_algorithm_, RecordIncomingPacket(_, _, _, _)).Times(AnyNumber()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(AnyNumber()); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber()); } QuicAckFrame* outgoing_ack() { @@ -222,7 +254,18 @@ class QuicConnectionTest : public ::testing::Test { void ProcessPacket(QuicPacketSequenceNumber number) { EXPECT_CALL(visitor_, OnPacket(_, _, _, _)) .WillOnce(Return(accept_packet_)); - ProcessDataPacket(number, 0); + ProcessDataPacket(number, 0, !kEntropyFlag); + } + + QuicPacketEntropyHash ProcessFramePacket(QuicFrame frame) { + QuicFrames frames; + frames.push_back(QuicFrame(frame)); + SerializedPacket serialized_packet = creator_.SerializeAllFrames(frames); + scoped_ptr<QuicPacket> packet(serialized_packet.packet); + scoped_ptr<QuicEncryptedPacket> encrypted( + framer_.EncryptPacket(serialized_packet.sequence_number, *packet)); + connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); + return serialized_packet.entropy_hash; } void ProcessFecProtectedPacket(QuicPacketSequenceNumber number, @@ -234,39 +277,59 @@ class QuicConnectionTest : public ::testing::Test { EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillOnce( Return(accept_packet_)); } - ProcessDataPacket(number, 1); + ProcessDataPacket(number, 1, !kEntropyFlag); } void ProcessDataPacket(QuicPacketSequenceNumber number, - QuicFecGroupNumber fec_group) { - scoped_ptr<QuicPacket> packet(ConstructDataPacket(number, fec_group)); - scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*packet)); + QuicFecGroupNumber fec_group, + bool entropy_flag) { + scoped_ptr<QuicPacket> packet(ConstructDataPacket(number, fec_group, + entropy_flag)); + scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(number, + *packet)); connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); } void ProcessClosePacket(QuicPacketSequenceNumber number, QuicFecGroupNumber fec_group) { scoped_ptr<QuicPacket> packet(ConstructClosePacket(number, fec_group)); - scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*packet)); + scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(number, + *packet)); connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); } + void ProcessFecProtectedPacket(QuicPacketSequenceNumber number, + bool expect_revival, bool entropy_flag) { + if (expect_revival) { + EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillOnce(DoAll( + SaveArg<2>(&revived_header_), Return(accept_packet_))); + } + EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillOnce(Return(accept_packet_)) + .RetiresOnSaturation(); + ProcessDataPacket(number, 1, entropy_flag); + } + // Sends an FEC packet that covers the packets that would have been sent. void ProcessFecPacket(QuicPacketSequenceNumber number, QuicPacketSequenceNumber min_protected_packet, - bool expect_revival) { + bool expect_revival, + bool fec_entropy_flag) { if (expect_revival) { - EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillOnce( - Return(accept_packet_)); + EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillOnce(DoAll( + SaveArg<2>(&revived_header_), Return(accept_packet_))); } // Construct the decrypted data packet so we can compute the correct // redundancy. - scoped_ptr<QuicPacket> data_packet(ConstructDataPacket(number, 1)); + scoped_ptr<QuicPacket> data_packet(ConstructDataPacket(number, 1, + !kEntropyFlag)); header_.public_header.guid = guid_; - header_.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header_.private_flags = PACKET_PRIVATE_FLAGS_FEC; + header_.public_header.reset_flag = false; + header_.public_header.version_flag = false; + header_.entropy_flag = kEntropyFlag; + header_.fec_flag = true; + header_.fec_entropy_flag = fec_entropy_flag; header_.packet_sequence_number = number; header_.fec_group = min_protected_packet; QuicFecData fec_data; @@ -282,9 +345,9 @@ class QuicConnectionTest : public ::testing::Test { } fec_data.redundancy = data_packet->FecProtectedData(); scoped_ptr<QuicPacket> fec_packet( - framer_.ConstructFecPacket(header_, fec_data)); + framer_.ConstructFecPacket(header_, fec_data).packet); scoped_ptr<QuicEncryptedPacket> encrypted( - framer_.EncryptPacket(*fec_packet)); + framer_.EncryptPacket(number, *fec_packet)); connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); } @@ -292,46 +355,50 @@ class QuicConnectionTest : public ::testing::Test { void SendStreamDataToPeer(QuicStreamId id, StringPiece data, QuicStreamOffset offset, bool fin, QuicPacketSequenceNumber* last_packet) { - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); connection_.SendStreamData(id, data, offset, fin); if (last_packet != NULL) { *last_packet = QuicConnectionPeer::GetPacketCreator(&connection_)->sequence_number(); } - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(AnyNumber()); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber()); } void SendAckPacketToPeer() { - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1); connection_.SendAck(); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(AnyNumber()); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber()); } - void ProcessAckPacket(QuicAckFrame* frame) { - QuicFrames frames; - frames.push_back(QuicFrame(frame)); - PacketPair pair = creator_.SerializeAllFrames(frames); - scoped_ptr<QuicPacket> packet(pair.second); - scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*packet)); - connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); + QuicPacketEntropyHash ProcessAckPacket(QuicAckFrame* frame) { + return ProcessFramePacket(QuicFrame(frame)); + } + + QuicPacketEntropyHash ProcessGoAwayPacket(QuicGoAwayFrame* frame) { + return ProcessFramePacket(QuicFrame(frame)); } bool IsMissing(QuicPacketSequenceNumber number) { - return outgoing_ack()->received_info.IsAwaitingPacket(number); + return IsAwaitingPacket(outgoing_ack()->received_info, number); } QuicPacket* ConstructDataPacket(QuicPacketSequenceNumber number, - QuicFecGroupNumber fec_group) { + QuicFecGroupNumber fec_group, + bool entropy_flag) { header_.public_header.guid = guid_; - header_.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header_.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header_.public_header.reset_flag = false; + header_.public_header.version_flag = false; + header_.entropy_flag = entropy_flag; + header_.fec_flag = false; + header_.fec_entropy_flag = false; header_.packet_sequence_number = number; header_.fec_group = fec_group; QuicFrames frames; QuicFrame frame(&frame1_); frames.push_back(frame); - QuicPacket* packet = framer_.ConstructFrameDataPacket(header_, frames); + QuicPacket* packet = + framer_.ConstructFrameDataPacket(header_, frames).packet; EXPECT_TRUE(packet != NULL); return packet; } @@ -340,17 +407,22 @@ class QuicConnectionTest : public ::testing::Test { QuicFecGroupNumber fec_group) { header_.public_header.guid = guid_; header_.packet_sequence_number = number; - header_.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header_.public_header.reset_flag = false; + header_.public_header.version_flag = false; + header_.entropy_flag = false; + header_.fec_flag = false; + header_.fec_entropy_flag = false; header_.fec_group = fec_group; QuicConnectionCloseFrame qccf; - qccf.error_code = QUIC_CLIENT_GOING_AWAY; + qccf.error_code = QUIC_PEER_GOING_AWAY; qccf.ack_frame = QuicAckFrame(0, 1); QuicFrames frames; QuicFrame frame(&qccf); frames.push_back(frame); - QuicPacket* packet = framer_.ConstructFrameDataPacket(header_, frames); + QuicPacket* packet = + framer_.ConstructFrameDataPacket(header_, frames).packet; EXPECT_TRUE(packet != NULL); return packet; } @@ -373,6 +445,7 @@ class QuicConnectionTest : public ::testing::Test { testing::StrictMock<MockConnectionVisitor> visitor_; QuicPacketHeader header_; + QuicPacketHeader revived_header_; QuicStreamFrame frame1_; QuicStreamFrame frame2_; bool accept_packet_; @@ -432,7 +505,7 @@ TEST_F(QuicConnectionTest, DuplicatePacket) { // Send packet 3 again, but do not set the expectation that // the visitor OnPacket() will be called. - ProcessDataPacket(3, 0); + ProcessDataPacket(3, 0, !kEntropyFlag); EXPECT_EQ(3u, outgoing_ack()->received_info.largest_observed); EXPECT_TRUE(IsMissing(2)); EXPECT_TRUE(IsMissing(1)); @@ -469,7 +542,7 @@ TEST_F(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) { TEST_F(QuicConnectionTest, RejectPacketTooFarOut) { // Call ProcessDataPacket rather than ProcessPacket, as we should not get a // packet call to the visitor. - ProcessDataPacket(6000, 0); + ProcessDataPacket(6000, 0, !kEntropyFlag); SendAckPacketToPeer(); // Packet 2 EXPECT_EQ(0u, outgoing_ack()->received_info.largest_observed); @@ -478,26 +551,35 @@ TEST_F(QuicConnectionTest, RejectPacketTooFarOut) { TEST_F(QuicConnectionTest, TruncatedAck) { EXPECT_CALL(visitor_, OnAck(_)).Times(testing::AnyNumber()); EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(2); + EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); for (int i = 0; i < 200; ++i) { - SendStreamDataToPeer(1, "foo", i * 3, false, NULL); + SendStreamDataToPeer(1, "foo", i * 3, !kFin, NULL); } QuicAckFrame frame(0, 1); - frame.received_info.RecordReceived(193); + frame.received_info.largest_observed = 192; + InsertMissingPacketsBetween(&frame.received_info, 1, 192); + frame.received_info.entropy_hash = + QuicConnectionPeer::GetSentEntropyHash(&connection_, 192) ^ + QuicConnectionPeer::GetSentEntropyHash(&connection_, 191); + ProcessAckPacket(&frame); EXPECT_TRUE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_)); - frame.received_info.missing_packets.erase(192); + frame.received_info.missing_packets.erase(191); + frame.received_info.entropy_hash = + QuicConnectionPeer::GetSentEntropyHash(&connection_, 192) ^ + QuicConnectionPeer::GetSentEntropyHash(&connection_, 190); ProcessAckPacket(&frame); EXPECT_FALSE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_)); } TEST_F(QuicConnectionTest, LeastUnackedLower) { - SendStreamDataToPeer(1, "foo", 0, false, NULL); - SendStreamDataToPeer(1, "bar", 3, false, NULL); - SendStreamDataToPeer(1, "eep", 6, false, NULL); + SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); + SendStreamDataToPeer(1, "bar", 3, !kFin, NULL); + SendStreamDataToPeer(1, "eep", 6, !kFin, NULL); // Start out saying the least unacked is 2 creator_.set_sequence_number(5); @@ -514,19 +596,21 @@ TEST_F(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(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); creator_.set_sequence_number(7); ProcessAckPacket(&frame2); } TEST_F(QuicConnectionTest, LargestObservedLower) { - SendStreamDataToPeer(1, "foo", 0, false, NULL); - SendStreamDataToPeer(1, "bar", 3, false, NULL); - SendStreamDataToPeer(1, "eep", 6, false, NULL); + SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); + SendStreamDataToPeer(1, "bar", 3, !kFin, NULL); + SendStreamDataToPeer(1, "eep", 6, !kFin, NULL); EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(2); // Start out saying the largest observed is 2. QuicAckFrame frame(2, 0); + frame.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash( + &connection_, 2); EXPECT_CALL(visitor_, OnAck(_)); ProcessAckPacket(&frame); @@ -538,7 +622,7 @@ TEST_F(QuicConnectionTest, LargestObservedLower) { TEST_F(QuicConnectionTest, LeastUnackedGreaterThanPacketSequenceNumber) { EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); // Create an ack with least_unacked is 2 in packet number 1. creator_.set_sequence_number(0); QuicAckFrame frame(0, 2); @@ -546,13 +630,13 @@ TEST_F(QuicConnectionTest, LeastUnackedGreaterThanPacketSequenceNumber) { } TEST_F(QuicConnectionTest, - DISABLED_NackSequenceNumberGreaterThanLargestReceived) { - SendStreamDataToPeer(1, "foo", 0, false, NULL); - SendStreamDataToPeer(1, "bar", 3, false, NULL); - SendStreamDataToPeer(1, "eep", 6, false, NULL); + NackSequenceNumberGreaterThanLargestReceived) { + SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); + SendStreamDataToPeer(1, "bar", 3, !kFin, NULL); + SendStreamDataToPeer(1, "eep", 6, !kFin, NULL); EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); QuicAckFrame frame(0, 1); frame.received_info.missing_packets.insert(3); ProcessAckPacket(&frame); @@ -561,7 +645,7 @@ TEST_F(QuicConnectionTest, TEST_F(QuicConnectionTest, AckUnsentData) { // Ack a packet which has not been sent. EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); QuicAckFrame frame(1, 0); ProcessAckPacket(&frame); } @@ -574,10 +658,17 @@ TEST_F(QuicConnectionTest, AckAll) { ProcessAckPacket(&frame1); } +TEST_F(QuicConnectionTest, DontWaitForPacketsBefore) { + ProcessPacket(2); + ProcessPacket(7); + EXPECT_TRUE(connection_.DontWaitForPacketsBefore(4)); + EXPECT_EQ(3u, outgoing_ack()->received_info.missing_packets.size()); +} + TEST_F(QuicConnectionTest, BasicSending) { EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(6); QuicPacketSequenceNumber last_packet; - SendStreamDataToPeer(1, "foo", 0, false, &last_packet); // Packet 1 + SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1 EXPECT_EQ(1u, last_packet); SendAckPacketToPeer(); // Packet 2 @@ -586,17 +677,19 @@ TEST_F(QuicConnectionTest, BasicSending) { SendAckPacketToPeer(); // Packet 3 EXPECT_EQ(1u, last_ack()->sent_info.least_unacked); - SendStreamDataToPeer(1u, "bar", 3, false, &last_packet); // Packet 4 + SendStreamDataToPeer(1u, "bar", 3, !kFin, &last_packet); // Packet 4 EXPECT_EQ(4u, last_packet); SendAckPacketToPeer(); // Packet 5 EXPECT_EQ(1u, last_ack()->sent_info.least_unacked); - QuicConnectionVisitorInterface::AckedPackets expected_acks; + SequenceNumberSet expected_acks; expected_acks.insert(1); // Client acks up to packet 3 EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks))); QuicAckFrame frame(3, 0); + frame.received_info.entropy_hash = + QuicConnectionPeer::GetSentEntropyHash(&connection_, 3); ProcessAckPacket(&frame); SendAckPacketToPeer(); // Packet 6 @@ -610,6 +703,8 @@ TEST_F(QuicConnectionTest, BasicSending) { // Client acks up to packet 4, the last packet EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks))); QuicAckFrame frame2(6, 0); + frame2.received_info.entropy_hash = + QuicConnectionPeer::GetSentEntropyHash(&connection_, 6); ProcessAckPacket(&frame2); // Even parity triggers ack packet 7 // The least packet awaiting ack should now be 7 @@ -620,7 +715,7 @@ TEST_F(QuicConnectionTest, BasicSending) { EXPECT_EQ(8u, last_ack()->sent_info.least_unacked); // But if we send more data it should. - SendStreamDataToPeer(1, "eep", 6, false, &last_packet); // Packet 9 + SendStreamDataToPeer(1, "eep", 6, !kFin, &last_packet); // Packet 9 EXPECT_EQ(9u, last_packet); SendAckPacketToPeer(); // Packet10 EXPECT_EQ(9u, last_ack()->sent_info.least_unacked); @@ -635,8 +730,8 @@ TEST_F(QuicConnectionTest, FECSending) { connection_.options()->max_packets_per_fec_group = 2; // Send 4 data packets and 2 FEC packets. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(6); - connection_.SendStreamData(1, "food", 0, false); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(6); + connection_.SendStreamData(1, "food", 0, !kFin); // Expect the FEC group to be closed after SendStreamData. EXPECT_FALSE(creator_.ShouldSendFec(true)); } @@ -651,26 +746,110 @@ TEST_F(QuicConnectionTest, FECQueueing) { EXPECT_EQ(0u, connection_.NumQueuedPackets()); helper_->set_blocked(true); - connection_.SendStreamData(1, "food", 0, false); + connection_.SendStreamData(1, "food", 0, !kFin); EXPECT_FALSE(creator_.ShouldSendFec(true)); // Expect the first data packet and the fec packet to be queued. EXPECT_EQ(2u, connection_.NumQueuedPackets()); } +TEST_F(QuicConnectionTest, FramePacking) { + // Block the connection. + helper_->SetSendAlarm(QuicTime::Delta::FromSeconds(1)); + + // Send an ack and two stream frames in 1 packet by queueing them. + connection_.SendAck(); + EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(DoAll( + IgnoreResult(InvokeWithoutArgs(&connection_, + &TestConnection::SendStreamData1)), + IgnoreResult(InvokeWithoutArgs(&connection_, + &TestConnection::SendStreamData2)), + Return(true))); + + // Unblock the connection. + helper_->UnregisterSendAlarmIfRegistered(); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, !kIsRetransmission)) + .Times(1); + connection_.OnCanWrite(); + EXPECT_EQ(0u, connection_.NumQueuedPackets()); + EXPECT_FALSE(connection_.HasQueuedData()); + + // Parse the last packet and ensure it's an ack and two stream frames from + // two different streams. + EXPECT_EQ(3u, helper_->frame_count()); + EXPECT_TRUE(helper_->ack()); + EXPECT_EQ(2u, helper_->stream_frames()->size()); + EXPECT_EQ(1u, (*helper_->stream_frames())[0].stream_id); + EXPECT_EQ(2u, (*helper_->stream_frames())[1].stream_id); +} + +TEST_F(QuicConnectionTest, FramePackingFEC) { + // Enable fec. + connection_.options()->max_packets_per_fec_group = 6; + // Block the connection. + helper_->SetSendAlarm(QuicTime::Delta::FromSeconds(1)); + + // Send an ack and two stream frames in 1 packet by queueing them. + connection_.SendAck(); + EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(DoAll( + IgnoreResult(InvokeWithoutArgs(&connection_, + &TestConnection::SendStreamData1)), + IgnoreResult(InvokeWithoutArgs(&connection_, + &TestConnection::SendStreamData2)), + Return(true))); + + // Unblock the connection. + helper_->UnregisterSendAlarmIfRegistered(); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, !kIsRetransmission)) + .Times(2); + connection_.OnCanWrite(); + EXPECT_EQ(0u, connection_.NumQueuedPackets()); + EXPECT_FALSE(connection_.HasQueuedData()); + + // Parse the last packet and ensure it's in an fec group. + EXPECT_EQ(1u, helper_->header()->fec_group); + EXPECT_EQ(0u, helper_->frame_count()); +} + +TEST_F(QuicConnectionTest, OnCanWrite) { + // Visitor's OnCanWill send data, but will return false. + EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(DoAll( + IgnoreResult(InvokeWithoutArgs(&connection_, + &TestConnection::SendStreamData1)), + IgnoreResult(InvokeWithoutArgs(&connection_, + &TestConnection::SendStreamData2)), + Return(false))); + + EXPECT_CALL(*send_algorithm_, + TimeUntilSend(_, !kIsRetransmission)).WillRepeatedly( + testing::Return(QuicTime::Delta::Zero())); + + // Unblock the connection. + connection_.OnCanWrite(); + // Parse the last packet and ensure it's the two stream frames from + // two different streams. + EXPECT_EQ(2u, helper_->frame_count()); + EXPECT_EQ(2u, helper_->stream_frames()->size()); + EXPECT_EQ(1u, (*helper_->stream_frames())[0].stream_id); + EXPECT_EQ(2u, (*helper_->stream_frames())[1].stream_id); +} + TEST_F(QuicConnectionTest, RetransmitOnNack) { EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(2); + EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); QuicPacketSequenceNumber last_packet; - SendStreamDataToPeer(1, "foo", 0, false, &last_packet); // Packet 1 - SendStreamDataToPeer(1, "foos", 3, false, &last_packet); // Packet 2 - SendStreamDataToPeer(1, "fooos", 7, false, &last_packet); // Packet 3 + SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1 + SendStreamDataToPeer(1, "foos", 3, !kFin, &last_packet); // Packet 2 + SendStreamDataToPeer(1, "fooos", 7, !kFin, &last_packet); // Packet 3 - QuicConnectionVisitorInterface::AckedPackets expected_acks; + SequenceNumberSet expected_acks; expected_acks.insert(1); EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks))); // Client acks one but not two or three. Right now we only retransmit on // explicit nack, so it should not trigger a retransimission. QuicAckFrame ack_one(1, 0); + ack_one.received_info.entropy_hash = + QuicConnectionPeer::GetSentEntropyHash(&connection_, 1); ProcessAckPacket(&ack_one); ProcessAckPacket(&ack_one); ProcessAckPacket(&ack_one); @@ -683,37 +862,47 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) { // change. QuicAckFrame nack_two(3, 0); nack_two.received_info.missing_packets.insert(2); + nack_two.received_info.entropy_hash = + QuicConnectionPeer::GetSentEntropyHash(&connection_, 3) ^ + QuicConnectionPeer::GetSentEntropyHash(&connection_, 2) ^ + QuicConnectionPeer::GetSentEntropyHash(&connection_, 1); ProcessAckPacket(&nack_two); ProcessAckPacket(&nack_two); // The third nack should trigger a retransimission. - EXPECT_CALL(*send_algorithm_, SentPacket(_, 37, true)).Times(1); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, 37, kIsRetransmission)) + .Times(1); ProcessAckPacket(&nack_two); } TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) { + EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); QuicPacketSequenceNumber largest_observed; QuicByteCount packet_size; - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, false)).WillOnce(DoAll( - SaveArg<0>(&largest_observed), SaveArg<1>(&packet_size))); - connection_.SendStreamData(1, "foo", 0, false); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, !kIsRetransmission)) + .WillOnce(DoAll(SaveArg<1>(&largest_observed), SaveArg<2>(&packet_size))); + connection_.SendStreamData(1, "foo", 0, !kFin); QuicAckFrame frame(1, largest_observed); frame.received_info.missing_packets.insert(largest_observed); + frame.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash( + &connection_, largest_observed - 1); ProcessAckPacket(&frame); // Second udp packet will force an ack frame. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, false)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, !kIsRetransmission)); ProcessAckPacket(&frame); // Third nack should retransmit the largest observed packet. - EXPECT_CALL(*send_algorithm_, SentPacket(_, packet_size, true)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, packet_size, + kIsRetransmission)); ProcessAckPacket(&frame); } TEST_F(QuicConnectionTest, LimitPacketsPerNack) { EXPECT_CALL(*send_algorithm_, OnIncomingAck(12, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); int offset = 0; // Send packets 1 to 12 for (int i = 0; i < 12; ++i) { - SendStreamDataToPeer(1, "foo", offset, false, NULL); + SendStreamDataToPeer(1, "foo", offset, !kFin, NULL); offset += 3; } @@ -723,47 +912,55 @@ TEST_F(QuicConnectionTest, LimitPacketsPerNack) { nack.received_info.missing_packets.insert(i); } - QuicConnectionVisitorInterface::AckedPackets expected_acks; + nack.received_info.entropy_hash = + QuicConnectionPeer::GetSentEntropyHash(&connection_, 12) ^ + QuicConnectionPeer::GetSentEntropyHash(&connection_, 11); + SequenceNumberSet expected_acks; expected_acks.insert(12); EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks))); // Nack three times. ProcessAckPacket(&nack); // The second call will trigger an ack. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(1); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1); ProcessAckPacket(&nack); // The third call should trigger retransmitting 10 packets. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(10); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(10); ProcessAckPacket(&nack); // The fourth call should trigger retransmitting the 11th packet and an ack. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(2); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(2); ProcessAckPacket(&nack); } // Test sending multiple acks from the connection to the session. TEST_F(QuicConnectionTest, MultipleAcks) { EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(6); + EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); QuicPacketSequenceNumber last_packet; - SendStreamDataToPeer(1u, "foo", 0, false, &last_packet); // Packet 1 + SendStreamDataToPeer(1u, "foo", 0, !kFin, &last_packet); // Packet 1 EXPECT_EQ(1u, last_packet); - SendStreamDataToPeer(3u, "foo", 0, false, &last_packet); // Packet 2 + SendStreamDataToPeer(3u, "foo", 0, !kFin, &last_packet); // Packet 2 EXPECT_EQ(2u, last_packet); SendAckPacketToPeer(); // Packet 3 - SendStreamDataToPeer(5u, "foo", 0, false, &last_packet); // Packet 4 + SendStreamDataToPeer(5u, "foo", 0, !kFin, &last_packet); // Packet 4 EXPECT_EQ(4u, last_packet); - SendStreamDataToPeer(1u, "foo", 3, false, &last_packet); // Packet 5 + SendStreamDataToPeer(1u, "foo", 3, !kFin, &last_packet); // Packet 5 EXPECT_EQ(5u, last_packet); - SendStreamDataToPeer(3u, "foo", 3, false, &last_packet); // Packet 6 + SendStreamDataToPeer(3u, "foo", 3, !kFin, &last_packet); // Packet 6 EXPECT_EQ(6u, last_packet); // Client will ack packets 1, [!2], 3, 4, 5 QuicAckFrame frame1(5, 0); frame1.received_info.missing_packets.insert(2); + frame1.received_info.entropy_hash = + QuicConnectionPeer::GetSentEntropyHash(&connection_, 5) ^ + QuicConnectionPeer::GetSentEntropyHash(&connection_, 2) ^ + QuicConnectionPeer::GetSentEntropyHash(&connection_, 1); // The connection should pass up acks for 1, 4, 5. 2 is not acked, and 3 was // an ackframe so should not be passed up. - QuicConnectionVisitorInterface::AckedPackets expected_acks; + SequenceNumberSet expected_acks; expected_acks.insert(1); expected_acks.insert(4); expected_acks.insert(5); @@ -773,6 +970,8 @@ TEST_F(QuicConnectionTest, MultipleAcks) { // Now the client implicitly acks 2, and explicitly acks 6 QuicAckFrame frame2(6, 0); + frame2.received_info.entropy_hash = + QuicConnectionPeer::GetSentEntropyHash(&connection_, 6); expected_acks.clear(); // Both acks should be passed up. expected_acks.insert(2); @@ -784,110 +983,122 @@ TEST_F(QuicConnectionTest, MultipleAcks) { TEST_F(QuicConnectionTest, DontLatchUnackedPacket) { EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1); - SendStreamDataToPeer(1, "foo", 0, false, NULL); // Packet 1; + SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); // Packet 1; SendAckPacketToPeer(); // Packet 2 - // This sets least unacked to 2, the ack packet. - QuicConnectionVisitorInterface::AckedPackets expected_acks; + // This sets least unacked to 3 (unsent packet), since we don't need + // an ack for Packet 2 (ack packet). + SequenceNumberSet expected_acks; expected_acks.insert(1); // Client acks packet 1 EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks))); QuicAckFrame frame(1, 0); + frame.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash( + &connection_, 1); ProcessAckPacket(&frame); - // Verify that our internal state has least-unacked as 2. - QuicAckFrame* outgoing_ack = QuicConnectionPeer::GetOutgoingAck(&connection_); - EXPECT_EQ(2u, outgoing_ack->sent_info.least_unacked); + // Verify that our internal state has least-unacked as 3. + EXPECT_EQ(3u, outgoing_ack()->sent_info.least_unacked); // When we send an ack, we make sure our least-unacked makes sense. In this // case since we're not waiting on an ack for 2 and all packets are acked, we // set it to 3. SendAckPacketToPeer(); // Packet 3 - EXPECT_EQ(3u, outgoing_ack->sent_info.least_unacked); + // Since this was an ack packet, we set least_unacked to 4. + EXPECT_EQ(4u, outgoing_ack()->sent_info.least_unacked); + // Check that the outgoing ack had its sequence number as least_unacked. EXPECT_EQ(3u, last_ack()->sent_info.least_unacked); + + SendStreamDataToPeer(1, "bar", 3, false, NULL); // Packet 4 + EXPECT_EQ(4u, outgoing_ack()->sent_info.least_unacked); + SendAckPacketToPeer(); // Packet 5 + EXPECT_EQ(4u, last_ack()->sent_info.least_unacked); } TEST_F(QuicConnectionTest, ReviveMissingPacketAfterFecPacket) { // Don't send missing packet 1. - ProcessFecPacket(2, 1, true); + ProcessFecPacket(2, 1, true, !kFecEntropyFlag); + EXPECT_FALSE(revived_header_.entropy_flag); } TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketThenFecPacket) { - ProcessFecProtectedPacket(1, false); + ProcessFecProtectedPacket(1, false, kEntropyFlag); // Don't send missing packet 2. - ProcessFecPacket(3, 1, true); + ProcessFecPacket(3, 1, true, !kFecEntropyFlag); + EXPECT_TRUE(revived_header_.entropy_flag); } TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketsThenFecPacket) { - ProcessFecProtectedPacket(1, false); + ProcessFecProtectedPacket(1, false, !kEntropyFlag); // Don't send missing packet 2. - ProcessFecProtectedPacket(3, false); - ProcessFecPacket(4, 1, true); + ProcessFecProtectedPacket(3, false, !kEntropyFlag); + ProcessFecPacket(4, 1, true, kFecEntropyFlag); + EXPECT_TRUE(revived_header_.entropy_flag); } TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacket) { // Don't send missing packet 1. - ProcessFecPacket(3, 1, false); // out of order - ProcessFecProtectedPacket(2, true); + ProcessFecPacket(3, 1, false, !kFecEntropyFlag); + // out of order + ProcessFecProtectedPacket(2, true, !kEntropyFlag); + EXPECT_FALSE(revived_header_.entropy_flag); } TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPackets) { - ProcessFecProtectedPacket(1, false); + ProcessFecProtectedPacket(1, false, !kEntropyFlag); // Don't send missing packet 2. - ProcessFecPacket(6, 1, false); - ProcessFecProtectedPacket(3, false); - ProcessFecProtectedPacket(4, false); - ProcessFecProtectedPacket(5, true); + ProcessFecPacket(6, 1, false, kFecEntropyFlag); + ProcessFecProtectedPacket(3, false, kEntropyFlag); + ProcessFecProtectedPacket(4, false, kEntropyFlag); + ProcessFecProtectedPacket(5, true, !kEntropyFlag); + EXPECT_TRUE(revived_header_.entropy_flag); } TEST_F(QuicConnectionTest, TestRetransmit) { - // TODO(rch): make this work - // FLAGS_fake_packet_loss_percentage = 100; const QuicTime::Delta kDefaultRetransmissionTime = QuicTime::Delta::FromMilliseconds(500); - QuicTime default_retransmission_time = clock_.Now().Add( + QuicTime default_retransmission_time = clock_.ApproximateNow().Add( kDefaultRetransmissionTime); - - QuicAckFrame* outgoing_ack = QuicConnectionPeer::GetOutgoingAck(&connection_); - SendStreamDataToPeer(1, "foo", 0, false, NULL); - EXPECT_EQ(1u, outgoing_ack->sent_info.least_unacked); + SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); + EXPECT_EQ(1u, outgoing_ack()->sent_info.least_unacked); EXPECT_EQ(1u, last_header()->packet_sequence_number); EXPECT_EQ(default_retransmission_time, helper_->retransmission_alarm()); // Simulate the retransimission alarm firing clock_.AdvanceTime(kDefaultRetransmissionTime); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); connection_.RetransmitPacket(1); EXPECT_EQ(2u, last_header()->packet_sequence_number); - EXPECT_EQ(2u, outgoing_ack->sent_info.least_unacked); + EXPECT_EQ(2u, outgoing_ack()->sent_info.least_unacked); } TEST_F(QuicConnectionTest, TestRetransmitOrder) { QuicByteCount first_packet_size; - EXPECT_CALL(*send_algorithm_, SentPacket(_,_,_)).WillOnce( - SaveArg<1>(&first_packet_size)); - connection_.SendStreamData(1, "first_packet", 0, false); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).WillOnce( + SaveArg<2>(&first_packet_size)); + connection_.SendStreamData(1, "first_packet", 0, !kFin); QuicByteCount second_packet_size; - EXPECT_CALL(*send_algorithm_, SentPacket(_,_,_)).WillOnce( - SaveArg<1>(&second_packet_size)); - connection_.SendStreamData(1, "second_packet", 12, false); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).WillOnce( + SaveArg<2>(&second_packet_size)); + connection_.SendStreamData(1, "second_packet", 12, !kFin); EXPECT_NE(first_packet_size, second_packet_size); // Advance the clock by huge time to make sure packets will be retransmitted. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10)); { InSequence s; - EXPECT_CALL(*send_algorithm_, SentPacket(_, first_packet_size, _)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, second_packet_size, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, first_packet_size, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, second_packet_size, _)); } connection_.OnRetransmissionTimeout(); } TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) { + EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1); QuicPacketSequenceNumber original_sequence_number; - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, false)).WillOnce( - SaveArg<0>(&original_sequence_number)); - connection_.SendStreamData(1, "foo", 0, false); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, !kIsRetransmission)) + .WillOnce(SaveArg<1>(&original_sequence_number)); + connection_.SendStreamData(1, "foo", 0, !kFin); EXPECT_TRUE(QuicConnectionPeer::IsSavedForRetransmission( &connection_, original_sequence_number)); EXPECT_EQ(0u, QuicConnectionPeer::GetRetransmissionCount( @@ -895,8 +1106,8 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) { // Force retransmission due to RTO. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10)); QuicPacketSequenceNumber rto_sequence_number; - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, true)).WillOnce( - SaveArg<0>(&rto_sequence_number)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, kIsRetransmission)) + .WillOnce(SaveArg<1>(&rto_sequence_number)); connection_.OnRetransmissionTimeout(); EXPECT_FALSE(QuicConnectionPeer::IsSavedForRetransmission( &connection_, original_sequence_number)); @@ -908,13 +1119,16 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) { QuicPacketSequenceNumber nack_sequence_number; // Ack packets might generate some other packets, which are not // retransmissions. (More ack packets). - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, false)).Times(AnyNumber()); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, true)).WillOnce( - SaveArg<0>(&nack_sequence_number)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, !kIsRetransmission)) + .Times(AnyNumber()); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, kIsRetransmission)) + .WillOnce(SaveArg<1>(&nack_sequence_number)); QuicAckFrame ack(rto_sequence_number, 0); // Ack the retransmitted packet. EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1); ack.received_info.missing_packets.insert(rto_sequence_number); + ack.received_info.entropy_hash = QuicConnectionPeer::GetSentEntropyHash( + &connection_, rto_sequence_number - 1); for (int i = 0; i < 3; i++) { ProcessAckPacket(&ack); } @@ -928,7 +1142,7 @@ TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) { TEST_F(QuicConnectionTest, SetRTOAfterWritingToSocket) { helper_->set_blocked(true); - connection_.SendStreamData(1, "foo", 0, false); + connection_.SendStreamData(1, "foo", 0, !kFin); // Make sure that RTO is not started when the packet is queued. EXPECT_EQ(0u, QuicConnectionPeer::GetNumRetransmissionTimeouts(&connection_)); @@ -942,7 +1156,7 @@ TEST_F(QuicConnectionTest, SetRTOAfterWritingToSocket) { TEST_F(QuicConnectionTest, TestQueued) { EXPECT_EQ(0u, connection_.NumQueuedPackets()); helper_->set_blocked(true); - connection_.SendStreamData(1, "foo", 0, false); + connection_.SendStreamData(1, "foo", 0, !kFin); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Attempt to send all packets, but since we're actually still @@ -960,7 +1174,7 @@ TEST_F(QuicConnectionTest, TestQueued) { TEST_F(QuicConnectionTest, CloseFecGroup) { // Don't send missing packet 1 // Don't send missing packet 2 - ProcessFecProtectedPacket(3, false); + ProcessFecProtectedPacket(3, false, !kEntropyFlag); // Don't send missing FEC packet 3 ASSERT_EQ(1u, connection_.NumFecGroups()); @@ -998,15 +1212,15 @@ TEST_F(QuicConnectionTest, DontUpdateQuicCongestionFeedbackFrameForRevived) { // Process an FEC packet, and revive the missing data packet // but only contact the receive_algorithm once. EXPECT_CALL(*receive_algorithm_, RecordIncomingPacket(_, _, _, _)); - ProcessFecPacket(2, 1, true); + ProcessFecPacket(2, 1, true, !kEntropyFlag); } TEST_F(QuicConnectionTest, InitialTimeout) { EXPECT_TRUE(connection_.connected()); EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); - QuicTime default_timeout = clock_.Now().Add( + QuicTime default_timeout = clock_.ApproximateNow().Add( QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs)); EXPECT_EQ(default_timeout, helper_->timeout_alarm()); @@ -1019,7 +1233,7 @@ TEST_F(QuicConnectionTest, InitialTimeout) { TEST_F(QuicConnectionTest, TimeoutAfterSend) { EXPECT_TRUE(connection_.connected()); - QuicTime default_timeout = clock_.Now().Add( + QuicTime default_timeout = clock_.ApproximateNow().Add( QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs)); // When we send a packet, the timeout will change to 5000 + kDefaultTimeout. @@ -1033,7 +1247,7 @@ TEST_F(QuicConnectionTest, TimeoutAfterSend) { // network event at t=5000. The alarm will reregister. clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds( kDefaultTimeoutUs - 5000)); - EXPECT_EQ(default_timeout, clock_.Now()); + EXPECT_EQ(default_timeout, clock_.ApproximateNow()); EXPECT_FALSE(connection_.CheckForTimeout()); EXPECT_TRUE(connection_.connected()); EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)), @@ -1041,10 +1255,10 @@ TEST_F(QuicConnectionTest, TimeoutAfterSend) { // This time, we should time out. EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)), - clock_.Now()); + clock_.ApproximateNow()); EXPECT_TRUE(connection_.CheckForTimeout()); EXPECT_FALSE(connection_.connected()); } @@ -1052,118 +1266,121 @@ TEST_F(QuicConnectionTest, TimeoutAfterSend) { // TODO(ianswett): Add scheduler tests when should_retransmit is false. TEST_F(QuicConnectionTest, SendScheduler) { // Test that if we send a packet without delay, it is not queued. - QuicPacket* packet = ConstructDataPacket(1, 0); - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::Zero())); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)); - connection_.SendOrQueuePacket(1, packet, false); + QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce( + testing::Return(QuicTime::Delta::Zero())); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + connection_.SendOrQueuePacket(1, packet, kTestEntropyHash); EXPECT_EQ(0u, connection_.NumQueuedPackets()); } TEST_F(QuicConnectionTest, SendSchedulerDelay) { // Test that if we send a packet with a delay, it ends up queued. - QuicPacket* packet = ConstructDataPacket(1, 0); - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::FromMicroseconds(1))); - EXPECT_CALL(*send_algorithm_, SentPacket(1, _, _)).Times(0); - connection_.SendOrQueuePacket(1, packet, false); + QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce( + testing::Return(QuicTime::Delta::FromMicroseconds(1))); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0); + connection_.SendOrQueuePacket(1, packet, kTestEntropyHash); EXPECT_EQ(1u, connection_.NumQueuedPackets()); } TEST_F(QuicConnectionTest, SendSchedulerForce) { // Test that if we force send a packet, it is not queued. - QuicPacket* packet = ConstructDataPacket(1, 0); - EXPECT_CALL(*send_algorithm_, TimeUntilSend(true)).Times(0); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)); - connection_.SendOrQueuePacket(1, packet, true); + QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, kIsRetransmission)).Times(0); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + connection_.SendOrQueuePacket(1, packet, kTestEntropyHash); + // XXX: fixme. was: connection_.SendOrQueuePacket(1, packet, kForce); EXPECT_EQ(0u, connection_.NumQueuedPackets()); } TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) { - QuicPacket* packet = ConstructDataPacket(1, 0); + QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); helper_->set_blocked(true); - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::Zero())); - EXPECT_CALL(*send_algorithm_, SentPacket(1, _, _)).Times(0); - connection_.SendOrQueuePacket(1, packet, false); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce( + testing::Return(QuicTime::Delta::Zero())); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0); + connection_.SendOrQueuePacket(1, packet, kTestEntropyHash); EXPECT_EQ(1u, connection_.NumQueuedPackets()); } TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) { // Test that if we send a packet with a delay, it ends up queued. - QuicPacket* packet = ConstructDataPacket(1, 0); - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::FromMicroseconds(1))); - connection_.SendOrQueuePacket(1, packet, false); + QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce( + testing::Return(QuicTime::Delta::FromMicroseconds(1))); + connection_.SendOrQueuePacket(1, packet, kTestEntropyHash); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Advance the clock to fire the alarm, and configure the scheduler // to permit the packet to be sent. - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::Zero())); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce( + testing::Return(QuicTime::Delta::Zero())); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)); + helper_->UnregisterSendAlarmIfRegistered(); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); EXPECT_CALL(visitor_, OnCanWrite()); connection_.OnCanWrite(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); } TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) { - // Fake packet loss. - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::Zero())); - EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false)); - connection_.SendStreamData(1, "foo", 0, false); + EXPECT_CALL(*send_algorithm_, + TimeUntilSend(_, !kIsRetransmission)).WillRepeatedly( + testing::Return(QuicTime::Delta::Zero())); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, !kIsRetransmission)); + connection_.SendStreamData(1, "foo", 0, !kFin); EXPECT_EQ(0u, connection_.NumQueuedPackets()); // Advance the time for retransmission of lost packet. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(501)); // Test that if we send a retransmit with a delay, it ends up queued. - EXPECT_CALL(*send_algorithm_, TimeUntilSend(true)).WillOnce(testing::Return( - QuicTime::Delta::FromMicroseconds(1))); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, kIsRetransmission)).WillOnce( + testing::Return(QuicTime::Delta::FromMicroseconds(1))); connection_.OnRetransmissionTimeout(); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Advance the clock to fire the alarm, and configure the scheduler // to permit the packet to be sent. - EXPECT_CALL(*send_algorithm_, TimeUntilSend(true)).WillOnce(testing::Return( - QuicTime::Delta::Zero())); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, kIsRetransmission)).WillOnce( + testing::Return(QuicTime::Delta::Zero())); // Ensure the scheduler is notified this is a retransmit. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, true)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, kIsRetransmission)); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1)); + helper_->UnregisterSendAlarmIfRegistered(); EXPECT_CALL(visitor_, OnCanWrite()); connection_.OnCanWrite(); EXPECT_EQ(0u, connection_.NumQueuedPackets()); } TEST_F(QuicConnectionTest, SendSchedulerDelayAndQueue) { - QuicPacket* packet = ConstructDataPacket(1, 0); - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::FromMicroseconds(1))); - connection_.SendOrQueuePacket(1, packet, false); + QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce( + testing::Return(QuicTime::Delta::FromMicroseconds(1))); + connection_.SendOrQueuePacket(1, packet, kTestEntropyHash); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Attempt to send another packet and make sure that it gets queued. - packet = ConstructDataPacket(2, 0); - connection_.SendOrQueuePacket(2, packet, false); + packet = ConstructDataPacket(2, 0, !kEntropyFlag); + connection_.SendOrQueuePacket(2, packet, kTestEntropyHash); EXPECT_EQ(2u, connection_.NumQueuedPackets()); } TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) { - QuicPacket* packet = ConstructDataPacket(1, 0); - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::FromMicroseconds(10))); - connection_.SendOrQueuePacket(1, packet, false); + QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce( + testing::Return(QuicTime::Delta::FromMicroseconds(10))); + connection_.SendOrQueuePacket(1, packet, kTestEntropyHash); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Now send non-retransmitting information, that we're not going to // retransmit 3. The far end should stop waiting for it. QuicAckFrame frame(0, 1); EXPECT_CALL(*send_algorithm_, - TimeUntilSend(false)).WillRepeatedly( + TimeUntilSend(_, !kIsRetransmission)).WillRepeatedly( testing::Return(QuicTime::Delta::Zero())); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)); - EXPECT_CALL(visitor_, OnCanWrite()); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)); + EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(Return(true)); ProcessAckPacket(&frame); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -1172,27 +1389,27 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) { } TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) { - QuicPacket* packet = ConstructDataPacket(1, 0); - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::FromMicroseconds(10))); - connection_.SendOrQueuePacket(1, packet, false); + QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce( + testing::Return(QuicTime::Delta::FromMicroseconds(10))); + connection_.SendOrQueuePacket(1, packet, kTestEntropyHash); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Now send non-retransmitting information, that we're not going to // retransmit 3. The far end should stop waiting for it. QuicAckFrame frame(0, 1); - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::FromMicroseconds(1))); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce( + testing::Return(QuicTime::Delta::FromMicroseconds(1))); ProcessAckPacket(&frame); EXPECT_EQ(1u, connection_.NumQueuedPackets()); } TEST_F(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) { - QuicPacket* packet = ConstructDataPacket(1, 0); - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::FromMicroseconds(10))); - connection_.SendOrQueuePacket(1, packet, false); + QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce( + testing::Return(QuicTime::Delta::FromMicroseconds(10))); + connection_.SendOrQueuePacket(1, packet, kTestEntropyHash); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // OnCanWrite should not send the packet (because of the delay) @@ -1209,11 +1426,11 @@ TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) { ciphertext_size + QuicUtils::StreamFramePacketOverhead(1); // Queue the first packet. - EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta::FromMicroseconds(10))); - EXPECT_EQ(1u, connection_.SendStreamData( - 1, "EnoughDataToQueue", 0, false).bytes_consumed); - EXPECT_EQ(1u, connection_.NumQueuedPackets()); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce( + testing::Return(QuicTime::Delta::FromMicroseconds(10))); + EXPECT_EQ(0u, connection_.SendStreamData( + 1, "EnoughDataToQueue", 0, !kFin).bytes_consumed); + EXPECT_EQ(0u, connection_.NumQueuedPackets()); } TEST_F(QuicConnectionTest, LoopThroughSendingPackets) { @@ -1223,33 +1440,34 @@ TEST_F(QuicConnectionTest, LoopThroughSendingPackets) { ciphertext_size + QuicUtils::StreamFramePacketOverhead(1); // Queue the first packet. - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(17); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(17); EXPECT_EQ(17u, connection_.SendStreamData( - 1, "EnoughDataToQueue", 0, false).bytes_consumed); + 1, "EnoughDataToQueue", 0, !kFin).bytes_consumed); } TEST_F(QuicConnectionTest, NoAckForClose) { ProcessPacket(1); EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(0); - EXPECT_CALL(visitor_, ConnectionClose(QUIC_CLIENT_GOING_AWAY, true)); - EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(0); + EXPECT_CALL(visitor_, ConnectionClose(QUIC_PEER_GOING_AWAY, true)); + EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(0); ProcessClosePacket(2, 0); } TEST_F(QuicConnectionTest, SendWhenDisconnected) { EXPECT_TRUE(connection_.connected()); - EXPECT_CALL(visitor_, ConnectionClose(QUIC_CLIENT_GOING_AWAY, false)); - connection_.CloseConnection(QUIC_CLIENT_GOING_AWAY, false); + EXPECT_CALL(visitor_, ConnectionClose(QUIC_PEER_GOING_AWAY, false)); + connection_.CloseConnection(QUIC_PEER_GOING_AWAY, false); EXPECT_FALSE(connection_.connected()); - QuicPacket* packet = ConstructDataPacket(1, 0); - EXPECT_CALL(*send_algorithm_, SentPacket(1, _, _)).Times(0); - connection_.SendOrQueuePacket(1, packet, false); + QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag); + EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, _)).Times(0); + connection_.SendOrQueuePacket(1, packet, kTestEntropyHash); } TEST_F(QuicConnectionTest, PublicReset) { QuicPublicResetPacket header; header.public_header.guid = guid_; - header.public_header.flags = PACKET_PUBLIC_FLAGS_RST; + header.public_header.reset_flag = true; + header.public_header.version_flag = false; header.rejected_sequence_number = 10101; scoped_ptr<QuicEncryptedPacket> packet( framer_.ConstructPublicResetPacket(header)); @@ -1257,6 +1475,123 @@ TEST_F(QuicConnectionTest, PublicReset) { connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *packet); } +TEST_F(QuicConnectionTest, GoAway) { + QuicGoAwayFrame goaway; + goaway.last_good_stream_id = 1; + goaway.error_code = QUIC_PEER_GOING_AWAY; + goaway.reason_phrase = "Going away."; + EXPECT_CALL(visitor_, OnGoAway(_)); + ProcessGoAwayPacket(&goaway); +} + +TEST_F(QuicConnectionTest, MissingPacketsBeforeLeastUnacked) { + QuicAckFrame ack(0, 4); + // Set the sequence number of the ack packet to be least unacked (4) + creator_.set_sequence_number(3); + ProcessAckPacket(&ack); + EXPECT_TRUE(outgoing_ack()->received_info.missing_packets.empty()); +} + +TEST_F(QuicConnectionTest, ReceivedEntropyHashCalculation) { + EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillRepeatedly(Return(true)); + ProcessDataPacket(1, 1, kEntropyFlag); + ProcessDataPacket(4, 1, kEntropyFlag); + ProcessDataPacket(3, 1, !kEntropyFlag); + ProcessDataPacket(7, 1, kEntropyFlag); + EXPECT_EQ(146u, outgoing_ack()->received_info.entropy_hash); +} + +TEST_F(QuicConnectionTest, UpdateEntropyForReceivedPackets) { + EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillRepeatedly(Return(true)); + ProcessDataPacket(1, 1, kEntropyFlag); + ProcessDataPacket(5, 1, kEntropyFlag); + ProcessDataPacket(4, 1, !kEntropyFlag); + EXPECT_EQ(34u, outgoing_ack()->received_info.entropy_hash); + // Make 4th packet my least unacked, and update entropy for 2, 3 packets. + QuicAckFrame ack(0, 4); + QuicPacketEntropyHash kRandomEntropyHash = 129u; + ack.sent_info.entropy_hash = kRandomEntropyHash; + creator_.set_sequence_number(5); + QuicPacketEntropyHash six_packet_entropy_hash = 0; + if (ProcessAckPacket(&ack)) { + six_packet_entropy_hash = 1 << 6; + }; + + EXPECT_EQ((kRandomEntropyHash + (1 << 5) + six_packet_entropy_hash), + outgoing_ack()->received_info.entropy_hash); +} + +TEST_F(QuicConnectionTest, UpdateEntropyHashUptoCurrentPacket) { + EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillRepeatedly(Return(true)); + ProcessDataPacket(1, 1, kEntropyFlag); + ProcessDataPacket(5, 1, !kEntropyFlag); + ProcessDataPacket(22, 1, kEntropyFlag); + EXPECT_EQ(66u, outgoing_ack()->received_info.entropy_hash); + creator_.set_sequence_number(22); + QuicPacketEntropyHash kRandomEntropyHash = 85u; + // Current packet is the least unacked packet. + QuicAckFrame ack(0, 23); + ack.sent_info.entropy_hash = kRandomEntropyHash; + QuicPacketEntropyHash ack_entropy_hash = ProcessAckPacket(&ack); + EXPECT_EQ((kRandomEntropyHash + ack_entropy_hash), + outgoing_ack()->received_info.entropy_hash); + ProcessDataPacket(25, 1, kEntropyFlag); + EXPECT_EQ((kRandomEntropyHash + ack_entropy_hash + (1 << (25 % 8))), + outgoing_ack()->received_info.entropy_hash); +} + +TEST_F(QuicConnectionTest, EntropyCalculationForTruncatedAck) { + EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillRepeatedly(Return(true)); + QuicPacketEntropyHash entropy[51]; + entropy[0] = 0; + for (int i = 1; i < 51; ++i) { + bool should_send = i % 10 != 0; + bool entropy_flag = (i & (i - 1)) != 0; + if (!should_send) { + entropy[i] = entropy[i - 1]; + continue; + } + if (entropy_flag) { + entropy[i] = entropy[i - 1] ^ (1 << (i % 8)); + } else { + entropy[i] = entropy[i - 1]; + } + ProcessDataPacket(i, 1, entropy_flag); + } + // Till 50 since 50th packet is not sent. + for (int i = 1; i < 50; ++i) { + EXPECT_EQ(entropy[i], QuicConnectionPeer::ReceivedEntropyHash( + &connection_, i)); + } +} + +TEST_F(QuicConnectionTest, CheckSentEntropyHash) { + creator_.set_sequence_number(1); + SequenceNumberSet missing_packets; + QuicPacketEntropyHash entropy_hash = 0; + QuicPacketSequenceNumber max_sequence_number = 51; + for (QuicPacketSequenceNumber i = 1; i <= max_sequence_number; ++i) { + bool is_missing = i % 10 != 0; + bool entropy_flag = (i & (i - 1)) != 0; + QuicPacketEntropyHash packet_entropy_hash = 0; + if (entropy_flag) { + packet_entropy_hash = 1 << (i % 8); + } + QuicPacket* packet = ConstructDataPacket(i, 0, entropy_flag); + connection_.SendOrQueuePacket(i, packet, packet_entropy_hash); + + if (is_missing) { + missing_packets.insert(i); + continue; + } + + entropy_hash ^= packet_entropy_hash; + } + EXPECT_TRUE(QuicConnectionPeer::IsValidEntropy( + &connection_, max_sequence_number, missing_packets, entropy_hash)) + << ""; +} + } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_fec_group.cc b/net/quic/quic_fec_group.cc index af976a3..8431ff3 100644 --- a/net/quic/quic_fec_group.cc +++ b/net/quic/quic_fec_group.cc @@ -21,7 +21,8 @@ const QuicPacketSequenceNumber kNoSequenceNumber = kuint64max; QuicFecGroup::QuicFecGroup() : min_protected_packet_(kNoSequenceNumber), max_protected_packet_(kNoSequenceNumber), - parity_len_(0) { + payload_parity_len_(0), + entropy_parity_(false) { } QuicFecGroup::~QuicFecGroup() {} @@ -39,7 +40,7 @@ bool QuicFecGroup::Update(const QuicPacketHeader& header, << header.packet_sequence_number; return false; } - if (!UpdateParity(decrypted_payload)) { + if (!UpdateParity(decrypted_payload, header.entropy_flag)) { return false; } received_packets_.insert(header.packet_sequence_number); @@ -48,11 +49,12 @@ bool QuicFecGroup::Update(const QuicPacketHeader& header, bool QuicFecGroup::UpdateFec( QuicPacketSequenceNumber fec_packet_sequence_number, + bool fec_entropy_flag, const QuicFecData& fec) { if (min_protected_packet_ != kNoSequenceNumber) { return false; } - set<QuicPacketSequenceNumber>::const_iterator it = received_packets_.begin(); + SequenceNumberSet::const_iterator it = received_packets_.begin(); while (it != received_packets_.end()) { if ((*it < fec.fec_group) || (*it >= fec_packet_sequence_number)) { @@ -61,7 +63,7 @@ bool QuicFecGroup::UpdateFec( } ++it; } - if (!UpdateParity(fec.redundancy)) { + if (!UpdateParity(fec.redundancy, fec_entropy_flag)) { return false; } min_protected_packet_ = fec.fec_group; @@ -98,16 +100,19 @@ size_t QuicFecGroup::Revive(QuicPacketHeader* header, } DCHECK_NE(kNoSequenceNumber, missing); - DCHECK_LE(parity_len_, decrypted_payload_len); - if (parity_len_ > decrypted_payload_len) { + DCHECK_LE(payload_parity_len_, decrypted_payload_len); + if (payload_parity_len_ > decrypted_payload_len) { return 0; } - for (size_t i = 0; i < parity_len_; ++i) { - decrypted_payload[i] = parity_[i]; + for (size_t i = 0; i < payload_parity_len_; ++i) { + decrypted_payload[i] = payload_parity_[i]; } + header->packet_sequence_number = missing; + header->entropy_flag = entropy_parity_; + received_packets_.insert(missing); - return parity_len_; + return payload_parity_len_; } bool QuicFecGroup::ProtectsPacketsBefore(QuicPacketSequenceNumber num) const { @@ -119,32 +124,35 @@ bool QuicFecGroup::ProtectsPacketsBefore(QuicPacketSequenceNumber num) const { return *received_packets_.begin() < num; } -bool QuicFecGroup::UpdateParity(StringPiece payload) { +bool QuicFecGroup::UpdateParity(StringPiece payload, bool entropy) { DCHECK_LE(payload.size(), kMaxPacketSize); if (payload.size() > kMaxPacketSize) { DLOG(ERROR) << "Illegal payload size: " << payload.size(); return false; } - if (parity_len_ < payload.size()) { - parity_len_ = payload.size(); + if (payload_parity_len_ < payload.size()) { + payload_parity_len_ = payload.size(); } DCHECK_LE(payload.size(), kMaxPacketSize); if (received_packets_.size() == 0 && min_protected_packet_ == kNoSequenceNumber) { // Initialize the parity to the value of this payload - memcpy(parity_, payload.data(), payload.size()); + memcpy(payload_parity_, payload.data(), payload.size()); if (payload.size() < kMaxPacketSize) { // TODO(rch): expand as needed. - memset(parity_ + payload.size(), 0, + memset(payload_parity_ + payload.size(), 0, kMaxPacketSize - payload.size()); } + entropy_parity_ = entropy; return true; } // Update the parity by XORing in the data (padding with 0s if necessary). for (size_t i = 0; i < kMaxPacketSize; ++i) { uint8 byte = i < payload.size() ? payload[i] : 0x00; - parity_[i] ^= byte; + payload_parity_[i] ^= byte; } + // xor of boolean values. + entropy_parity_ = (entropy_parity_ != entropy); return true; } diff --git a/net/quic/quic_fec_group.h b/net/quic/quic_fec_group.h index 14fdec8..f9d4e28 100644 --- a/net/quic/quic_fec_group.h +++ b/net/quic/quic_fec_group.h @@ -30,6 +30,7 @@ class NET_EXPORT_PRIVATE QuicFecGroup { // Returns false if this packet has already been seen or if it does // not claim to protect all the packets previously seen in this group. bool UpdateFec(QuicPacketSequenceNumber fec_packet_sequence_number, + bool fec_entropy_flag, const QuicFecData& fec); // Returns true if a packet can be revived from this FEC group. @@ -51,8 +52,12 @@ class NET_EXPORT_PRIVATE QuicFecGroup { // numbers less than |num|. bool ProtectsPacketsBefore(QuicPacketSequenceNumber num) const; - const base::StringPiece parity() const { - return base::StringPiece(parity_, parity_len_); + const base::StringPiece payload_parity() const { + return base::StringPiece(payload_parity_, payload_parity_len_); + } + + bool entropy_parity() const { + return entropy_parity_; } QuicPacketSequenceNumber min_protected_packet() const { @@ -64,13 +69,13 @@ class NET_EXPORT_PRIVATE QuicFecGroup { } private: - bool UpdateParity(base::StringPiece payload); + bool UpdateParity(base::StringPiece payload, bool entropy); // Returns the number of missing packets, or size_t max if the number // of missing packets is not known. size_t NumMissingPackets() const; // Set of packets that we have recevied. - std::set<QuicPacketSequenceNumber> received_packets_; + SequenceNumberSet received_packets_; // Sequence number of the first protected packet in this group (the one // with the lowest packet sequence number). Will only be set once the FEC // packet has been seen. @@ -80,8 +85,9 @@ class NET_EXPORT_PRIVATE QuicFecGroup { // packet has been seen. QuicPacketSequenceNumber max_protected_packet_; // The cumulative parity calculation of all received packets. - char parity_[kMaxPacketSize]; - size_t parity_len_; + char payload_parity_[kMaxPacketSize]; + size_t payload_parity_len_; + bool entropy_parity_; }; } // namespace net diff --git a/net/quic/quic_fec_group_test.cc b/net/quic/quic_fec_group_test.cc index 4e4dd20..2dd4a7d 100644 --- a/net/quic/quic_fec_group_test.cc +++ b/net/quic/quic_fec_group_test.cc @@ -18,14 +18,25 @@ namespace net { namespace { const char* kData[] = { - "abc12345678", - "987defg", - "ghi12345", - "987jlkmno", - "mno4567890", - "789pqrstuvw", + "abc12345678", + "987defg", + "ghi12345", + "987jlkmno", + "mno4567890", + "789pqrstuvw", }; +const bool kEntropyFlag[] = { + false, + true, + true, + false, + true, + true, +}; + +const bool kTestFecEntropy = false; + } // namespace class QuicFecGroupTest : public ::testing::Test { @@ -33,14 +44,19 @@ class QuicFecGroupTest : public ::testing::Test { void RunTest(size_t num_packets, size_t lost_packet, bool out_of_order) { size_t max_len = strlen(kData[0]); scoped_array<char>redundancy(new char[max_len]); - for (size_t i = 0; i < max_len; i++) { - // Initialize to the first packet. - redundancy[i] = kData[0][i]; - // XOR in the remaining packets. - for (size_t packet = 1; packet < num_packets; packet++) { + bool entropy_redundancy = false; + for (size_t packet = 0; packet < num_packets; ++packet) { + for (size_t i = 0; i < max_len; i++) { + if (packet == 0) { + // Initialize to the first packet. + redundancy[i] = kData[0][i]; + continue; + } + // XOR in the remaining packets. uint8 byte = i > strlen(kData[packet]) ? 0x00 : kData[packet][i]; redundancy[i] = redundancy[i] ^ byte; } + entropy_redundancy = (entropy_redundancy != kEntropyFlag[packet]); } QuicFecGroup group; @@ -55,10 +71,11 @@ class QuicFecGroupTest : public ::testing::Test { QuicFecData fec; fec.fec_group = 0; fec.redundancy = StringPiece(redundancy.get(), strlen(kData[0])); - ASSERT_TRUE(group.UpdateFec(num_packets, fec)); + ASSERT_TRUE(group.UpdateFec(num_packets, entropy_redundancy, fec)); } else { QuicPacketHeader header; header.packet_sequence_number = packet; + header.entropy_flag = kEntropyFlag[packet]; ASSERT_TRUE(group.Update(header, kData[packet])); } ASSERT_TRUE(group.CanRevive() == (packet == num_packets - 1)); @@ -72,6 +89,7 @@ class QuicFecGroupTest : public ::testing::Test { QuicPacketHeader header; header.packet_sequence_number = packet; + header.entropy_flag = kEntropyFlag[packet]; ASSERT_TRUE(group.Update(header, kData[packet])); ASSERT_FALSE(group.CanRevive()); } @@ -82,7 +100,7 @@ class QuicFecGroupTest : public ::testing::Test { fec.fec_group = 0; fec.redundancy = StringPiece(redundancy.get(), strlen(kData[0])); - ASSERT_TRUE(group.UpdateFec(num_packets, fec)); + ASSERT_TRUE(group.UpdateFec(num_packets, entropy_redundancy, fec)); } QuicPacketHeader header; char recovered[kMaxPacketSize]; @@ -94,6 +112,7 @@ class QuicFecGroupTest : public ::testing::Test { EXPECT_EQ(lost_packet, header.packet_sequence_number) << "Failed to revive packet " << lost_packet << " out of " << num_packets; + EXPECT_EQ(kEntropyFlag[lost_packet], header.entropy_flag); ASSERT_GE(len, strlen(kData[lost_packet])) << "Incorrect length"; for (size_t i = 0; i < strlen(kData[lost_packet]); i++) { EXPECT_EQ(kData[lost_packet][i], recovered[i]); @@ -137,7 +156,8 @@ TEST_F(QuicFecGroupTest, UpdateFecIfReceivedPacketIsNotCovered) { fec.fec_group = 1; fec.redundancy = redundancy; - ASSERT_FALSE(group.UpdateFec(2, fec)); + header.packet_sequence_number = 2; + ASSERT_FALSE(group.UpdateFec(2, kTestFecEntropy, fec)); } TEST_F(QuicFecGroupTest, ProtectsPacketsBefore) { @@ -186,7 +206,7 @@ TEST_F(QuicFecGroupTest, ProtectsPacketsBeforeWithFecData) { fec.redundancy = kData[0]; QuicFecGroup group; - ASSERT_TRUE(group.UpdateFec(3, fec)); + ASSERT_TRUE(group.UpdateFec(3, kTestFecEntropy, fec)); EXPECT_FALSE(group.ProtectsPacketsBefore(1)); EXPECT_FALSE(group.ProtectsPacketsBefore(2)); diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index a794701..db3de8d5 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc @@ -86,8 +86,19 @@ size_t QuicFramer::GetSerializedFrameLength( return frame_len; } -QuicPacket* QuicFramer::ConstructFrameDataPacket(const QuicPacketHeader& header, - const QuicFrames& frames) { +QuicPacketEntropyHash QuicFramer::GetPacketEntropyHash( + const QuicPacketHeader& header) const { + if (!header.entropy_flag) { + // TODO(satyamshekhar): Return some more better value here (something that + // is not a constant). + return 0; + } + return 1 << (header.packet_sequence_number % 8); +} + +SerializedPacket QuicFramer::ConstructFrameDataPacket( + const QuicPacketHeader& header, + const QuicFrames& frames) { const size_t max_plaintext_size = GetMaxPlaintextSize(kMaxPacketSize); size_t packet_size = kPacketHeaderSize; for (size_t i = 0; i < frames.size(); ++i) { @@ -100,18 +111,20 @@ QuicPacket* QuicFramer::ConstructFrameDataPacket(const QuicPacketHeader& header, return ConstructFrameDataPacket(header, frames, packet_size); } -QuicPacket* QuicFramer::ConstructFrameDataPacket(const QuicPacketHeader& header, - const QuicFrames& frames, - size_t packet_size) { +SerializedPacket QuicFramer::ConstructFrameDataPacket( + const QuicPacketHeader& header, + const QuicFrames& frames, + size_t packet_size) { QuicDataWriter writer(packet_size); + SerializedPacket kNoPacket = SerializedPacket(0, NULL, 0, NULL); if (!WritePacketHeader(header, &writer)) { - return NULL; + return kNoPacket; } for (size_t i = 0; i < frames.size(); ++i) { const QuicFrame& frame = frames[i]; if (!writer.WriteUInt8(frame.type)) { - return NULL; + return kNoPacket; } switch (frame.type) { @@ -120,34 +133,39 @@ QuicPacket* QuicFramer::ConstructFrameDataPacket(const QuicPacketHeader& header, break; case STREAM_FRAME: if (!AppendStreamFramePayload(*frame.stream_frame, &writer)) { - return NULL; + return kNoPacket; } break; case ACK_FRAME: if (!AppendAckFramePayload(*frame.ack_frame, &writer)) { - return NULL; + return kNoPacket; } break; case CONGESTION_FEEDBACK_FRAME: if (!AppendQuicCongestionFeedbackFramePayload( *frame.congestion_feedback_frame, &writer)) { - return NULL; + return kNoPacket; } break; case RST_STREAM_FRAME: if (!AppendRstStreamFramePayload(*frame.rst_stream_frame, &writer)) { - return NULL; + return kNoPacket; } break; case CONNECTION_CLOSE_FRAME: if (!AppendConnectionCloseFramePayload( *frame.connection_close_frame, &writer)) { - return NULL; + return kNoPacket; + } + break; + case GOAWAY_FRAME: + if (!AppendGoAwayFramePayload(*frame.goaway_frame, &writer)) { + return kNoPacket; } break; default: RaiseError(QUIC_INVALID_FRAME_DATA); - return NULL; + return kNoPacket; } } @@ -163,32 +181,35 @@ QuicPacket* QuicFramer::ConstructFrameDataPacket(const QuicPacketHeader& header, packet->FecProtectedData()); } - return packet; + return SerializedPacket(header.packet_sequence_number, packet, + GetPacketEntropyHash(header), NULL); } -QuicPacket* QuicFramer::ConstructFecPacket(const QuicPacketHeader& header, - const QuicFecData& fec) { +SerializedPacket QuicFramer::ConstructFecPacket(const QuicPacketHeader& header, + const QuicFecData& fec) { size_t len = kPacketHeaderSize; len += fec.redundancy.length(); QuicDataWriter writer(len); - + SerializedPacket kNoPacket = SerializedPacket(0, NULL, 0, NULL); if (!WritePacketHeader(header, &writer)) { - return NULL; + return kNoPacket; } if (!writer.WriteBytes(fec.redundancy.data(), fec.redundancy.length())) { - return NULL; + return kNoPacket; } - return QuicPacket::NewFecPacket(writer.take(), len, true); + return SerializedPacket(header.packet_sequence_number, + QuicPacket::NewFecPacket(writer.take(), len, true), + GetPacketEntropyHash(header), NULL); } // static QuicEncryptedPacket* QuicFramer::ConstructPublicResetPacket( const QuicPublicResetPacket& packet) { - DCHECK_EQ(PACKET_PUBLIC_FLAGS_RST, - PACKET_PUBLIC_FLAGS_RST & packet.public_header.flags); + DCHECK(packet.public_header.reset_flag); + DCHECK(!packet.public_header.version_flag); size_t len = kPublicResetPacketSize; QuicDataWriter writer(len); @@ -196,7 +217,7 @@ QuicEncryptedPacket* QuicFramer::ConstructPublicResetPacket( return NULL; } - uint8 flags = static_cast<uint8>(packet.public_header.flags); + uint8 flags = static_cast<uint8>(PACKET_PUBLIC_FLAGS_RST); if (!writer.WriteUInt8(flags)) { return NULL; } @@ -226,7 +247,7 @@ bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) { } bool rv; - if (public_header.flags & PACKET_PUBLIC_FLAGS_RST) { + if (public_header.reset_flag) { rv = ProcessPublicResetPacket(public_header); } else { rv = ProcessDataPacket(public_header, packet); @@ -257,7 +278,7 @@ bool QuicFramer::ProcessDataPacket( } // Handle the payload. - if ((header.private_flags & PACKET_PRIVATE_FLAGS_FEC) == 0) { + if (!header.fec_flag) { if (header.fec_group != 0) { StringPiece payload = reader_->PeekRemainingPayload(); visitor_->OnFecProtectedPayload(payload); @@ -295,13 +316,16 @@ bool QuicFramer::ProcessPublicResetPacket( return true; } -bool QuicFramer::ProcessRevivedPacket(const QuicPacketHeader& header, +bool QuicFramer::ProcessRevivedPacket(QuicPacketHeader* header, StringPiece payload) { DCHECK(!reader_.get()); visitor_->OnRevivedPacket(); - visitor_->OnPacketHeader(header); + header->entropy_hash = GetPacketEntropyHash(*header); + + // TODO(satyamshekhar): Don't process if the visitor refuses the header. + visitor_->OnPacketHeader(*header); if (payload.length() > kMaxPacketSize) { set_detailed_error("Revived packet too large."); @@ -326,7 +350,13 @@ bool QuicFramer::WritePacketHeader(const QuicPacketHeader& header, return false; } - uint8 flags = static_cast<uint8>(header.public_header.flags); + uint8 flags = 0; + if (header.public_header.reset_flag) { + flags |= PACKET_PUBLIC_FLAGS_RST; + } + if (header.public_header.version_flag) { + flags |= PACKET_PUBLIC_FLAGS_VERSION; + } if (!writer->WriteUInt8(flags)) { return false; } @@ -335,7 +365,16 @@ bool QuicFramer::WritePacketHeader(const QuicPacketHeader& header, return false; } - flags = static_cast<uint8>(header.private_flags); + flags = 0; + if (header.fec_flag) { + flags |= PACKET_PRIVATE_FLAGS_FEC; + } + if (header.entropy_flag) { + flags |= PACKET_PRIVATE_FLAGS_ENTROPY; + } + if (header.fec_entropy_flag) { + flags |= PACKET_PRIVATE_FLAGS_FEC_ENTROPY; + } if (!writer->WriteUInt8(flags)) { return false; } @@ -361,7 +400,7 @@ bool QuicFramer::WritePacketHeader(const QuicPacketHeader& header, QuicPacketSequenceNumber QuicFramer::CalculatePacketSequenceNumberFromWire( QuicPacketSequenceNumber packet_sequence_number) const { - // The new sequence number might have wrapped to the next epoc, or + // The new sequence number might have wrapped to the next epoch, or // it might have reverse wrapped to the previous epoch, or it might // remain in the same epoch. Select the sequence number closest to the // previous sequence number. @@ -393,7 +432,10 @@ bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) { return false; } - public_header->flags = static_cast<QuicPacketPublicFlags>(public_flags); + public_header->reset_flag = (public_flags & PACKET_PUBLIC_FLAGS_RST) != 0; + public_header->version_flag = + (public_flags & PACKET_PUBLIC_FLAGS_VERSION) != 0; + return true; } @@ -417,7 +459,7 @@ bool QuicFramer::ProcessPacketHeader( return false; } - if (!DecryptPayload(packet)) { + if (!DecryptPayload(header->packet_sequence_number, packet)) { DLOG(WARNING) << "Unable to decrypt payload."; return RaiseError(QUIC_DECRYPTION_FAILURE); } @@ -433,7 +475,10 @@ bool QuicFramer::ProcessPacketHeader( return false; } - header->private_flags = static_cast<QuicPacketPrivateFlags>(private_flags); + header->fec_flag = (private_flags & PACKET_PRIVATE_FLAGS_FEC) != 0; + header->entropy_flag = (private_flags & PACKET_PRIVATE_FLAGS_ENTROPY) != 0; + header->fec_entropy_flag = + (private_flags & PACKET_PRIVATE_FLAGS_FEC_ENTROPY) != 0; uint8 first_fec_protected_packet_offset; if (!reader_->ReadBytes(&first_fec_protected_packet_offset, 1)) { @@ -443,6 +488,7 @@ bool QuicFramer::ProcessPacketHeader( header->fec_group = first_fec_protected_packet_offset == kNoFecOffset ? 0 : header->packet_sequence_number - first_fec_protected_packet_offset; + header->entropy_hash = GetPacketEntropyHash(*header); // Set the last sequence number after we have decrypted the packet // so we are confident is not attacker controlled. last_sequence_number_ = header->packet_sequence_number; @@ -505,6 +551,11 @@ bool QuicFramer::ProcessFrameData() { return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA); } break; + case GOAWAY_FRAME: + if (!ProcessGoAwayFrame()) { + return RaiseError(QUIC_INVALID_GOAWAY_DATA); + } + break; default: set_detailed_error("Illegal frame type."); DLOG(WARNING) << "Illegal frame type: " @@ -560,6 +611,11 @@ bool QuicFramer::ProcessAckFrame(QuicAckFrame* frame) { } bool QuicFramer::ProcessReceivedInfo(ReceivedPacketInfo* received_info) { + if (!reader_->ReadBytes(&received_info->entropy_hash, 1)) { + set_detailed_error("Unable to read entropy hash for received packets."); + return false; + } + if (!ProcessPacketSequenceNumber(&received_info->largest_observed)) { set_detailed_error("Unable to read largest observed."); return false; @@ -584,6 +640,11 @@ bool QuicFramer::ProcessReceivedInfo(ReceivedPacketInfo* received_info) { } bool QuicFramer::ProcessSentInfo(SentPacketInfo* sent_info) { + if (!reader_->ReadBytes(&sent_info->entropy_hash, 1)) { + set_detailed_error("Unable to read entropy hash for sent packets."); + return false; + } + if (!ProcessPacketSequenceNumber(&sent_info->least_unacked)) { set_detailed_error("Unable to read least unacked."); return false; @@ -700,11 +761,6 @@ bool QuicFramer::ProcessRstStreamFrame() { return false; } - if (!reader_->ReadUInt64(&frame.offset)) { - set_detailed_error("Unable to read offset in rst frame."); - return false; - } - uint32 error_code; if (!reader_->ReadUInt32(&error_code)) { set_detailed_error("Unable to read rst stream error code."); @@ -749,8 +805,39 @@ bool QuicFramer::ProcessConnectionCloseFrame() { return true; } -QuicEncryptedPacket* QuicFramer::EncryptPacket(const QuicPacket& packet) { - scoped_ptr<QuicData> out(encrypter_->Encrypt(packet.AssociatedData(), +bool QuicFramer::ProcessGoAwayFrame() { + QuicGoAwayFrame frame; + + uint32 error_code; + if (!reader_->ReadUInt32(&error_code)) { + set_detailed_error("Unable to read go away error code."); + return false; + } + frame.error_code = static_cast<QuicErrorCode>(error_code); + + uint32 stream_id; + if (!reader_->ReadUInt32(&stream_id)) { + set_detailed_error("Unable to read last good stream id."); + return false; + } + frame.last_good_stream_id = static_cast<QuicErrorCode>(stream_id); + + StringPiece reason_phrase; + if (!reader_->ReadStringPiece16(&reason_phrase)) { + set_detailed_error("Unable to read goaway reason."); + return false; + } + frame.reason_phrase = reason_phrase.as_string(); + + visitor_->OnGoAwayFrame(frame); + return true; +} + +QuicEncryptedPacket* QuicFramer::EncryptPacket( + QuicPacketSequenceNumber packet_sequence_number, + const QuicPacket& packet) { + scoped_ptr<QuicData> out(encrypter_->Encrypt(packet_sequence_number, + packet.AssociatedData(), packet.Plaintext())); if (out.get() == NULL) { RaiseError(QUIC_ENCRYPTION_FAILURE); @@ -768,13 +855,15 @@ size_t QuicFramer::GetMaxPlaintextSize(size_t ciphertext_size) { return encrypter_->GetMaxPlaintextSize(ciphertext_size); } -bool QuicFramer::DecryptPayload(const QuicEncryptedPacket& packet) { +bool QuicFramer::DecryptPayload(QuicPacketSequenceNumber sequence_number, + const QuicEncryptedPacket& packet) { StringPiece encrypted; if (!reader_->ReadStringPiece(&encrypted, reader_->BytesRemaining())) { return false; } DCHECK(decrypter_.get() != NULL); - decrypted_.reset(decrypter_->Decrypt(packet.AssociatedData(), encrypted)); + decrypted_.reset(decrypter_->Decrypt(sequence_number, + packet.AssociatedData(), encrypted)); if (decrypted_.get() == NULL) { return false; } @@ -789,34 +878,36 @@ size_t QuicFramer::ComputeFramePayloadLength(const QuicFrame& frame) { // same as sizeof(member_wire_format). switch (frame.type) { case STREAM_FRAME: - len += 4; // stream id - len += 1; // fin - len += 8; // offset - len += 2; // space for the 16 bit length + len += 4; // Stream id of the frame. + len += 1; // A byte for fin. + len += 8; // Byte offset. + len += 2; // Space for the 16 bit length. len += frame.stream_frame->data.size(); break; case ACK_FRAME: { const QuicAckFrame& ack = *frame.ack_frame; - len += 6; // largest observed packet sequence number - len += 1; // num missing packets + len += 1; // Commutative hash of entropy of the packets received. + len += 6; // Least packet sequence number awaiting an ack. + len += 1; // Hash of entropy of the packets sent up to largest observed. + len += 6; // Largest observed packet sequence number. + len += 1; // Number of missing packets. len += 6 * ack.received_info.missing_packets.size(); - len += 6; // least packet sequence number awaiting an ack break; } case CONGESTION_FEEDBACK_FRAME: { const QuicCongestionFeedbackFrame& congestion_feedback = *frame.congestion_feedback_frame; - len += 1; // congestion feedback type + len += 1; // Congestion feedback type. switch (congestion_feedback.type) { case kInterArrival: { const CongestionFeedbackMessageInterArrival& inter_arrival = congestion_feedback.inter_arrival; len += 2; - len += 1; // num received packets + len += 1; // Number received packets. if (inter_arrival.received_packet_times.size() > 0) { - len += 6; // smallest received - len += 8; // time + len += 6; // Smallest received. + len += 8; // Time. // 2 bytes per sequence number delta plus 4 bytes per delta time. len += 6 * (inter_arrival.received_packet_times.size() - 1); } @@ -836,19 +927,24 @@ size_t QuicFramer::ComputeFramePayloadLength(const QuicFrame& frame) { break; } case RST_STREAM_FRAME: - len += 4; // stream id - len += 8; // offset - len += 4; // error code - len += 2; // error details size + len += 4; // Stream id of the frame. + len += 4; // Error code. + len += 2; // Error details size. len += frame.rst_stream_frame->error_details.size(); break; case CONNECTION_CLOSE_FRAME: - len += 4; // error code - len += 2; // error details size + len += 4; // Error code. + len += 2; // Error details size. len += frame.connection_close_frame->error_details.size(); len += ComputeFramePayloadLength( QuicFrame(&frame.connection_close_frame->ack_frame)); break; + case GOAWAY_FRAME: + len += 4; // error code + len += 4; // last good stream id + len += 2; // reason phrase length + len += frame.goaway_frame->reason_phrase.size(); + break; default: set_detailed_error("Illegal frame type."); DLOG(INFO) << "Illegal frame type: " << frame.type; @@ -891,9 +987,9 @@ bool QuicFramer::AppendStreamFramePayload( } QuicPacketSequenceNumber QuicFramer::CalculateLargestObserved( - const SequenceSet& missing_packets, - SequenceSet::const_iterator largest_written) { - SequenceSet::const_iterator it = largest_written; + const SequenceNumberSet& missing_packets, + SequenceNumberSet::const_iterator largest_written) { + SequenceNumberSet::const_iterator it = largest_written; QuicPacketSequenceNumber previous_missing = *it; ++it; @@ -911,10 +1007,21 @@ QuicPacketSequenceNumber QuicFramer::CalculateLargestObserved( bool QuicFramer::AppendAckFramePayload( const QuicAckFrame& frame, QuicDataWriter* writer) { + // TODO(satyamshekhar): Decide how often we really should send this + // entropy_hash update. + if (!writer->WriteUInt8(frame.sent_info.entropy_hash)) { + return false; + } + if (!AppendPacketSequenceNumber(frame.sent_info.least_unacked, writer)) { return false; } + size_t received_entropy_offset = writer->length(); + if (!writer->WriteUInt8(frame.received_info.entropy_hash)) { + return false; + } + size_t largest_observed_offset = writer->length(); if (!AppendPacketSequenceNumber(frame.received_info.largest_observed, writer)) { @@ -929,13 +1036,19 @@ bool QuicFramer::AppendAckFramePayload( return false; } - SequenceSet::const_iterator it = frame.received_info.missing_packets.begin(); + SequenceNumberSet::const_iterator it = + frame.received_info.missing_packets.begin(); int num_missing_packets_written = 0; for (; it != frame.received_info.missing_packets.end(); ++it) { if (!AppendPacketSequenceNumber(*it, writer)) { - // We are truncating. Overwrite largest_observed. + // We are truncating. QuicPacketSequenceNumber largest_observed = CalculateLargestObserved(frame.received_info.missing_packets, --it); + // Overwrite entropy hash for received packets. + writer->WriteUInt8ToOffset( + entropy_calculator_->ReceivedEntropyHash(largest_observed), + received_entropy_offset); + // Overwrite largest_observed. writer->WriteUInt48ToOffset(largest_observed & kSequenceNumberMask, largest_observed_offset); writer->WriteUInt8ToOffset(num_missing_packets_written, @@ -1045,9 +1158,6 @@ bool QuicFramer::AppendRstStreamFramePayload( if (!writer->WriteUInt32(frame.stream_id)) { return false; } - if (!writer->WriteUInt64(frame.offset)) { - return false; - } uint32 error_code = static_cast<uint32>(frame.error_code); if (!writer->WriteUInt32(error_code)) { @@ -1074,6 +1184,22 @@ bool QuicFramer::AppendConnectionCloseFramePayload( return true; } +bool QuicFramer::AppendGoAwayFramePayload(const QuicGoAwayFrame& frame, + QuicDataWriter* writer) { + uint32 error_code = static_cast<uint32>(frame.error_code); + if (!writer->WriteUInt32(error_code)) { + return false; + } + uint32 stream_id = static_cast<uint32>(frame.last_good_stream_id); + if (!writer->WriteUInt32(stream_id)) { + return false; + } + if (!writer->WriteStringPiece16(frame.reason_phrase)) { + return false; + } + return true; +} + bool QuicFramer::RaiseError(QuicErrorCode error) { DLOG(INFO) << detailed_error_; set_error(error); diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h index 297ca05..478f7b3 100644 --- a/net/quic/quic_framer.h +++ b/net/quic/quic_framer.h @@ -74,6 +74,9 @@ class NET_EXPORT_PRIVATE QuicFramerVisitorInterface { virtual void OnConnectionCloseFrame( const QuicConnectionCloseFrame& frame) = 0; + // Called when a GoAwayFrame has been parsed. + virtual void OnGoAwayFrame(const QuicGoAwayFrame& frame) = 0; + // Called when FEC data has been parsed. virtual void OnFecData(const QuicFecData& fec) = 0; @@ -91,6 +94,21 @@ class NET_EXPORT_PRIVATE QuicFecBuilderInterface { base::StringPiece payload) = 0; }; +// This class calculates the received entropy of the ack packet being +// framed, should it get truncated. +class NET_EXPORT_PRIVATE QuicReceivedEntropyHashCalculatorInterface { + public: + virtual ~QuicReceivedEntropyHashCalculatorInterface() {} + + // When an ack frame gets truncated while being framed the received + // entropy of the ack frame needs to be calculated since the some of the + // missing packets are not added and the largest observed might be lowered. + // This should return the received entropy hash of the packets received up to + // and including |sequence_number|. + virtual QuicPacketEntropyHash ReceivedEntropyHash( + QuicPacketSequenceNumber sequence_number) const = 0; +}; + // Class for parsing and constructing QUIC packets. It has a // QuicFramerVisitorInterface that is called when packets are parsed. // It also has a QuicFecBuilder that is called when packets are constructed @@ -106,8 +124,8 @@ class NET_EXPORT_PRIVATE QuicFramer { // Frame was truncated. last_written in this case is the iterator for the // last missing packet which fit in the outgoing ack. static QuicPacketSequenceNumber CalculateLargestObserved( - const SequenceSet& missing_packets, - SequenceSet::const_iterator last_written); + const SequenceNumberSet& missing_packets, + SequenceNumberSet::const_iterator last_written); // Set callbacks to be called from the framer. A visitor must be set, or // else the framer will likely crash. It is acceptable for the visitor @@ -124,6 +142,15 @@ class NET_EXPORT_PRIVATE QuicFramer { fec_builder_ = builder; } + // Set entropy calculator to be called from the framer when it needs the + // entropy of a truncated ack frame. An entropy calculator must be set or else + // the framer will likely crash. If this is called multiple times, only the + // last visitor will be used. + void set_entropy_calculator( + QuicReceivedEntropyHashCalculatorInterface* entropy_calculator) { + entropy_calculator_ = entropy_calculator; + } + QuicErrorCode error() const { return error_; } @@ -139,7 +166,7 @@ class NET_EXPORT_PRIVATE QuicFramer { // for parsing. // Return true if the packet was processed succesfully. |payload| must be // the complete DECRYPTED payload of the revived packet. - bool ProcessRevivedPacket(const QuicPacketHeader& header, + bool ProcessRevivedPacket(QuicPacketHeader* header, base::StringPiece payload); // Returns the number of bytes added to the packet for the specified frame, @@ -148,22 +175,24 @@ class NET_EXPORT_PRIVATE QuicFramer { size_t GetSerializedFrameLength( const QuicFrame& frame, size_t free_bytes, bool first_frame); - // Returns a new QuicPacket, owned by the caller, populated with the fields - // in |header| and |frames|, or NULL if the packet could not be created. + // Returns a SerializedPacket whose |packet| member is owned by the caller, + // and is populated with the fields in |header| and |frames|, or is NULL if + // the packet could not be created. // TODO(ianswett): Used for testing only. - QuicPacket* ConstructFrameDataPacket(const QuicPacketHeader& header, - const QuicFrames& frames); - - // Returns a new QuicPacket from the first |num_frames| frames, owned by the - // caller or NULL if the packet could not be created. The packet must be of - // size |packet_size|. - QuicPacket* ConstructFrameDataPacket(const QuicPacketHeader& header, - const QuicFrames& frames, - size_t packet_size); - - // Returns a new QuicPacket, owned by the caller, populated with the fields - // in |header| and |fec|, or NULL if the packet could not be created. - QuicPacket* ConstructFecPacket(const QuicPacketHeader& header, + SerializedPacket ConstructFrameDataPacket(const QuicPacketHeader& header, + const QuicFrames& frames); + + // Returns a SerializedPacket whose |packet| member is owned by the caller, + // is created from the first |num_frames| frames, or is NULL if the packet + // could not be created. The packet must be of size |packet_size|. + SerializedPacket ConstructFrameDataPacket(const QuicPacketHeader& header, + const QuicFrames& frames, + size_t packet_size); + + // Returns a SerializedPacket whose |packet| member is owned by the caller, + // and is populated with the fields in |header| and |fec|, or is NULL if the + // packet could not be created. + SerializedPacket ConstructFecPacket(const QuicPacketHeader& header, const QuicFecData& fec); // Returns a new public reset packet, owned by the caller. @@ -171,7 +200,8 @@ class NET_EXPORT_PRIVATE QuicFramer { const QuicPublicResetPacket& packet); // Returns a new encrypted packet, owned by the caller. - QuicEncryptedPacket* EncryptPacket(const QuicPacket& packet); + QuicEncryptedPacket* EncryptPacket(QuicPacketSequenceNumber sequence_number, + const QuicPacket& packet); // Returns the maximum length of plaintext that can be encrypted // to ciphertext no larger than |ciphertext_size|. @@ -187,6 +217,9 @@ class NET_EXPORT_PRIVATE QuicFramer { private: friend class test::QuicFramerPeer; + QuicPacketEntropyHash GetPacketEntropyHash( + const QuicPacketHeader& header) const; + bool ProcessDataPacket(const QuicPacketPublicHeader& public_header, const QuicEncryptedPacket& packet); @@ -210,8 +243,10 @@ class NET_EXPORT_PRIVATE QuicFramer { QuicCongestionFeedbackFrame* congestion_feedback); bool ProcessRstStreamFrame(); bool ProcessConnectionCloseFrame(); + bool ProcessGoAwayFrame(); - bool DecryptPayload(const QuicEncryptedPacket& packet); + bool DecryptPayload(QuicPacketSequenceNumber packet_sequence_number, + const QuicEncryptedPacket& packet); // Returns the full packet sequence number from the truncated // wire format version and the last seen packet sequence number. @@ -237,6 +272,8 @@ class NET_EXPORT_PRIVATE QuicFramer { bool AppendConnectionCloseFramePayload( const QuicConnectionCloseFrame& frame, QuicDataWriter* builder); + bool AppendGoAwayFramePayload(const QuicGoAwayFrame& frame, + QuicDataWriter* writer); bool RaiseError(QuicErrorCode error); void set_error(QuicErrorCode error) { @@ -251,6 +288,7 @@ class NET_EXPORT_PRIVATE QuicFramer { scoped_ptr<QuicDataReader> reader_; QuicFramerVisitorInterface* visitor_; QuicFecBuilderInterface* fec_builder_; + QuicReceivedEntropyHashCalculatorInterface* entropy_calculator_; QuicErrorCode error_; QuicPacketSequenceNumber last_sequence_number_; // Buffer containing decrypted payload data during parsing. diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index d64df49..da1a665 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc @@ -49,18 +49,33 @@ class QuicFramerPeer { class TestEncrypter : public QuicEncrypter { public: virtual ~TestEncrypter() {} - virtual QuicData* Encrypt(StringPiece associated_data, - StringPiece plaintext) OVERRIDE { + virtual bool SetKey(StringPiece key) OVERRIDE { + return true; + } + virtual bool SetNoncePrefix(StringPiece nonce_prefix) OVERRIDE { + return true; + } + virtual QuicData* Encrypt(QuicPacketSequenceNumber sequence_number, + StringPiece associated_data, + StringPiece plaintext) OVERRIDE{ + sequence_number_ = sequence_number; associated_data_ = associated_data.as_string(); plaintext_ = plaintext.as_string(); return new QuicData(plaintext.data(), plaintext.length()); } - virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) OVERRIDE { + virtual size_t GetKeySize() const OVERRIDE { + return 0; + } + virtual size_t GetNoncePrefixSize() const OVERRIDE{ + return 0; + } + virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) const OVERRIDE { return ciphertext_size; } - virtual size_t GetCiphertextSize(size_t plaintext_size) OVERRIDE { + virtual size_t GetCiphertextSize(size_t plaintext_size) const OVERRIDE { return plaintext_size; } + QuicPacketSequenceNumber sequence_number_; string associated_data_; string plaintext_; }; @@ -68,12 +83,21 @@ class TestEncrypter : public QuicEncrypter { class TestDecrypter : public QuicDecrypter { public: virtual ~TestDecrypter() {} - virtual QuicData* Decrypt(StringPiece associated_data, - StringPiece ciphertext) OVERRIDE { + virtual bool SetKey(StringPiece key) OVERRIDE { + return true; + } + virtual bool SetNoncePrefix(StringPiece nonce_prefix) OVERRIDE { + return true; + } + virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number, + StringPiece associated_data, + StringPiece ciphertext) OVERRIDE{ + sequence_number_ = sequence_number; associated_data_ = associated_data.as_string(); ciphertext_ = ciphertext.as_string(); return new QuicData(ciphertext.data(), ciphertext.length()); } + QuicPacketSequenceNumber sequence_number_; string associated_data_; string ciphertext_; }; @@ -159,6 +183,10 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface { connection_close_frame_ = frame; } + virtual void OnGoAwayFrame(const QuicGoAwayFrame& frame) { + goaway_frame_ = frame; + } + // Counters from the visitor_ callbacks. int error_count_; int packet_count_; @@ -177,6 +205,7 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface { string fec_protected_payload_; QuicRstStreamFrame rst_stream_frame_; QuicConnectionCloseFrame connection_close_frame_; + QuicGoAwayFrame goaway_frame_; }; class QuicFramerTest : public ::testing::Test { @@ -186,9 +215,17 @@ class QuicFramerTest : public ::testing::Test { decrypter_(new test::TestDecrypter()), framer_(decrypter_, encrypter_) { framer_.set_visitor(&visitor_); + framer_.set_entropy_calculator(&entropy_calculator_); } - bool CheckEncryption(StringPiece packet) { + bool CheckEncryption(QuicPacketSequenceNumber sequence_number, + StringPiece packet) { + if (sequence_number != encrypter_->sequence_number_) { + LOG(ERROR) << "Encrypted incorrect packet sequence number. expected " + << sequence_number << " actual: " + << encrypter_->sequence_number_; + return false; + } StringPiece associated_data( packet.substr(kStartOfHashData, kStartOfEncryptedData - kStartOfHashData)); @@ -209,6 +246,13 @@ class QuicFramerTest : public ::testing::Test { } bool CheckDecryption(StringPiece packet) { + if (visitor_.header_->packet_sequence_number != + decrypter_->sequence_number_) { + LOG(ERROR) << "Decrypted incorrect packet sequence number. expected " + << visitor_.header_->packet_sequence_number << " actual: " + << decrypter_->sequence_number_; + return false; + } StringPiece associated_data( packet.substr(kStartOfHashData, kStartOfEncryptedData - kStartOfHashData)); @@ -218,10 +262,10 @@ class QuicFramerTest : public ::testing::Test { << decrypter_->associated_data_; return false; } - StringPiece plaintext(packet.substr(kStartOfEncryptedData)); - if (plaintext != decrypter_->ciphertext_) { + StringPiece ciphertext(packet.substr(kStartOfEncryptedData)); + if (ciphertext != decrypter_->ciphertext_) { LOG(ERROR) << "Decrypted incorrect chipertext data. expected " - << plaintext << " actual: " + << ciphertext << " actual: " << decrypter_->ciphertext_; return false; } @@ -266,6 +310,7 @@ class QuicFramerTest : public ::testing::Test { test::TestDecrypter* decrypter_; QuicFramer framer_; test::TestQuicVisitor visitor_; + test::TestEntropyCalculator entropy_calculator_; }; TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearEpochStart) { @@ -347,7 +392,7 @@ TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearNextEpoch) { } TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearNextMax) { - const uint64 max_number = std::numeric_limits<uint64>::max(); + const uint64 max_number = numeric_limits<uint64>::max(); const uint64 max_epoch = max_number & ~kMask; // Cases where the last number was close to the end of the range @@ -425,8 +470,12 @@ TEST_F(QuicFramerTest, PacketHeader) { ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210), visitor_.header_->public_header.guid); - EXPECT_EQ(0x00, visitor_.header_->public_header.flags); - EXPECT_EQ(0x00, visitor_.header_->private_flags); + EXPECT_FALSE(visitor_.header_->public_header.reset_flag); + EXPECT_FALSE(visitor_.header_->public_header.version_flag); + EXPECT_FALSE(visitor_.header_->fec_flag); + EXPECT_FALSE(visitor_.header_->entropy_flag); + EXPECT_FALSE(visitor_.header_->fec_entropy_flag); + EXPECT_EQ(0, visitor_.header_->entropy_hash); EXPECT_EQ(GG_UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number); EXPECT_EQ(0x00u, visitor_.header_->fec_group); @@ -499,7 +548,7 @@ TEST_F(QuicFramerTest, InvalidPrivateFlag) { 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, // private flags - 0x07, + 0x08, // first fec protected packet offset 0xFF, @@ -558,9 +607,9 @@ TEST_F(QuicFramerTest, PaddingFrame) { QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); ASSERT_EQ(0u, visitor_.stream_frames_.size()); EXPECT_EQ(0u, visitor_.ack_frames_.size()); @@ -611,9 +660,9 @@ TEST_F(QuicFramerTest, StreamFrame) { QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); ASSERT_EQ(1u, visitor_.stream_frames_.size()); EXPECT_EQ(0u, visitor_.ack_frames_.size()); @@ -680,9 +729,9 @@ TEST_F(QuicFramerTest, RejectPacket) { QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); ASSERT_EQ(0u, visitor_.stream_frames_.size()); EXPECT_EQ(0u, visitor_.ack_frames_.size()); @@ -709,13 +758,16 @@ TEST_F(QuicFramerTest, RevivedStreamFrame) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = true; + header.entropy_flag = true; + header.fec_entropy_flag = false; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); header.fec_group = 0; // Do not encrypt the payload because the revived payload is post-encryption. - EXPECT_TRUE(framer_.ProcessRevivedPacket(header, + EXPECT_TRUE(framer_.ProcessRevivedPacket(&header, StringPiece(AsChars(payload), arraysize(payload)))); @@ -724,8 +776,13 @@ TEST_F(QuicFramerTest, RevivedStreamFrame) { ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210), visitor_.header_->public_header.guid); - EXPECT_EQ(0x00, visitor_.header_->public_header.flags); - EXPECT_EQ(0x00, visitor_.header_->private_flags); + EXPECT_FALSE(visitor_.header_->public_header.reset_flag); + EXPECT_FALSE(visitor_.header_->public_header.version_flag); + EXPECT_TRUE(visitor_.header_->fec_flag); + EXPECT_TRUE(visitor_.header_->entropy_flag); + EXPECT_FALSE(visitor_.header_->fec_entropy_flag); + EXPECT_EQ(1 << (header.packet_sequence_number % 8), + visitor_.header_->entropy_hash); EXPECT_EQ(GG_UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number); EXPECT_EQ(0x00u, visitor_.header_->fec_group); @@ -774,9 +831,9 @@ TEST_F(QuicFramerTest, StreamFrameInFecGroup) { QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(GG_UINT64_C(0x341256789ABA), visitor_.header_->fec_group); EXPECT_EQ(string(AsChars(packet) + kStartOfFecProtectedData, @@ -809,9 +866,13 @@ TEST_F(QuicFramerTest, AckFrame) { // frame type (ack frame) 0x02, + // entropy hash of sent packets till least awaiting - 1. + 0xAB, // least packet sequence number awaiting an ack 0xA0, 0x9A, 0x78, 0x56, 0x34, 0x12, + // entropy hash of all received packets. + 0xBA, // largest observed packet sequence number 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -825,34 +886,41 @@ TEST_F(QuicFramerTest, AckFrame) { QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(0u, visitor_.stream_frames_.size()); ASSERT_EQ(1u, visitor_.ack_frames_.size()); const QuicAckFrame& frame = *visitor_.ack_frames_[0]; + EXPECT_EQ(0xAB, frame.sent_info.entropy_hash); + EXPECT_EQ(0xBA, frame.received_info.entropy_hash); EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.received_info.largest_observed); ASSERT_EQ(1u, frame.received_info.missing_packets.size()); - SequenceSet::const_iterator missing_iter = + SequenceNumberSet::const_iterator missing_iter = frame.received_info.missing_packets.begin(); EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter); EXPECT_EQ(GG_UINT64_C(0x0123456789AA0), frame.sent_info.least_unacked); // Now test framing boundaries - for (size_t i = 0; i < 20; ++i) { + for (size_t i = 0; i < 22; ++i) { string expected_error; if (i < 1) { expected_error = "Unable to read frame type."; - } else if (i < 7) { + } else if (i < 2) { + expected_error = "Unable to read entropy hash for sent packets."; + } else if (i < 8) { expected_error = "Unable to read least unacked."; - } else if (i < 13) { + } else if (i < 9) { + expected_error = "Unable to read entropy hash for received packets."; + } else if (i < 15) { expected_error = "Unable to read largest observed."; - } else if (i < 14) { + } else if (i < 16) { expected_error = "Unable to read num missing packets."; - } else if (i < 20) { + } else { expected_error = "Unable to read sequence number in missing packets."; - } CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, + } + CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, QUIC_INVALID_FRAME_DATA); } } @@ -885,9 +953,9 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameTCP) { QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(0u, visitor_.stream_frames_.size()); ASSERT_EQ(1u, visitor_.congestion_feedback_frames_.size()); @@ -957,9 +1025,9 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) { QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(0u, visitor_.stream_frames_.size()); ASSERT_EQ(1u, visitor_.congestion_feedback_frames_.size()); @@ -1038,9 +1106,9 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameFixRate) { QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(0u, visitor_.stream_frames_.size()); ASSERT_EQ(1u, visitor_.congestion_feedback_frames_.size()); @@ -1112,9 +1180,6 @@ TEST_F(QuicFramerTest, RstStreamFrame) { 0x04, // stream id 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0xBA, // error code 0x08, 0x07, 0x06, 0x05, @@ -1130,26 +1195,22 @@ TEST_F(QuicFramerTest, RstStreamFrame) { QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(GG_UINT64_C(0x01020304), visitor_.rst_stream_frame_.stream_id); EXPECT_EQ(0x05060708, visitor_.rst_stream_frame_.error_code); - EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654), - visitor_.rst_stream_frame_.offset); EXPECT_EQ("because I can", visitor_.rst_stream_frame_.error_details); // Now test framing boundaries - for (size_t i = 2; i < 32; ++i) { + for (size_t i = 2; i < 24; ++i) { string expected_error; if (i < 5) { expected_error = "Unable to read stream_id."; - } else if (i < 13) { - expected_error = "Unable to read offset in rst frame."; - } else if (i < 17) { + } else if (i < 9) { expected_error = "Unable to read rst stream error code."; - } else if (i < 32) { + } else if (i < 24) { expected_error = "Unable to read rst stream error details."; } CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, @@ -1186,9 +1247,13 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) { 'n', // Ack frame. + // entropy hash of sent packets till least awaiting - 1. + 0xBF, // least packet sequence number awaiting an ack 0xA0, 0x9A, 0x78, 0x56, 0x34, 0x12, + // entropy hash of all received packets. + 0xEB, // largest observed packet sequence number 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1202,9 +1267,9 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) { QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(0u, visitor_.stream_frames_.size()); @@ -1213,12 +1278,14 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) { ASSERT_EQ(1u, visitor_.ack_frames_.size()); const QuicAckFrame& frame = *visitor_.ack_frames_[0]; + EXPECT_EQ(0xBF, frame.sent_info.entropy_hash); + EXPECT_EQ(GG_UINT64_C(0x0123456789AA0), frame.sent_info.least_unacked); + EXPECT_EQ(0xEB, frame.received_info.entropy_hash); EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.received_info.largest_observed); ASSERT_EQ(1u, frame.received_info.missing_packets.size()); - SequenceSet::const_iterator missing_iter = + SequenceNumberSet::const_iterator missing_iter = frame.received_info.missing_packets.begin(); EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter); - EXPECT_EQ(GG_UINT64_C(0x0123456789AA0), frame.sent_info.least_unacked); // Now test framing boundaries for (size_t i = 2; i < 20; ++i) { @@ -1233,6 +1300,63 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) { } } +TEST_F(QuicFramerTest, GoAwayFrame) { + unsigned char packet[] = { + // guid + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // public flags + 0x00, + // packet sequence number + 0xBC, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags + 0x00, + // first fec protected packet offset + 0xFF, + + // frame type (go away frame) + 0x06, + // error code + 0x08, 0x07, 0x06, 0x05, + // stream id + 0x04, 0x03, 0x02, 0x01, + // error details length + 0x0d, 0x00, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n', + }; + + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + + EXPECT_EQ(GG_UINT64_C(0x01020304), + visitor_.goaway_frame_.last_good_stream_id); + EXPECT_EQ(0x05060708, visitor_.goaway_frame_.error_code); + EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase); + + // Now test framing boundaries + for (size_t i = 2; i < 24; ++i) { + string expected_error; + if (i < 5) { + expected_error = "Unable to read go away error code."; + } else if (i < 9) { + expected_error = "Unable to read last good stream id."; + } else if (i < 24) { + expected_error = "Unable to read goaway reason."; + } + CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, + QUIC_INVALID_GOAWAY_DATA); + } +} + TEST_F(QuicFramerTest, PublicResetPacket) { unsigned char packet[] = { // guid @@ -1250,12 +1374,12 @@ TEST_F(QuicFramerTest, PublicResetPacket) { QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.public_reset_packet_.get()); EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210), visitor_.public_reset_packet_->public_header.guid); - EXPECT_EQ(PACKET_PUBLIC_FLAGS_RST, - visitor_.public_reset_packet_->public_header.flags); + EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag); + EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag); EXPECT_EQ(GG_UINT64_C(0xABCDEF0123456789), visitor_.public_reset_packet_->nonce_proof); EXPECT_EQ(GG_UINT64_C(0x123456789ABC), @@ -1302,9 +1426,9 @@ TEST_F(QuicFramerTest, FecPacket) { QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(0u, visitor_.stream_frames_.size()); EXPECT_EQ(0u, visitor_.ack_frames_.size()); @@ -1317,8 +1441,11 @@ TEST_F(QuicFramerTest, FecPacket) { TEST_F(QuicFramerTest, ConstructPaddingFramePacket) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = false; + header.fec_entropy_flag = false; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); header.fec_group = 0; @@ -1349,7 +1476,8 @@ TEST_F(QuicFramerTest, ConstructPaddingFramePacket) { memset(packet + kPacketHeaderSize + 1, 0x00, kMaxPacketSize - kPacketHeaderSize - 1); - scoped_ptr<QuicPacket> data(framer_.ConstructFrameDataPacket(header, frames)); + scoped_ptr<QuicPacket> data( + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(data != NULL); test::CompareCharArraysWithHexError("constructed packet", @@ -1360,8 +1488,11 @@ TEST_F(QuicFramerTest, ConstructPaddingFramePacket) { TEST_F(QuicFramerTest, ConstructStreamFramePacket) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = true; + header.fec_entropy_flag = false; header.packet_sequence_number = GG_UINT64_C(0x77123456789ABC); header.fec_group = 0; @@ -1383,8 +1514,8 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacket) { // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // private flags - 0x00, + // private flags (entropy) + 0x02, // first fec protected packet offset 0xFF, @@ -1405,7 +1536,8 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacket) { 'r', 'l', 'd', '!', }; - scoped_ptr<QuicPacket> data(framer_.ConstructFrameDataPacket(header, frames)); + scoped_ptr<QuicPacket> data( + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(data != NULL); test::CompareCharArraysWithHexError("constructed packet", @@ -1416,15 +1548,20 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacket) { TEST_F(QuicFramerTest, ConstructAckFramePacket) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = true; + header.fec_entropy_flag = true; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); header.fec_group = 0; QuicAckFrame ack_frame; + ack_frame.received_info.entropy_hash = 0x43; ack_frame.received_info.largest_observed = GG_UINT64_C(0x770123456789ABF); ack_frame.received_info.missing_packets.insert( GG_UINT64_C(0x770123456789ABE)); + ack_frame.sent_info.entropy_hash = 0x14; ack_frame.sent_info.least_unacked = GG_UINT64_C(0x770123456789AA0); QuicFrames frames; @@ -1439,16 +1576,20 @@ TEST_F(QuicFramerTest, ConstructAckFramePacket) { // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // private flags - 0x00, + // private flags (entropy & fec_entropy -- not relevant) + 0x06, // first fec protected packet offset 0xFF, // frame type (ack frame) 0x02, + // entropy hash of sent packets till least awaiting - 1. + 0x14, // least packet sequence number awaiting an ack 0xA0, 0x9A, 0x78, 0x56, 0x34, 0x12, + // entropy hash of all received packets. + 0x43, // largest observed packet sequence number 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1459,7 +1600,8 @@ TEST_F(QuicFramerTest, ConstructAckFramePacket) { 0x34, 0x12, }; - scoped_ptr<QuicPacket> data(framer_.ConstructFrameDataPacket(header, frames)); + scoped_ptr<QuicPacket> data( + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(data != NULL); test::CompareCharArraysWithHexError("constructed packet", @@ -1470,8 +1612,11 @@ TEST_F(QuicFramerTest, ConstructAckFramePacket) { TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = false; + header.fec_entropy_flag = true; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); header.fec_group = 0; @@ -1493,7 +1638,7 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) { 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, // private flags - 0x00, + 0x04, // (fec_entropy_flag) // first fec protected packet offset 0xFF, @@ -1507,7 +1652,8 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) { 0x03, 0x04, }; - scoped_ptr<QuicPacket> data(framer_.ConstructFrameDataPacket(header, frames)); + scoped_ptr<QuicPacket> data( + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(data != NULL); test::CompareCharArraysWithHexError("constructed packet", @@ -1518,8 +1664,11 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) { TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = false; + header.fec_entropy_flag = false; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); header.fec_group = 0; @@ -1576,7 +1725,8 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) { 0x02, 0x00, 0x00, 0x00, }; - scoped_ptr<QuicPacket> data(framer_.ConstructFrameDataPacket(header, frames)); + scoped_ptr<QuicPacket> data( + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(data != NULL); test::CompareCharArraysWithHexError("constructed packet", @@ -1587,8 +1737,11 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) { TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = false; + header.fec_entropy_flag = false; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); header.fec_group = 0; @@ -1622,7 +1775,8 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) { 0x01, 0x02, 0x03, 0x04, }; - scoped_ptr<QuicPacket> data(framer_.ConstructFrameDataPacket(header, frames)); + scoped_ptr<QuicPacket> data( + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(data != NULL); test::CompareCharArraysWithHexError("constructed packet", @@ -1633,8 +1787,11 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) { TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInvalidFeedback) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = false; + header.fec_entropy_flag = false; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); header.fec_group = 0; @@ -1645,22 +1802,25 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInvalidFeedback) { QuicFrames frames; frames.push_back(QuicFrame(&congestion_feedback_frame)); - scoped_ptr<QuicPacket> data(framer_.ConstructFrameDataPacket(header, frames)); + scoped_ptr<QuicPacket> data( + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(data == NULL); } TEST_F(QuicFramerTest, ConstructRstFramePacket) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = false; + header.fec_entropy_flag = false; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); header.fec_group = 0; QuicRstStreamFrame rst_frame; rst_frame.stream_id = 0x01020304; rst_frame.error_code = static_cast<QuicErrorCode>(0x05060708); - rst_frame.offset = GG_UINT64_C(0xBA98FEDC32107654); rst_frame.error_details = "because I can"; unsigned char packet[] = { @@ -1681,9 +1841,6 @@ TEST_F(QuicFramerTest, ConstructRstFramePacket) { 0x04, // stream id 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0xBA, // error code 0x08, 0x07, 0x06, 0x05, // error details length @@ -1698,7 +1855,8 @@ TEST_F(QuicFramerTest, ConstructRstFramePacket) { QuicFrames frames; frames.push_back(QuicFrame(&rst_frame)); - scoped_ptr<QuicPacket> data(framer_.ConstructFrameDataPacket(header, frames)); + scoped_ptr<QuicPacket> data( + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(data != NULL); test::CompareCharArraysWithHexError("constructed packet", @@ -1709,8 +1867,11 @@ TEST_F(QuicFramerTest, ConstructRstFramePacket) { TEST_F(QuicFramerTest, ConstructCloseFramePacket) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = true; + header.fec_entropy_flag = false; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); header.fec_group = 0; @@ -1719,8 +1880,10 @@ TEST_F(QuicFramerTest, ConstructCloseFramePacket) { close_frame.error_details = "because I can"; QuicAckFrame* ack_frame = &close_frame.ack_frame; + ack_frame->received_info.entropy_hash = 0x43; ack_frame->received_info.largest_observed = GG_UINT64_C(0x0123456789ABF); ack_frame->received_info.missing_packets.insert(GG_UINT64_C(0x0123456789ABE)); + ack_frame->sent_info.entropy_hash = 0xE0; ack_frame->sent_info.least_unacked = GG_UINT64_C(0x0123456789AA0); QuicFrames frames; @@ -1736,7 +1899,7 @@ TEST_F(QuicFramerTest, ConstructCloseFramePacket) { 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, // private flags - 0x00, + 0x02, // first fec protected packet offset 0xFF, @@ -1753,9 +1916,13 @@ TEST_F(QuicFramerTest, ConstructCloseFramePacket) { 'n', // Ack frame. + // entropy hash of sent packets till least awaiting - 1. + 0xE0, // least packet sequence number awaiting an ack 0xA0, 0x9A, 0x78, 0x56, 0x34, 0x12, + // entropy hash of all received packets. + 0x43, // largest observed packet sequence number 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -1766,7 +1933,65 @@ TEST_F(QuicFramerTest, ConstructCloseFramePacket) { 0x34, 0x12, }; - scoped_ptr<QuicPacket> data(framer_.ConstructFrameDataPacket(header, frames)); + scoped_ptr<QuicPacket> data( + framer_.ConstructFrameDataPacket(header, frames).packet); + ASSERT_TRUE(data != NULL); + + test::CompareCharArraysWithHexError("constructed packet", + data->data(), data->length(), + AsChars(packet), arraysize(packet)); +} + +TEST_F(QuicFramerTest, ConstructGoAwayPacket) { + QuicPacketHeader header; + header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = true; + header.fec_entropy_flag = false; + header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); + header.fec_group = 0; + + QuicGoAwayFrame goaway_frame; + goaway_frame.error_code = static_cast<QuicErrorCode>(0x05060708); + goaway_frame.last_good_stream_id = 0x01020304; + goaway_frame.reason_phrase = "because I can"; + + QuicFrames frames; + frames.push_back(QuicFrame(&goaway_frame)); + + unsigned char packet[] = { + // guid + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // public flags + 0x00, + // packet sequence number + 0xBC, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags + 0x02, + // first fec protected packet offset + 0xFF, + + // frame type (go away frame) + 0x06, + // error code + 0x08, 0x07, 0x06, 0x05, + // stream id + 0x04, 0x03, 0x02, 0x01, + // error details length + 0x0d, 0x00, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n', + }; + + scoped_ptr<QuicPacket> data( + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(data != NULL); test::CompareCharArraysWithHexError("constructed packet", @@ -1777,7 +2002,8 @@ TEST_F(QuicFramerTest, ConstructCloseFramePacket) { TEST_F(QuicFramerTest, ConstructPublicResetPacket) { QuicPublicResetPacket reset_packet; reset_packet.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - reset_packet.public_header.flags = PACKET_PUBLIC_FLAGS_RST; + reset_packet.public_header.reset_flag = true; + reset_packet.public_header.version_flag = false; reset_packet.rejected_sequence_number = GG_UINT64_C(0x123456789ABC); reset_packet.nonce_proof = GG_UINT64_C(0xABCDEF0123456789); @@ -1807,8 +2033,11 @@ TEST_F(QuicFramerTest, ConstructPublicResetPacket) { TEST_F(QuicFramerTest, ConstructFecPacket) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header.private_flags = PACKET_PRIVATE_FLAGS_FEC; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = true; + header.entropy_flag = true; + header.fec_entropy_flag = false; header.packet_sequence_number = (GG_UINT64_C(0x123456789ABC)); header.fec_group = GG_UINT64_C(0x123456789ABB);; @@ -1826,7 +2055,7 @@ TEST_F(QuicFramerTest, ConstructFecPacket) { 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, // private flags - 0x01, + 0x03, // first fec protected packet offset 0x01, @@ -1837,7 +2066,8 @@ TEST_F(QuicFramerTest, ConstructFecPacket) { 'm', 'n', 'o', 'p', }; - scoped_ptr<QuicPacket> data(framer_.ConstructFecPacket(header, fec_data)); + scoped_ptr<QuicPacket> data( + framer_.ConstructFecPacket(header, fec_data).packet); ASSERT_TRUE(data != NULL); test::CompareCharArraysWithHexError("constructed packet", @@ -1846,6 +2076,7 @@ TEST_F(QuicFramerTest, ConstructFecPacket) { } TEST_F(QuicFramerTest, EncryptPacket) { + QuicPacketSequenceNumber sequence_number = GG_UINT64_C(0x123456789ABC); unsigned char packet[] = { // guid 0x10, 0x32, 0x54, 0x76, @@ -1869,17 +2100,19 @@ TEST_F(QuicFramerTest, EncryptPacket) { scoped_ptr<QuicPacket> raw( QuicPacket::NewDataPacket(AsChars(packet), arraysize(packet), false)); - scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*raw)); + scoped_ptr<QuicEncryptedPacket> encrypted( + framer_.EncryptPacket(sequence_number, *raw)); ASSERT_TRUE(encrypted.get() != NULL); - EXPECT_TRUE(CheckEncryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(CheckEncryption(sequence_number, + StringPiece(AsChars(packet), arraysize(packet)))); } // TODO(rch): re-enable after https://codereview.chromium.org/11820005/ // lands. Currently this is causing valgrind problems, but it should be // fixed in the followup CL. TEST_F(QuicFramerTest, DISABLED_CalculateLargestReceived) { - SequenceSet missing; + SequenceNumberSet missing; missing.insert(1); missing.insert(5); missing.insert(7); @@ -1900,8 +2133,11 @@ TEST_F(QuicFramerTest, DISABLED_CalculateLargestReceived) { TEST_F(QuicFramerTest, DISABLED_Truncation) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = false; + header.fec_entropy_flag = false; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); header.fec_group = 0; @@ -1923,11 +2159,11 @@ TEST_F(QuicFramerTest, DISABLED_Truncation) { frames.push_back(frame); scoped_ptr<QuicPacket> raw_ack_packet( - framer_.ConstructFrameDataPacket(header, frames)); + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(raw_ack_packet != NULL); scoped_ptr<QuicEncryptedPacket> ack_packet( - framer_.EncryptPacket(*raw_ack_packet)); + framer_.EncryptPacket(header.packet_sequence_number, *raw_ack_packet)); // Create a packet with just connection close. frames.clear(); @@ -1936,11 +2172,11 @@ TEST_F(QuicFramerTest, DISABLED_Truncation) { frames.push_back(frame); scoped_ptr<QuicPacket> raw_close_packet( - framer_.ConstructFrameDataPacket(header, frames)); + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(raw_close_packet != NULL); scoped_ptr<QuicEncryptedPacket> close_packet( - framer_.EncryptPacket(*raw_close_packet)); + framer_.EncryptPacket(header.packet_sequence_number, *raw_close_packet)); // Now make sure we can turn our ack packet back into an ack frame ASSERT_TRUE(framer_.ProcessPacket(*ack_packet)); @@ -1952,8 +2188,11 @@ TEST_F(QuicFramerTest, DISABLED_Truncation) { TEST_F(QuicFramerTest, CleanTruncation) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = true; + header.fec_entropy_flag = false; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); header.fec_group = 0; @@ -1975,11 +2214,11 @@ TEST_F(QuicFramerTest, CleanTruncation) { frames.push_back(frame); scoped_ptr<QuicPacket> raw_ack_packet( - framer_.ConstructFrameDataPacket(header, frames)); + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(raw_ack_packet != NULL); scoped_ptr<QuicEncryptedPacket> ack_packet( - framer_.EncryptPacket(*raw_ack_packet)); + framer_.EncryptPacket(header.packet_sequence_number, *raw_ack_packet)); // Create a packet with just connection close. frames.clear(); @@ -1988,11 +2227,11 @@ TEST_F(QuicFramerTest, CleanTruncation) { frames.push_back(frame); scoped_ptr<QuicPacket> raw_close_packet( - framer_.ConstructFrameDataPacket(header, frames)); + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(raw_close_packet != NULL); scoped_ptr<QuicEncryptedPacket> close_packet( - framer_.EncryptPacket(*raw_close_packet)); + framer_.EncryptPacket(header.packet_sequence_number, *raw_close_packet)); // Now make sure we can turn our ack packet back into an ack frame ASSERT_TRUE(framer_.ProcessPacket(*ack_packet)); @@ -2009,7 +2248,7 @@ TEST_F(QuicFramerTest, CleanTruncation) { size_t original_raw_length = raw_ack_packet->length(); raw_ack_packet.reset( - framer_.ConstructFrameDataPacket(header, frames)); + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(raw_ack_packet != NULL); EXPECT_EQ(original_raw_length, raw_ack_packet->length()); @@ -2020,10 +2259,93 @@ TEST_F(QuicFramerTest, CleanTruncation) { original_raw_length = raw_close_packet->length(); raw_close_packet.reset( - framer_.ConstructFrameDataPacket(header, frames)); + framer_.ConstructFrameDataPacket(header, frames).packet); ASSERT_TRUE(raw_ack_packet != NULL); EXPECT_EQ(original_raw_length, raw_close_packet->length()); } +TEST_F(QuicFramerTest, EntropyFlagTest) { + unsigned char packet[] = { + // guid + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // public flags + 0x00, + // packet sequence number + 0xBC, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // Entropy + 0x02, + // first fec protected packet offset + 0xFF, + + // frame type (stream frame) + 0x01, + // stream id + 0x04, 0x03, 0x02, 0x01, + // fin + 0x01, + // offset + 0x54, 0x76, 0x10, 0x32, + 0xDC, 0xFE, 0x98, 0xBA, + // data length + 0x0c, 0x00, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; + + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(visitor_.header_->entropy_flag); + EXPECT_EQ(1 << 4, visitor_.header_->entropy_hash); + EXPECT_FALSE(visitor_.header_->fec_flag); +}; + +TEST_F(QuicFramerTest, FecEntropyFlagTest) { + unsigned char packet[] = { + // guid + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // public flags + 0x00, + // packet sequence number + 0xBC, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // Flags: Entropy, FEC-Entropy, FEC + 0x07, + // first fec protected packet offset + 0xFF, + + // frame type (stream frame) + 0x01, + // stream id + 0x04, 0x03, 0x02, 0x01, + // fin + 0x01, + // offset + 0x54, 0x76, 0x10, 0x32, + 0xDC, 0xFE, 0x98, 0xBA, + // data length + 0x0c, 0x00, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; + + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(visitor_.header_->fec_flag); + EXPECT_TRUE(visitor_.header_->entropy_flag); + EXPECT_TRUE(visitor_.header_->fec_entropy_flag); + EXPECT_EQ(1 << 4, visitor_.header_->entropy_hash); +}; + } // namespace test } // namespace net diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index 4a5f333..a16f2f9 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc @@ -17,6 +17,7 @@ #include "net/quic/quic_connection.h" #include "net/quic/quic_connection_helper.h" #include "net/quic/test_tools/mock_clock.h" +#include "net/quic/test_tools/mock_random.h" #include "net/quic/test_tools/quic_connection_peer.h" #include "net/quic/test_tools/quic_test_utils.h" #include "net/quic/test_tools/test_task_runner.h" @@ -114,7 +115,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { read_buffer_(new IOBufferWithSize(4096)), guid_(2), framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)), - creator_(guid_, &framer_) { + creator_(guid_, &framer_, &random_) { IPAddressNumber ip; CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip)); peer_addr_ = IPEndPoint(ip, 443); @@ -165,7 +166,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { runner_ = new TestTaskRunner(&clock_); send_algorithm_ = new MockSendAlgorithm(); receive_algorithm_ = new TestReceiveAlgorithm(NULL); - EXPECT_CALL(*send_algorithm_, TimeUntilSend(_)). + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _)). WillRepeatedly(testing::Return(QuicTime::Delta::Zero())); helper_ = new QuicConnectionHelper(runner_.get(), &clock_, &random_generator_, socket); @@ -240,17 +241,19 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { InitializeHeader(sequence_number); QuicAckFrame ack(largest_received, least_unacked); + ack.sent_info.entropy_hash = 0; + ack.received_info.entropy_hash = 0; + return ConstructPacket(header_, QuicFrame(&ack)); } // Returns a newly created packet to send ack data. QuicEncryptedPacket* ConstructRstPacket( QuicPacketSequenceNumber sequence_number, - QuicStreamId stream_id, - QuicStreamOffset offset) { + QuicStreamId stream_id) { InitializeHeader(sequence_number); - QuicRstStreamFrame rst(stream_id, offset, QUIC_NO_ERROR); + QuicRstStreamFrame rst(stream_id, QUIC_NO_ERROR); return ConstructPacket(header_, QuicFrame(&rst)); } @@ -278,10 +281,13 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { private: void InitializeHeader(QuicPacketSequenceNumber sequence_number) { header_.public_header.guid = guid_; - header_.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header_.public_header.reset_flag = false; + header_.public_header.version_flag = false; header_.packet_sequence_number = sequence_number; header_.fec_group = 0; - header_.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header_.fec_entropy_flag = false; + header_.entropy_flag = false; + header_.fec_flag = false; } QuicEncryptedPacket* ConstructPacket(const QuicPacketHeader& header, @@ -289,14 +295,15 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { QuicFrames frames; frames.push_back(frame); scoped_ptr<QuicPacket> packet( - framer_.ConstructFrameDataPacket(header_, frames)); - return framer_.EncryptPacket(*packet); + framer_.ConstructFrameDataPacket(header_, frames).packet); + return framer_.EncryptPacket(header.packet_sequence_number, *packet); } const QuicGuid guid_; QuicFramer framer_; IPEndPoint self_addr_; IPEndPoint peer_addr_; + MockRandom random_; QuicPacketCreator creator_; QuicPacketHeader header_; scoped_ptr<StaticSocketDataProvider> socket_data_; @@ -468,7 +475,7 @@ TEST_P(QuicHttpStreamTest, SendPostRequest) { TEST_P(QuicHttpStreamTest, DestroyedEarly) { SetRequestString("GET", "/"); AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0, request_data_)); - AddWrite(SYNCHRONOUS, ConstructRstPacket(2, 3, request_data_.length())); + AddWrite(SYNCHRONOUS, ConstructRstPacket(2, 3)); AddWrite(SYNCHRONOUS, ConstructAckPacket(3, 2, 2)); use_closing_stream_ = true; Initialize(); diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index b9dae53..35aa947 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc @@ -91,14 +91,14 @@ class QuicNetworkTransactionTest : public PlatformTest { host)); QuicFramer framer(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); - return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*chlo)); + return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *chlo)); } scoped_ptr<QuicEncryptedPacket> ConstructShlo() { scoped_ptr<QuicPacket> shlo(ConstructHandshakePacket(0xDEADBEEF, kSHLO)); QuicFramer framer(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); - return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*shlo)); + return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *shlo)); } scoped_ptr<QuicEncryptedPacket> ConstructRstPacket( @@ -106,12 +106,15 @@ class QuicNetworkTransactionTest : public PlatformTest { QuicStreamId stream_id) { QuicPacketHeader header; header.public_header.guid = 0xDEADBEEF; - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; header.packet_sequence_number = num; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.entropy_flag = false; + header.fec_flag = false; + header.fec_entropy_flag = false; header.fec_group = 0; - QuicRstStreamFrame rst(stream_id, 0, QUIC_NO_ERROR); + QuicRstStreamFrame rst(stream_id, QUIC_NO_ERROR); return scoped_ptr<QuicEncryptedPacket>( ConstructPacket(header, QuicFrame(&rst))); } @@ -121,9 +124,12 @@ class QuicNetworkTransactionTest : public PlatformTest { QuicPacketSequenceNumber least_unacked) { QuicPacketHeader header; header.public_header.guid = 0xDEADBEEF; - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; header.packet_sequence_number = 3; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.entropy_flag = false; + header.fec_flag = false; + header.fec_entropy_flag = false; header.fec_group = 0; QuicAckFrame ack(largest_received, least_unacked); @@ -139,8 +145,9 @@ class QuicNetworkTransactionTest : public PlatformTest { frames.push_back(QuicFrame(&ack)); frames.push_back(QuicFrame(&feedback)); scoped_ptr<QuicPacket> packet( - framer.ConstructFrameDataPacket(header, frames)); - return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*packet)); + framer.ConstructFrameDataPacket(header, frames).packet); + return scoped_ptr<QuicEncryptedPacket>( + framer.EncryptPacket(header.packet_sequence_number, *packet)); } std::string GetRequestString(const std::string& method, @@ -190,16 +197,20 @@ class QuicNetworkTransactionTest : public PlatformTest { QuicFrames frames; frames.push_back(frame); scoped_ptr<QuicPacket> packet( - framer.ConstructFrameDataPacket(header, frames)); - return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*packet)); + framer.ConstructFrameDataPacket(header, frames).packet); + return scoped_ptr<QuicEncryptedPacket>( + framer.EncryptPacket(header.packet_sequence_number, *packet)); } void InitializeHeader(QuicPacketSequenceNumber sequence_number) { header_.public_header.guid = random_generator_.RandUint64(); - header_.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header_.public_header.reset_flag = false; + header_.public_header.version_flag = false; header_.packet_sequence_number = sequence_number; header_.fec_group = 0; - header_.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header_.entropy_flag = false; + header_.fec_flag = false; + header_.fec_entropy_flag = false; } void CreateSession() { diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc index e80ea85..bc80bd3 100644 --- a/net/quic/quic_packet_creator.cc +++ b/net/quic/quic_packet_creator.cc @@ -5,8 +5,11 @@ #include "net/quic/quic_packet_creator.h" #include "base/logging.h" +#include "net/quic/crypto/quic_random.h" +#include "net/quic/quic_fec_group.h" #include "net/quic/quic_utils.h" + using base::StringPiece; using std::make_pair; using std::min; @@ -15,9 +18,12 @@ using std::vector; namespace net { -QuicPacketCreator::QuicPacketCreator(QuicGuid guid, QuicFramer* framer) +QuicPacketCreator::QuicPacketCreator(QuicGuid guid, + QuicFramer* framer, + QuicRandom* random_generator) : guid_(guid), framer_(framer), + random_generator_(random_generator), sequence_number_(0), fec_group_number_(0), packet_size_(kPacketHeaderSize) { @@ -48,6 +54,10 @@ void QuicPacketCreator::MaybeStartFEC() { } } +bool QuicPacketCreator::HasRoomForStreamFrame() const { + return (BytesFree() > kFrameTypeSize + kMinStreamFrameLength); +} + size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id, StringPiece data, QuicStreamOffset offset, @@ -55,10 +65,11 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id, QuicFrame* frame) { DCHECK_GT(options_.max_packet_length, QuicUtils::StreamFramePacketOverhead(1)); - const size_t free_bytes = BytesFree(); - DCHECK_GE(free_bytes, kFrameTypeSize + kMinStreamFrameLength); + DCHECK(HasRoomForStreamFrame()); + const size_t free_bytes = BytesFree(); size_t bytes_consumed = 0; + if (data.size() != 0) { size_t max_data_len = free_bytes - kFrameTypeSize - kMinStreamFrameLength; bytes_consumed = min<size_t>(max_data_len, data.size()); @@ -75,76 +86,69 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id, return bytes_consumed; } -PacketPair QuicPacketCreator::SerializeAllFrames(const QuicFrames& frames) { +SerializedPacket QuicPacketCreator::SerializeAllFrames( + const QuicFrames& frames) { + // TODO(satyamshekhar): Verify that this DCHECK won't fail. What about queued + // frames from SendStreamData()[send_stream_should_flush_ == false && + // data.empty() == true] and retransmit due to RTO. DCHECK_EQ(0u, queued_frames_.size()); for (size_t i = 0; i < frames.size(); ++i) { - bool success = AddFrame(frames[i]); + bool success = AddFrame(frames[i], false); DCHECK(success); } - return SerializePacket(NULL); + SerializedPacket packet = SerializePacket(); + DCHECK(packet.retransmittable_frames == NULL); + return packet; } bool QuicPacketCreator::HasPendingFrames() { return !queued_frames_.empty(); } -size_t QuicPacketCreator::BytesFree() { +size_t QuicPacketCreator::BytesFree() const { const size_t max_plaintext_size = framer_->GetMaxPlaintextSize(options_.max_packet_length); if (packet_size_ > max_plaintext_size) { return 0; - } else { - return max_plaintext_size - packet_size_; } + return max_plaintext_size - packet_size_; } -bool QuicPacketCreator::AddFrame(const QuicFrame& frame) { - size_t frame_len = framer_->GetSerializedFrameLength( - frame, BytesFree(), queued_frames_.empty()); - if (frame_len == 0) { - return false; - } - packet_size_ += frame_len; - queued_frames_.push_back(frame); - return true; +bool QuicPacketCreator::AddSavedFrame(const QuicFrame& frame) { + return AddFrame(frame, true); } -PacketPair QuicPacketCreator::SerializePacket( - QuicFrames* retransmittable_frames) { +SerializedPacket QuicPacketCreator::SerializePacket() { DCHECK_EQ(false, queued_frames_.empty()); QuicPacketHeader header; - FillPacketHeader(fec_group_number_, PACKET_PRIVATE_FLAGS_NONE, &header); + FillPacketHeader(fec_group_number_, false, false, &header); - QuicPacket* packet = framer_->ConstructFrameDataPacket( + SerializedPacket serialized = framer_->ConstructFrameDataPacket( header, queued_frames_, packet_size_); - for (size_t i = 0; i < queued_frames_.size(); ++i) { - if (retransmittable_frames != NULL && ShouldRetransmit(queued_frames_[i])) { - retransmittable_frames->push_back(queued_frames_[i]); - } - } queued_frames_.clear(); packet_size_ = kPacketHeaderSize; - return make_pair(header.packet_sequence_number, packet); + serialized.retransmittable_frames = queued_retransmittable_frames_.release(); + return serialized; } -QuicPacketCreator::PacketPair QuicPacketCreator::SerializeFec() { +SerializedPacket QuicPacketCreator::SerializeFec() { DCHECK_LT(0u, fec_group_->NumReceivedPackets()); DCHECK_EQ(0u, queued_frames_.size()); QuicPacketHeader header; - FillPacketHeader(fec_group_number_, PACKET_PRIVATE_FLAGS_FEC, &header); - + FillPacketHeader(fec_group_number_, true, + fec_group_->entropy_parity(), &header); QuicFecData fec_data; fec_data.fec_group = fec_group_->min_protected_packet(); - fec_data.redundancy = fec_group_->parity(); - QuicPacket* packet = framer_->ConstructFecPacket(header, fec_data); + fec_data.redundancy = fec_group_->payload_parity(); + SerializedPacket serialized = framer_->ConstructFecPacket(header, fec_data); fec_group_.reset(NULL); fec_group_number_ = 0; - DCHECK(packet); - DCHECK_GE(options_.max_packet_length, packet->length()); - return make_pair(header.packet_sequence_number, packet); + DCHECK(serialized.packet); + DCHECK_GE(options_.max_packet_length, serialized.packet->length()); + return serialized; } -QuicPacketCreator::PacketPair QuicPacketCreator::CloseConnection( +SerializedPacket QuicPacketCreator::SerializeConnectionClose( QuicConnectionCloseFrame* close_frame) { QuicFrames frames; frames.push_back(QuicFrame(close_frame)); @@ -152,12 +156,22 @@ QuicPacketCreator::PacketPair QuicPacketCreator::CloseConnection( } void QuicPacketCreator::FillPacketHeader(QuicFecGroupNumber fec_group, - QuicPacketPrivateFlags flags, + bool fec_flag, + bool fec_entropy_flag, QuicPacketHeader* header) { header->public_header.guid = guid_; - header->public_header.flags = PACKET_PUBLIC_FLAGS_NONE; - header->private_flags = flags; + header->public_header.reset_flag = false; + header->public_header.version_flag = false; + header->fec_flag = fec_flag; + header->fec_entropy_flag = fec_entropy_flag; header->packet_sequence_number = ++sequence_number_; + if (header->packet_sequence_number == 1) { + // TODO(satyamshekhar): No entropy in the first message. + // For crypto tests to pass. Fix this by using deterministic QuicRandom. + header->entropy_flag = 0; + } else { + header->entropy_flag = random_generator_->RandBool(); + } header->fec_group = fec_group; } @@ -166,4 +180,30 @@ bool QuicPacketCreator::ShouldRetransmit(const QuicFrame& frame) { frame.type != PADDING_FRAME; } +bool QuicPacketCreator::AddFrame(const QuicFrame& frame, + bool save_retransmittable_frames) { + size_t frame_len = framer_->GetSerializedFrameLength( + frame, BytesFree(), queued_frames_.empty()); + if (frame_len == 0) { + return false; + } + packet_size_ += frame_len; + + if (save_retransmittable_frames && ShouldRetransmit(frame)) { + if (queued_retransmittable_frames_.get() == NULL) { + queued_retransmittable_frames_.reset(new RetransmittableFrames()); + } + if (frame.type == STREAM_FRAME) { + queued_frames_.push_back( + queued_retransmittable_frames_->AddStreamFrame(frame.stream_frame)); + } else { + queued_frames_.push_back( + queued_retransmittable_frames_->AddNonStreamFrame(frame)); + } + } else { + queued_frames_.push_back(frame); + } + return true; +} + } // namespace net diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h index b5eb9b8..23301ec 100644 --- a/net/quic/quic_packet_creator.h +++ b/net/quic/quic_packet_creator.h @@ -20,10 +20,10 @@ namespace net { +class QuicRandom; + class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { public: - typedef std::pair<QuicPacketSequenceNumber, QuicPacket*> PacketPair; - // Options for controlling how packets are created. struct Options { Options() @@ -38,7 +38,10 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { size_t max_packets_per_fec_group; }; - QuicPacketCreator(QuicGuid guid, QuicFramer* framer); + // QuicRandom* required for packet entropy. + QuicPacketCreator(QuicGuid guid, + QuicFramer* framer, + QuicRandom* random_generator); virtual ~QuicPacketCreator(); @@ -54,6 +57,8 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { // and there is not already an FEC group open. void MaybeStartFEC(); + bool HasRoomForStreamFrame() const; + // Converts a raw payload to a frame which fits into the currently open // packet if there is one. Returns the number of bytes consumed from data. // If data is empty and fin is true, the expected behavior is to consume the @@ -64,30 +69,41 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { bool fin, QuicFrame* frame); - // Serializes all frames into a single packet. All frames must fit into a - // single packet. - PacketPair SerializeAllFrames(const QuicFrames& frames); + // Serializes all frames into a single packet. All frames must fit into a + // single packet. Also, sets the entropy hash of the serialized packet to a + // random bool and returns that value as a member of SerializedPacket. + // Never returns an RetransmittableFrames in SerializedPacket + SerializedPacket SerializeAllFrames(const QuicFrames& frames); // Returns true if there are frames pending to be serialized. bool HasPendingFrames(); // Returns the number of bytes which are free to frames in the current packet. - size_t BytesFree(); + size_t BytesFree() const; // Adds |frame| to the packet creator's list of frames to be serialized. // Returns false if the frame doesn't fit into the current packet. - bool AddFrame(const QuicFrame& frame); + bool AddSavedFrame(const QuicFrame& frame); // Serializes all frames which have been added and adds any which should be - // retransmitted to |retransmittable_frames| if it's not NULL. - PacketPair SerializePacket(QuicFrames* retransmittable_frames); - - // Packetize FEC data. - PacketPair SerializeFec(); + // retransmitted to |retransmittable_frames| if it's not NULL. All frames must + // fit into a single packet. Sets the entropy hash of the serialized + // packet to a random bool and returns that value as a member of + // SerializedPacket. Also, sets |serialized_frames| in the SerializedPacket + // to the corresponding RetransmittableFrames if any frames are to be + // retransmitted. + SerializedPacket SerializePacket(); + + // Packetize FEC data. All frames must fit into a single packet. Also, sets + // the entropy hash of the serialized packet to a random bool and returns + // that value as a member of SerializedPacket. + SerializedPacket SerializeFec(); // Creates a packet with connection close frame. Caller owns the created - // packet. - PacketPair CloseConnection(QuicConnectionCloseFrame* close_frame); + // packet. Also, sets the entropy hash of the serialized packet to a random + // bool and returns that value as a member of SerializedPacket. + SerializedPacket SerializeConnectionClose( + QuicConnectionCloseFrame* close_frame); QuicPacketSequenceNumber sequence_number() const { return sequence_number_; @@ -105,17 +121,24 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { static bool ShouldRetransmit(const QuicFrame& frame); void FillPacketHeader(QuicFecGroupNumber fec_group, - QuicPacketPrivateFlags flags, + bool fec_flag, + bool fec_entropy_flag, QuicPacketHeader* header); + // Allows a frame to be added without creating retransmittable frames. + // Particularly useful for retransmits using SerializeAllFrames(). + bool AddFrame(const QuicFrame& frame, bool save_retransmittable_frames); + Options options_; QuicGuid guid_; QuicFramer* framer_; + QuicRandom* random_generator_; QuicPacketSequenceNumber sequence_number_; QuicFecGroupNumber fec_group_number_; scoped_ptr<QuicFecGroup> fec_group_; size_t packet_size_; QuicFrames queued_frames_; + scoped_ptr<RetransmittableFrames> queued_retransmittable_frames_; }; } // namespace net diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc index 1c202d0..c060da7 100644 --- a/net/quic/quic_packet_creator_test.cc +++ b/net/quic/quic_packet_creator_test.cc @@ -6,6 +6,9 @@ #include "base/stl_util.h" #include "net/quic/crypto/null_encrypter.h" +#include "net/quic/crypto/quic_decrypter.h" +#include "net/quic/crypto/quic_encrypter.h" +#include "net/quic/crypto/quic_random.h" #include "net/quic/quic_utils.h" #include "net/quic/test_tools/quic_test_utils.h" #include "testing/gmock/include/gmock/gmock.h" @@ -28,17 +31,15 @@ class QuicPacketCreatorTest : public ::testing::Test { sequence_number_(0), guid_(2), data_("foo"), - creator_(guid_, &framer_) { + creator_(guid_, &framer_, QuicRandom::GetInstance()) { framer_.set_visitor(&framer_visitor_); } ~QuicPacketCreatorTest() { - for (QuicFrames::iterator it = frames_.begin(); it != frames_.end(); ++it) { - QuicConnection::DeleteEnclosedFrame(&(*it)); - } } void ProcessPacket(QuicPacket* packet) { - scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*packet)); + scoped_ptr<QuicEncryptedPacket> encrypted( + framer_.EncryptPacket(sequence_number_, *packet)); framer_.ProcessPacket(*encrypted); } @@ -65,7 +66,8 @@ class QuicPacketCreatorTest : public ::testing::Test { TEST_F(QuicPacketCreatorTest, SerializeFrame) { frames_.push_back(QuicFrame(new QuicStreamFrame( 0u, false, 0u, StringPiece("")))); - PacketPair pair = creator_.SerializeAllFrames(frames_); + SerializedPacket serialized = creator_.SerializeAllFrames(frames_); + delete frames_[0].stream_frame; { InSequence s; @@ -74,8 +76,8 @@ TEST_F(QuicPacketCreatorTest, SerializeFrame) { EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); EXPECT_CALL(framer_visitor_, OnPacketComplete()); } - ProcessPacket(pair.second); - delete pair.second; + ProcessPacket(serialized.packet); + delete serialized.packet; } TEST_F(QuicPacketCreatorTest, SerializeFrames) { @@ -84,7 +86,10 @@ TEST_F(QuicPacketCreatorTest, SerializeFrames) { 0u, false, 0u, StringPiece("")))); frames_.push_back(QuicFrame(new QuicStreamFrame( 0u, true, 0u, StringPiece("")))); - PacketPair pair = creator_.SerializeAllFrames(frames_); + SerializedPacket serialized = creator_.SerializeAllFrames(frames_); + delete frames_[0].ack_frame; + delete frames_[1].stream_frame; + delete frames_[2].stream_frame; { InSequence s; @@ -95,8 +100,8 @@ TEST_F(QuicPacketCreatorTest, SerializeFrames) { EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); EXPECT_CALL(framer_visitor_, OnPacketComplete()); } - ProcessPacket(pair.second); - delete pair.second; + ProcessPacket(serialized.packet); + delete serialized.packet; } TEST_F(QuicPacketCreatorTest, SerializeWithFEC) { @@ -106,7 +111,8 @@ TEST_F(QuicPacketCreatorTest, SerializeWithFEC) { frames_.push_back(QuicFrame(new QuicStreamFrame( 0u, false, 0u, StringPiece("")))); - PacketPair pair = creator_.SerializeAllFrames(frames_); + SerializedPacket serialized = creator_.SerializeAllFrames(frames_); + delete frames_[0].stream_frame; { InSequence s; @@ -116,14 +122,14 @@ TEST_F(QuicPacketCreatorTest, SerializeWithFEC) { EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); EXPECT_CALL(framer_visitor_, OnPacketComplete()); } - ProcessPacket(pair.second); - delete pair.second; + ProcessPacket(serialized.packet); + delete serialized.packet; ASSERT_FALSE(creator_.ShouldSendFec(false)); ASSERT_TRUE(creator_.ShouldSendFec(true)); - pair = creator_.SerializeFec(); - ASSERT_EQ(2u, pair.first); + serialized = creator_.SerializeFec(); + ASSERT_EQ(2u, serialized.sequence_number); { InSequence s; @@ -132,17 +138,17 @@ TEST_F(QuicPacketCreatorTest, SerializeWithFEC) { EXPECT_CALL(framer_visitor_, OnFecData(_)); EXPECT_CALL(framer_visitor_, OnPacketComplete()); } - ProcessPacket(pair.second); - delete pair.second; + ProcessPacket(serialized.packet); + delete serialized.packet; } -TEST_F(QuicPacketCreatorTest, CloseConnection) { +TEST_F(QuicPacketCreatorTest, SerializeConnectionClose) { QuicConnectionCloseFrame frame; frame.error_code = QUIC_NO_ERROR; frame.ack_frame = QuicAckFrame(0u, 0u); - PacketPair pair = creator_.CloseConnection(&frame); - ASSERT_EQ(1u, pair.first); + SerializedPacket serialized = creator_.SerializeConnectionClose(&frame); + ASSERT_EQ(1u, serialized.sequence_number); ASSERT_EQ(1u, creator_.sequence_number()); InSequence s; @@ -152,8 +158,8 @@ TEST_F(QuicPacketCreatorTest, CloseConnection) { EXPECT_CALL(framer_visitor_, OnConnectionCloseFrame(_)); EXPECT_CALL(framer_visitor_, OnPacketComplete()); - ProcessPacket(pair.second); - delete pair.second; + ProcessPacket(serialized.packet); + delete serialized.packet; } TEST_F(QuicPacketCreatorTest, CreateStreamFrame) { @@ -200,40 +206,41 @@ TEST_F(QuicPacketCreatorTest, AddFrameAndSerialize) { // Add a variety of frame types and then a padding frame. QuicAckFrame ack_frame; - EXPECT_TRUE(creator_.AddFrame(QuicFrame(&ack_frame))); + EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&ack_frame))); EXPECT_TRUE(creator_.HasPendingFrames()); QuicCongestionFeedbackFrame congestion_feedback; congestion_feedback.type = kFixRate; - EXPECT_TRUE(creator_.AddFrame(QuicFrame(&congestion_feedback))); + EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&congestion_feedback))); EXPECT_TRUE(creator_.HasPendingFrames()); QuicFrame frame; size_t consumed = creator_.CreateStreamFrame(1u, "test", 0u, false, &frame); EXPECT_EQ(4u, consumed); ASSERT_TRUE(frame.stream_frame); - EXPECT_TRUE(creator_.AddFrame(frame)); + EXPECT_TRUE(creator_.AddSavedFrame(frame)); EXPECT_TRUE(creator_.HasPendingFrames()); QuicPaddingFrame padding_frame; - EXPECT_TRUE(creator_.AddFrame(QuicFrame(&padding_frame))); + EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&padding_frame))); EXPECT_TRUE(creator_.HasPendingFrames()); EXPECT_EQ(0u, creator_.BytesFree()); - EXPECT_FALSE(creator_.AddFrame(QuicFrame(&ack_frame))); + EXPECT_FALSE(creator_.AddSavedFrame(QuicFrame(&ack_frame))); // Ensure the packet is successfully created. - QuicFrames retransmittable_frames; - PacketPair pair = creator_.SerializePacket(&retransmittable_frames); - ASSERT_TRUE(pair.second); - delete pair.second; - ASSERT_EQ(1u, retransmittable_frames.size()); - EXPECT_EQ(STREAM_FRAME, retransmittable_frames[0].type); + SerializedPacket serialized = creator_.SerializePacket(); + ASSERT_TRUE(serialized.packet); + delete serialized.packet; + ASSERT_TRUE(serialized.retransmittable_frames); + RetransmittableFrames* retransmittable = serialized.retransmittable_frames; + ASSERT_EQ(1u, retransmittable->frames().size()); + EXPECT_EQ(STREAM_FRAME, retransmittable->frames()[0].type); + ASSERT_TRUE(retransmittable->frames()[0].stream_frame); + delete serialized.retransmittable_frames; EXPECT_FALSE(creator_.HasPendingFrames()); EXPECT_EQ(max_plaintext_size - kPacketHeaderSize, creator_.BytesFree()); - - delete frame.stream_frame; } } // namespace diff --git a/net/quic/quic_packet_entropy_manager.cc b/net/quic/quic_packet_entropy_manager.cc new file mode 100644 index 0000000..35fb198 --- /dev/null +++ b/net/quic/quic_packet_entropy_manager.cc @@ -0,0 +1,145 @@ +// 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/quic_packet_entropy_manager.h" + +#include "base/logging.h" +#include "net/base/linked_hash_map.h" + +using std::make_pair; +using std::max; + +namespace net { + +QuicPacketEntropyManager::QuicPacketEntropyManager() + : sent_packets_entropy_hash_(0), + received_packets_entropy_hash_(0), + largest_received_sequence_number_(0) {} + +QuicPacketEntropyManager::~QuicPacketEntropyManager() {} + +void QuicPacketEntropyManager::RecordReceivedPacketEntropyHash( + QuicPacketSequenceNumber sequence_number, + QuicPacketEntropyHash entropy_hash) { + largest_received_sequence_number_ = + max<QuicPacketSequenceNumber>(largest_received_sequence_number_, + sequence_number); + received_packets_entropy_.insert(make_pair(sequence_number, entropy_hash)); + received_packets_entropy_hash_ ^= entropy_hash; + DVLOG(2) << "setting cumulative received entropy hash to: " + << static_cast<int>(received_packets_entropy_hash_) + << " updated with sequence number " << sequence_number + << " entropy hash: " << static_cast<int>(entropy_hash); +} + +void QuicPacketEntropyManager::RecordSentPacketEntropyHash( + QuicPacketSequenceNumber sequence_number, + QuicPacketEntropyHash entropy_hash) { + // TODO(satyamshekhar): Check this logic again when/if we enable packet + // reordering. + sent_packets_entropy_hash_ ^= entropy_hash; + sent_packets_entropy_.insert( + make_pair(sequence_number, + make_pair(entropy_hash, sent_packets_entropy_hash_))); + DVLOG(2) << "setting cumulative sent entropy hash to: " + << static_cast<int>(sent_packets_entropy_hash_) + << " updated with sequence number " << sequence_number + << " entropy hash: " << static_cast<int>(entropy_hash); +} + +QuicPacketEntropyHash QuicPacketEntropyManager::ReceivedEntropyHash( + QuicPacketSequenceNumber sequence_number) const { + if (sequence_number == largest_received_sequence_number_) { + return received_packets_entropy_hash_; + } + + ReceivedEntropyMap::const_iterator it = + received_packets_entropy_.upper_bound(sequence_number); + // When this map is empty we should only query entropy for + // |largest_received_sequence_number_|. + LOG_IF(WARNING, it != received_packets_entropy_.end()) + << "largest_received: " << largest_received_sequence_number_ + << " sequence_number: " << sequence_number; + + // TODO(satyamshekhar): Make this O(1). + QuicPacketEntropyHash hash = received_packets_entropy_hash_; + for (; it != received_packets_entropy_.end(); ++it) { + hash ^= it->second; + } + return hash; +} + +QuicPacketEntropyHash QuicPacketEntropyManager::SentEntropyHash( + QuicPacketSequenceNumber sequence_number) const { + SentEntropyMap::const_iterator it = + sent_packets_entropy_.find(sequence_number); + if (it == sent_packets_entropy_.end()) { + // Should only happen when we have not received ack for any packet. + DCHECK_EQ(0u, sequence_number); + return 0; + } + return it->second.second; +} + +void QuicPacketEntropyManager::RecalculateReceivedEntropyHash( + QuicPacketSequenceNumber sequence_number, + QuicPacketEntropyHash entropy_hash) { + received_packets_entropy_hash_ = entropy_hash; + ReceivedEntropyMap::iterator it = + received_packets_entropy_.lower_bound(sequence_number); + // TODO(satyamshekhar): Make this O(1). + for (; it != received_packets_entropy_.end(); ++it) { + received_packets_entropy_hash_ ^= it->second; + } +} + +bool QuicPacketEntropyManager::IsValidEntropy( + QuicPacketSequenceNumber sequence_number, + const SequenceNumberSet& missing_packets, + QuicPacketEntropyHash entropy_hash) const { + SentEntropyMap::const_iterator entropy_it = + sent_packets_entropy_.find(sequence_number); + if (entropy_it == sent_packets_entropy_.end()) { + DCHECK_EQ(0u, sequence_number); + // Close connection if something goes wrong. + return 0 == sequence_number; + } + QuicPacketEntropyHash expected_entropy_hash = entropy_it->second.second; + for (SequenceNumberSet::const_iterator it = missing_packets.begin(); + it != missing_packets.end(); ++it) { + entropy_it = sent_packets_entropy_.find(*it); + DCHECK(entropy_it != sent_packets_entropy_.end()); + expected_entropy_hash ^= entropy_it->second.first; + } + DLOG_IF(WARNING, entropy_hash != expected_entropy_hash) + << "Invalid entropy hash: " << static_cast<int>(entropy_hash) + << " expected entropy hash: " << static_cast<int>(expected_entropy_hash); + return entropy_hash == expected_entropy_hash; +} + +void QuicPacketEntropyManager::ClearSentEntropyBefore( + QuicPacketSequenceNumber sequence_number) { + if (sent_packets_entropy_.empty()) { + return; + } + SentEntropyMap::iterator it = sent_packets_entropy_.begin(); + while (it->first < sequence_number) { + sent_packets_entropy_.erase(it); + it = sent_packets_entropy_.begin(); + DCHECK(it != sent_packets_entropy_.end()); + } + DVLOG(2) << "Cleared entropy before: " + << sent_packets_entropy_.begin()->first; +} + +void QuicPacketEntropyManager::ClearReceivedEntropyBefore( + QuicPacketSequenceNumber sequence_number) { + // This might clear the received_packets_entropy_ map if the current packet + // is peer_least_packet_awaiting_ack_ and it doesn't have entropy flag set. + received_packets_entropy_.erase( + received_packets_entropy_.begin(), + received_packets_entropy_.lower_bound(sequence_number)); +} + +} // namespace net diff --git a/net/quic/quic_packet_entropy_manager.h b/net/quic/quic_packet_entropy_manager.h new file mode 100644 index 0000000..5a6c671 --- /dev/null +++ b/net/quic/quic_packet_entropy_manager.h @@ -0,0 +1,102 @@ +// 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. +// +// Manages the packet entropy calculation for both sent and received packets +// for a connection. + +#ifndef NET_QUIC_QUIC_PACKET_ENTROPY_MANAGER_H_ +#define NET_QUIC_QUIC_PACKET_ENTROPY_MANAGER_H_ + +#include "net/base/linked_hash_map.h" +#include "net/quic/quic_framer.h" +#include "net/quic/quic_protocol.h" + +namespace net { + +// Records all sent and received packets by a connection to track the cumulative +// entropy of both sent and received packets separately. It is used by the +// connection to validate an ack frame sent by the peer as a preventive measure +// against the optimistic ack attack. Also, called by the framer when it +// truncates an ack frame to get the correct entropy value for the ack frame +// being serialized. +class NET_EXPORT_PRIVATE QuicPacketEntropyManager : + public QuicReceivedEntropyHashCalculatorInterface { + public: + QuicPacketEntropyManager(); + virtual ~QuicPacketEntropyManager(); + + // Record the received entropy hash against |sequence_number|. + void RecordReceivedPacketEntropyHash(QuicPacketSequenceNumber sequence_number, + QuicPacketEntropyHash entropy_hash); + + // Record |entropy_hash| for sent packet corresponding to |sequence_number|. + void RecordSentPacketEntropyHash(QuicPacketSequenceNumber sequence_number, + QuicPacketEntropyHash entropy_hash); + + // QuicReceivedEntropyHashCalculatorInterface + // Called by QuicFramer, when the outgoing ack gets truncated, to recalculate + // the received entropy hash for the truncated ack frame. + virtual QuicPacketEntropyHash ReceivedEntropyHash( + QuicPacketSequenceNumber sequence_number) const OVERRIDE; + + QuicPacketEntropyHash SentEntropyHash( + QuicPacketSequenceNumber sequence_number) const; + + // Recalculate the received entropy hash since we had some missing packets + // which the sender won't retransmit again and has sent us the |entropy_hash| + // for packets up to, but not including, |sequence_number|. + void RecalculateReceivedEntropyHash( + QuicPacketSequenceNumber sequence_number, + QuicPacketEntropyHash entropy_hash); + + // Returns true if |entropy_hash| matches the expected sent entropy hash + // up to |sequence_number| removing sequence numbers from |missing_packets|. + bool IsValidEntropy(QuicPacketSequenceNumber sequence_number, + const SequenceNumberSet& missing_packets, + QuicPacketEntropyHash entropy_hash) const; + + // Removes not required entries from |sent_packets_entropy_| before + // |sequence_number|. + void ClearSentEntropyBefore(QuicPacketSequenceNumber sequence_number); + + // Removes not required entries from |received_packets_entropy_| before + // |sequence_number|. + void ClearReceivedEntropyBefore(QuicPacketSequenceNumber sequence_number); + + QuicPacketEntropyHash sent_packets_entropy_hash() const { + return sent_packets_entropy_hash_; + } + + QuicPacketEntropyHash received_packets_entropy_hash() const { + return received_packets_entropy_hash_; + } + + private: + typedef linked_hash_map<QuicPacketSequenceNumber, + std::pair<QuicPacketEntropyHash, + QuicPacketEntropyHash> > SentEntropyMap; + typedef std::map<QuicPacketSequenceNumber, + QuicPacketEntropyHash> ReceivedEntropyMap; + + // TODO(satyamshekhar): Can be optimized using an interval set like data + // structure. + // Set of received sequence numbers that had the received entropy flag set. + ReceivedEntropyMap received_packets_entropy_; + + // Linked hash map from sequence numbers to the sent entropy hash up to the + // sequence number in the key. + SentEntropyMap sent_packets_entropy_; + + // Cumulative hash of entropy of all sent packets. + QuicPacketEntropyHash sent_packets_entropy_hash_; + + // Cumulative hash of entropy of all received packets. + QuicPacketEntropyHash received_packets_entropy_hash_; + + QuicPacketSequenceNumber largest_received_sequence_number_; +}; + +} // namespace net + +#endif // NET_QUIC_QUIC_PACKET_ENTROPY_MANAGER_H_ diff --git a/net/quic/quic_packet_entropy_manager_test.cc b/net/quic/quic_packet_entropy_manager_test.cc new file mode 100644 index 0000000..17f4f1e3 --- /dev/null +++ b/net/quic/quic_packet_entropy_manager_test.cc @@ -0,0 +1,139 @@ +// 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/quic_packet_entropy_manager.h" + +#include <algorithm> +#include <vector> + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using std::make_pair; +using std::pair; +using std::vector; + +namespace net { +namespace test { +namespace { + +class QuicPacketEntropyManagerTest : public ::testing::Test { + protected: + QuicPacketEntropyManager entropy_manager_; +}; + +TEST_F(QuicPacketEntropyManagerTest, ReceivedPacketEntropyHash) { + vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies; + entropies.push_back(make_pair(1, 12)); + entropies.push_back(make_pair(7, 1)); + entropies.push_back(make_pair(2, 33)); + entropies.push_back(make_pair(5, 3)); + entropies.push_back(make_pair(8, 34)); + + for (size_t i = 0; i < entropies.size(); ++i) { + entropy_manager_.RecordReceivedPacketEntropyHash(entropies[i].first, + entropies[i].second); + } + + sort(entropies.begin(), entropies.end()); + + QuicPacketEntropyHash hash = 0; + size_t index = 0; + for (size_t i = 1; i <= (*entropies.rbegin()).first; ++i) { + if (entropies[index].first == i) { + hash ^= entropies[index].second; + ++index; + } + EXPECT_EQ(hash, entropy_manager_.ReceivedEntropyHash(i)); + } +}; + +TEST_F(QuicPacketEntropyManagerTest, EntropyHashBelowLeastObserved) { + EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(0)); + EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(9)); + entropy_manager_.RecordReceivedPacketEntropyHash(4, 5); + EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(3)); +}; + +TEST_F(QuicPacketEntropyManagerTest, EntropyHashAboveLargesObserved) { + EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(0)); + EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(9)); + entropy_manager_.RecordReceivedPacketEntropyHash(4, 5); + EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(3)); +}; + +TEST_F(QuicPacketEntropyManagerTest, RecalculateReceivedEntropyHash) { + vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies; + entropies.push_back(make_pair(1, 12)); + entropies.push_back(make_pair(2, 1)); + entropies.push_back(make_pair(3, 33)); + entropies.push_back(make_pair(4, 3)); + entropies.push_back(make_pair(5, 34)); + entropies.push_back(make_pair(6, 29)); + + QuicPacketEntropyHash entropy_hash = 0; + for (size_t i = 0; i < entropies.size(); ++i) { + entropy_manager_.RecordReceivedPacketEntropyHash(entropies[i].first, + entropies[i].second); + entropy_hash ^= entropies[i].second; + } + EXPECT_EQ(entropy_hash, entropy_manager_.ReceivedEntropyHash(6)); + + // Now set the entropy hash up to 4 to be 100. + entropy_hash ^= 100; + for (size_t i = 0; i < 3; ++i) { + entropy_hash ^= entropies[i].second; + } + entropy_manager_.RecalculateReceivedEntropyHash(4, 100); + EXPECT_EQ(entropy_hash, entropy_manager_.ReceivedEntropyHash(6)); +} + +TEST_F(QuicPacketEntropyManagerTest, SentEntropyHash) { + EXPECT_EQ(0, entropy_manager_.SentEntropyHash(0)); + + vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies; + entropies.push_back(make_pair(1, 12)); + entropies.push_back(make_pair(2, 1)); + entropies.push_back(make_pair(3, 33)); + entropies.push_back(make_pair(4, 3)); + + for (size_t i = 0; i < entropies.size(); ++i) { + entropy_manager_.RecordSentPacketEntropyHash(entropies[i].first, + entropies[i].second); + } + + QuicPacketEntropyHash hash = 0; + for (size_t i = 0; i < entropies.size(); ++i) { + hash ^= entropies[i].second; + EXPECT_EQ(hash, entropy_manager_.SentEntropyHash(i + 1)); + } +} + +TEST_F(QuicPacketEntropyManagerTest, IsValidEntropy) { + QuicPacketEntropyHash entropies[10] = + {12, 1, 33, 3, 32, 100, 28, 42, 22, 255}; + for (size_t i = 0; i < 10; ++i) { + entropy_manager_.RecordSentPacketEntropyHash(i + 1, entropies[i]); + } + + SequenceNumberSet missing_packets; + missing_packets.insert(1); + missing_packets.insert(4); + missing_packets.insert(7); + missing_packets.insert(8); + + QuicPacketEntropyHash entropy_hash = 0; + for (size_t i = 0; i < 10; ++i) { + if (missing_packets.find(i + 1) == missing_packets.end()) { + entropy_hash ^= entropies[i]; + } + } + + EXPECT_TRUE(entropy_manager_.IsValidEntropy(10, missing_packets, + entropy_hash)); +} + +} // namespace +} // namespace test +} // namespace net diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc new file mode 100644 index 0000000..fb4bcf2 --- /dev/null +++ b/net/quic/quic_packet_generator.cc @@ -0,0 +1,203 @@ +// 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/quic_packet_generator.h" + +#include "base/logging.h" +#include "net/quic/quic_fec_group.h" +#include "net/quic/quic_utils.h" + +using base::StringPiece; + +namespace net { + +QuicPacketGenerator::QuicPacketGenerator(DelegateInterface* delegate, + QuicPacketCreator* creator) + : delegate_(delegate), + packet_creator_(creator), + should_flush_(true), + should_send_ack_(false), + should_send_feedback_(false) { +} + +QuicPacketGenerator::~QuicPacketGenerator() { + for (QuicFrames::iterator it = queued_control_frames_.begin(); + it != queued_control_frames_.end(); ++it) { + switch (it->type) { + case PADDING_FRAME: + delete it->padding_frame; + break; + case STREAM_FRAME: + delete it->stream_frame; + break; + case ACK_FRAME: + delete it->ack_frame; + break; + case CONGESTION_FEEDBACK_FRAME: + delete it->congestion_feedback_frame; + break; + case RST_STREAM_FRAME: + delete it->rst_stream_frame; + break; + case CONNECTION_CLOSE_FRAME: + delete it->connection_close_frame; + break; + case GOAWAY_FRAME: + delete it->goaway_frame; + break; + case NUM_FRAME_TYPES: + DCHECK(false) << "Cannot delete type: " << it->type; + } + } +} + +void QuicPacketGenerator::SetShouldSendAck(bool also_send_feedback) { + should_send_ack_ = true; + should_send_feedback_ = also_send_feedback; + SendQueuedData(); +} + + +void QuicPacketGenerator::AddControlFrame(const QuicFrame& frame) { + queued_control_frames_.push_back(frame); + SendQueuedData(); +} + +QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id, + StringPiece data, + QuicStreamOffset offset, + bool fin) { + SendQueuedData(); + + size_t total_bytes_consumed = 0; + bool fin_consumed = false; + + // Make sure any queued data gets sent before new data. + // SendQueuedData(); + + while (delegate_->CanWrite(false)) { + // TODO(rch) figure out FEC. + // packet_creator_.MaybeStartFEC(); + QuicFrame frame; + size_t bytes_consumed = packet_creator_->CreateStreamFrame( + id, data, offset + total_bytes_consumed, fin, &frame); + bool success = packet_creator_->AddSavedFrame(frame); + DCHECK(success); + + total_bytes_consumed += bytes_consumed; + fin_consumed = fin && bytes_consumed == data.size(); + data.remove_prefix(bytes_consumed); + DCHECK(data.empty() || packet_creator_->BytesFree() == 0u); + + // TODO(ianswett): Restore packet reordering. + if (should_flush_ || !packet_creator_->HasRoomForStreamFrame()) { + SerializeAndSendPacket(); + } + + if (data.empty()) { + // We're done writing the data. Exit the loop. + // We don't make this a precondition because we could have 0 bytes of data + // if we're simply writing a fin. + break; + } + } + + // Ensure the FEC group is closed at the end of this method unless other + // writes are pending. + if (should_flush_ && packet_creator_->ShouldSendFec(true)) { + SerializedPacket serialized_fec = packet_creator_->SerializeFec(); + DCHECK(serialized_fec.packet); + delegate_->OnSerializedPacket(serialized_fec); + } + + DCHECK(!should_flush_ || !packet_creator_->HasPendingFrames()); + return QuicConsumedData(total_bytes_consumed, fin_consumed); +} + +void QuicPacketGenerator::SendQueuedData() { + while (HasPendingData() && delegate_->CanWrite(false)) { + if (!AddNextPendingFrame()) { + // Packet was full, so serialize and send it. + SerializeAndSendPacket(); + } + } + + if (should_flush_) { + if (packet_creator_->HasPendingFrames()) { + SerializeAndSendPacket(); + } + + // Ensure the FEC group is closed at the end of this method unless other + // writes are pending. + if (packet_creator_->ShouldSendFec(true)) { + SerializedPacket serialized_fec = packet_creator_->SerializeFec(); + DCHECK(serialized_fec.packet); + delegate_->OnSerializedPacket(serialized_fec); + } + } +} + +void QuicPacketGenerator::StartBatchOperations() { + should_flush_ = false; +} + +void QuicPacketGenerator::FinishBatchOperations() { + should_flush_ = true; + SendQueuedData(); +} + +bool QuicPacketGenerator::HasQueuedData() const { + return packet_creator_->HasPendingFrames() || HasPendingData(); +} + +bool QuicPacketGenerator::HasPendingData() const { + return should_send_ack_ || should_send_feedback_ || + !queued_control_frames_.empty(); +} + +bool QuicPacketGenerator::AddNextPendingFrame() { + if (should_send_ack_) { + pending_ack_frame_.reset(delegate_->CreateAckFrame()); + if (!packet_creator_->AddSavedFrame(QuicFrame(pending_ack_frame_.get()))) { + // packet was full + return false; + } + should_send_ack_ = false; + return true; + } + + if (should_send_feedback_) { + pending_feedback_frame_.reset(delegate_->CreateFeedbackFrame()); + if (!packet_creator_->AddSavedFrame(QuicFrame( + pending_feedback_frame_.get()))) { + // packet was full + return false; + } + should_send_feedback_ = false; + return true; + } + + DCHECK(!queued_control_frames_.empty()); + if (!packet_creator_->AddSavedFrame(queued_control_frames_.back())) { + // packet was full + return false; + } + queued_control_frames_.pop_back(); + return true; +} + +void QuicPacketGenerator::SerializeAndSendPacket() { + packet_creator_->MaybeStartFEC(); + SerializedPacket serialized_packet = packet_creator_->SerializePacket(); + DCHECK(serialized_packet.packet); + delegate_->OnSerializedPacket(serialized_packet); + + if (packet_creator_->ShouldSendFec(false)) { + SerializedPacket serialized_fec = packet_creator_->SerializeFec(); + DCHECK(serialized_fec.packet); + delegate_->OnSerializedPacket(serialized_fec); + } +} + +} // namespace net diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h new file mode 100644 index 0000000..32becc1 --- /dev/null +++ b/net/quic/quic_packet_generator.h @@ -0,0 +1,113 @@ +// 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. +// +// Responsible for generating packets on behalf of a QuicConnection. +// Packets are serialized just-in-time. Control frame are queued. +// Ack and Feedback frames will requested from the Connection +// just-in-time. When a packet needs to be sent, the Generator +// wills serialized a packet pass it to QuicConnection::SendOrQueuePacket() +// +// The Generator's mode of operation is controlled by two conditions: +// +// 1) Is the Delegate writable? +// +// If the Delegate is not writable, then no operations will cause +// a packet to be serialized. In particular: +// * SetShouldSendAck will simply record that an ack is to be send. +// * AddControlFram will enqueue the control frame. +// * ConsumeData will do nothing. +// +// If the Delegate is writable, then the behavior depends on the second +// condition: +// +// 2) Is the Generator in batch mode? +// +// If the Generator is NOT in batch mode, then each call to a write +// operation will serialize one or more packets. The contents will +// include any previous queued frames. If an ack should be sent +// but has not been sent, then the Delegate will be asked to create +// an Ack frame which will then be included in the packet. When +// the write call completes, the current packet will be serialized +// and sent to the Delegate, even if it is not full. +// +// If the Generator is in batch mode, then each write operation will +// add data to the "current" packet. When the current packet becomes +// full, it will be serialized and sent to the packet. When batch +// mode is ended via |FinishBatchOperations|, the current packet +// will be serialzied, even if it is not full. +// +// FEC behavior also depends on batch mode. In batch mode, FEC packets +// will be sent after |max_packets_per_group| have been sent, as well +// as after batch operations are complete. When not in batch mode, +// an FEC packet will be sent after each write call completes. +// +// TODO(rch): This behavior should probably be tuned. When not in batch +// mode we, should probably set a timer so that several independent +// operations can be grouped into the same FEC group. +// +// When an FEC packet is generate, it will be send to the Delegate, +// even if the Delegate has become unwritable after handling the +// data packet immediately proceeding the FEC packet. + +#ifndef NET_QUIC_QUIC_PACKET_GENERATOR_H_ +#define NET_QUIC_QUIC_PACKET_GENERATOR_H_ + +#include "net/quic/quic_packet_creator.h" + +namespace net { + +class NET_EXPORT_PRIVATE QuicPacketGenerator { + public: + class NET_EXPORT_PRIVATE DelegateInterface { + public: + virtual ~DelegateInterface() {} + virtual bool CanWrite(bool is_retransmission) = 0; + virtual QuicAckFrame* CreateAckFrame() = 0; + virtual QuicCongestionFeedbackFrame* CreateFeedbackFrame() = 0; + // Takes ownership of |packet.packet| and |packet.retransmittable_frames|. + virtual bool OnSerializedPacket(const SerializedPacket& packet) = 0; + }; + + QuicPacketGenerator(DelegateInterface* delegate, + QuicPacketCreator* creator); + + virtual ~QuicPacketGenerator(); + + void SetShouldSendAck(bool also_send_feedback); + void AddControlFrame(const QuicFrame& frame); + QuicConsumedData ConsumeData(QuicStreamId id, + base::StringPiece data, + QuicStreamOffset offset, + bool fin); + + // Disables flushing. + void StartBatchOperations(); + // Enables flushing and flushes queued data. + void FinishBatchOperations(); + + bool HasQueuedData() const; + + private: + // Must be called when the connection is writable + // and not blocked by the congestion manager. + void SendQueuedData(); + + bool HasPendingData() const; + bool AddNextPendingFrame(); + void SerializeAndSendPacket(); + + DelegateInterface* delegate_; + + QuicPacketCreator* packet_creator_; + QuicFrames queued_control_frames_; + bool should_flush_; + bool should_send_ack_; + scoped_ptr<QuicAckFrame> pending_ack_frame_; + scoped_ptr<QuicCongestionFeedbackFrame> pending_feedback_frame_; + bool should_send_feedback_; +}; + +} // namespace net + +#endif // NET_QUIC_QUIC_PACKET_GENERATOR_H_ diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc new file mode 100644 index 0000000..85a16e8 --- /dev/null +++ b/net/quic/quic_packet_generator_test.cc @@ -0,0 +1,508 @@ +// 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/quic_packet_generator.h" + +#include <string> + +#include "net/quic/crypto/crypto_protocol.h" +#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_utils.h" +#include "net/quic/test_tools/quic_test_utils.h" +#include "net/quic/test_tools/simple_quic_framer.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::StringPiece; +using testing::InSequence; +using testing::Return; +using testing::SaveArg; +using testing::_; + +namespace net { +namespace test { +namespace { + +class MockDelegate : public QuicPacketGenerator::DelegateInterface { + public: + MockDelegate() {} + virtual ~MockDelegate() {} + + MOCK_METHOD1(CanWrite, bool(bool is_retransmission)); + + MOCK_METHOD0(CreateAckFrame, QuicAckFrame*()); + MOCK_METHOD0(CreateFeedbackFrame, QuicCongestionFeedbackFrame*()); + MOCK_METHOD1(OnSerializedPacket, bool(const SerializedPacket& packet)); + + void SetCanWrite(bool can_write) { + EXPECT_CALL(*this, CanWrite(false)).WillRepeatedly(Return(can_write)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockDelegate); +}; + +// Simple struct for describing the contents of a packet. +// Useful in conjunction with a SimpleQuicFrame for validating +// that a packet contains the expected frames. +struct PacketContents { + PacketContents() + : num_ack_frames(0), + num_connection_close_frames(0), + num_feedback_frames(0), + num_goaway_frames(0), + num_rst_stream_frames(0), + num_stream_frames(0), + fec_group(0) { + } + + size_t num_ack_frames; + size_t num_connection_close_frames; + size_t num_feedback_frames; + size_t num_goaway_frames; + size_t num_rst_stream_frames; + size_t num_stream_frames; + + QuicFecGroupNumber fec_group; +}; + +} // namespace + +class QuicPacketGeneratorTest : public ::testing::Test { + protected: + QuicPacketGeneratorTest() + : framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)), + creator_(42, &framer_, &random_), + generator_(&delegate_, &creator_), + packet_(0, NULL, 0, NULL), + packet2_(0, NULL, 0, NULL), + packet3_(0, NULL, 0, NULL), + packet4_(0, NULL, 0, NULL), + packet5_(0, NULL, 0, NULL) { + } + + ~QuicPacketGeneratorTest() { + delete packet_.packet; + delete packet_.retransmittable_frames; + delete packet2_.packet; + delete packet2_.retransmittable_frames; + delete packet3_.packet; + delete packet3_.retransmittable_frames; + delete packet4_.packet; + delete packet4_.retransmittable_frames; + delete packet5_.packet; + delete packet5_.retransmittable_frames; + } + + QuicAckFrame* CreateAckFrame() { + // TODO(rch): Initialize this so it can be verified later. + return new QuicAckFrame(0, 0); + } + + QuicCongestionFeedbackFrame* CreateFeedbackFrame() { + QuicCongestionFeedbackFrame* frame = new QuicCongestionFeedbackFrame; + frame->type = kFixRate; + frame->fix_rate.bitrate = QuicBandwidth::FromBytesPerSecond(42); + return frame; + } + + QuicRstStreamFrame* CreateRstStreamFrame() { + return new QuicRstStreamFrame(1, QUIC_NO_ERROR); + } + + QuicGoAwayFrame* CreateGoAwayFrame() { + return new QuicGoAwayFrame(QUIC_NO_ERROR, 1, ""); + } + + void CheckPacketContains(const PacketContents& contents, + const SerializedPacket& packet) { + size_t num_retransmittable_frames = contents.num_connection_close_frames + + contents.num_goaway_frames + contents.num_rst_stream_frames + + contents.num_stream_frames; + size_t num_frames = contents.num_feedback_frames + contents.num_ack_frames + + num_retransmittable_frames; + + if (num_retransmittable_frames == 0) { + ASSERT_TRUE(packet.retransmittable_frames == NULL); + } else { + ASSERT_TRUE(packet.retransmittable_frames != NULL); + EXPECT_EQ(num_retransmittable_frames, + packet.retransmittable_frames->frames().size()); + } + + ASSERT_TRUE(packet.packet != NULL); + ASSERT_TRUE(simple_framer_.ProcessPacket(*packet.packet)); + EXPECT_EQ(num_frames, simple_framer_.num_frames()); + EXPECT_EQ(contents.num_ack_frames, simple_framer_.ack_frames().size()); + EXPECT_EQ(contents.num_connection_close_frames, + simple_framer_.connection_close_frames().size()); + EXPECT_EQ(contents.num_feedback_frames, + simple_framer_.feedback_frames().size()); + EXPECT_EQ(contents.num_goaway_frames, + simple_framer_.goaway_frames().size()); + EXPECT_EQ(contents.num_rst_stream_frames, + simple_framer_.rst_stream_frames().size()); + EXPECT_EQ(contents.num_stream_frames, + simple_framer_.stream_frames().size()); + EXPECT_EQ(contents.fec_group, simple_framer_.header().fec_group); + } + + void CheckPacketHasSingleStreamFrame(const SerializedPacket& packet) { + ASSERT_TRUE(packet.retransmittable_frames != NULL); + EXPECT_EQ(1u, packet.retransmittable_frames->frames().size()); + ASSERT_TRUE(packet.packet != NULL); + ASSERT_TRUE(simple_framer_.ProcessPacket(*packet.packet)); + EXPECT_EQ(1u, simple_framer_.num_frames()); + EXPECT_EQ(1u, simple_framer_.stream_frames().size()); + } + + void CheckPacketIsFec(const SerializedPacket& packet, + QuicPacketSequenceNumber fec_group) { + ASSERT_TRUE(packet.retransmittable_frames == NULL); + ASSERT_TRUE(packet.packet != NULL); + ASSERT_TRUE(simple_framer_.ProcessPacket(*packet.packet)); + EXPECT_TRUE(simple_framer_.header().fec_flag); + EXPECT_EQ(fec_group, simple_framer_.fec_data().fec_group); + } + + StringPiece CreateData(size_t len) { + data_array_.reset(new char[len]); + memset(data_array_.get(), '?', len); + return StringPiece(data_array_.get(), len); + } + + QuicFramer framer_; + MockRandom random_; + QuicPacketCreator creator_; + testing::StrictMock<MockDelegate> delegate_; + QuicPacketGenerator generator_; + SimpleQuicFramer simple_framer_; + SerializedPacket packet_; + SerializedPacket packet2_; + SerializedPacket packet3_; + SerializedPacket packet4_; + SerializedPacket packet5_; + + private: + scoped_ptr<char[]> data_array_; +}; + +TEST_F(QuicPacketGeneratorTest, ShouldSendAck_NotWritable) { + delegate_.SetCanWrite(false); + + generator_.SetShouldSendAck(false); + EXPECT_TRUE(generator_.HasQueuedData()); +} + +TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldNotFlush) { + delegate_.SetCanWrite(true); + generator_.StartBatchOperations(); + + EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame())); + + generator_.SetShouldSendAck(false); + EXPECT_TRUE(generator_.HasQueuedData()); +} + +TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldFlush) { + delegate_.SetCanWrite(true); + + EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame())); + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet_), Return(true))); + + generator_.SetShouldSendAck(false); + EXPECT_FALSE(generator_.HasQueuedData()); + + PacketContents contents; + contents.num_ack_frames = 1; + CheckPacketContains(contents, packet_); +} + +TEST_F(QuicPacketGeneratorTest, + ShouldSendAckWithFeedback_WritableAndShouldNotFlush) { + delegate_.SetCanWrite(true); + generator_.StartBatchOperations(); + + EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame())); + EXPECT_CALL(delegate_, CreateFeedbackFrame()).WillOnce( + Return(CreateFeedbackFrame())); + + generator_.SetShouldSendAck(true); + EXPECT_TRUE(generator_.HasQueuedData()); +} + +TEST_F(QuicPacketGeneratorTest, + ShouldSendAckWithFeedback_WritableAndShouldFlush) { + delegate_.SetCanWrite(true); + + EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame())); + EXPECT_CALL(delegate_, CreateFeedbackFrame()).WillOnce( + Return(CreateFeedbackFrame())); + + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet_), Return(true))); + + generator_.SetShouldSendAck(true); + EXPECT_FALSE(generator_.HasQueuedData()); + + PacketContents contents; + contents.num_ack_frames = 1; + contents.num_feedback_frames = 1; + CheckPacketContains(contents, packet_); +} + +TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritable) { + delegate_.SetCanWrite(false); + + generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); + EXPECT_TRUE(generator_.HasQueuedData()); +} + +TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) { + delegate_.SetCanWrite(true); + generator_.StartBatchOperations(); + + generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); + EXPECT_TRUE(generator_.HasQueuedData()); +} + +TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) { + delegate_.SetCanWrite(true); + + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet_), Return(true))); + + generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); + EXPECT_FALSE(generator_.HasQueuedData()); + + PacketContents contents; + contents.num_rst_stream_frames = 1; + CheckPacketContains(contents, packet_); +} + +TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) { + delegate_.SetCanWrite(false); + + QuicConsumedData consumed = generator_.ConsumeData(1, "foo", 2, true); + EXPECT_EQ(0u, consumed.bytes_consumed); + EXPECT_FALSE(consumed.fin_consumed); + EXPECT_FALSE(generator_.HasQueuedData()); +} + +TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) { + delegate_.SetCanWrite(true); + generator_.StartBatchOperations(); + + QuicConsumedData consumed = generator_.ConsumeData(1, "foo", 2, true); + EXPECT_EQ(3u, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_TRUE(generator_.HasQueuedData()); +} + +TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) { + delegate_.SetCanWrite(true); + + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet_), Return(true))); + QuicConsumedData consumed = generator_.ConsumeData(1, "foo", 2, true); + EXPECT_EQ(3u, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_FALSE(generator_.HasQueuedData()); + + PacketContents contents; + contents.num_stream_frames = 1; + CheckPacketContains(contents, packet_); +} + +TEST_F(QuicPacketGeneratorTest, + ConsumeDataMultipleTimes_WritableAndShouldNotFlush) { + delegate_.SetCanWrite(true); + generator_.StartBatchOperations(); + + generator_.ConsumeData(1, "foo", 2, true); + QuicConsumedData consumed = generator_.ConsumeData(3, "quux", 7, false); + EXPECT_EQ(4u, consumed.bytes_consumed); + EXPECT_FALSE(consumed.fin_consumed); + EXPECT_TRUE(generator_.HasQueuedData()); +} + +TEST_F(QuicPacketGeneratorTest, ConsumeData_BatchOperations) { + delegate_.SetCanWrite(true); + generator_.StartBatchOperations(); + + generator_.ConsumeData(1, "foo", 2, true); + QuicConsumedData consumed = generator_.ConsumeData(3, "quux", 7, false); + EXPECT_EQ(4u, consumed.bytes_consumed); + EXPECT_FALSE(consumed.fin_consumed); + EXPECT_TRUE(generator_.HasQueuedData()); + + // Now both frames will be flushed out. + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet_), Return(true))); + generator_.FinishBatchOperations(); + EXPECT_FALSE(generator_.HasQueuedData()); + + PacketContents contents; + contents.num_stream_frames = 2; + CheckPacketContains(contents, packet_); +} + +TEST_F(QuicPacketGeneratorTest, ConsumeDataFEC) { + delegate_.SetCanWrite(true); + + // Send FEC every two packets. + creator_.options()->max_packets_per_fec_group = 2; + + { + InSequence dummy; + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet_), Return(true))); + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet2_), Return(true))); + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet3_), Return(true))); + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet4_), Return(true))); + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet5_), Return(true))); + } + + // Send enough data to create 3 packets: two full and one partial. + size_t data_len = 2 * kMaxPacketSize + 100; + QuicConsumedData consumed = + generator_.ConsumeData(3, CreateData(data_len), 0, true); + EXPECT_EQ(data_len, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_FALSE(generator_.HasQueuedData()); + + CheckPacketHasSingleStreamFrame(packet_); + CheckPacketHasSingleStreamFrame(packet2_); + CheckPacketIsFec(packet3_, 1); + + CheckPacketHasSingleStreamFrame(packet4_); + CheckPacketIsFec(packet5_, 4); +} + +TEST_F(QuicPacketGeneratorTest, ConsumeDataSendsFecAtEnd) { + delegate_.SetCanWrite(true); + + // Send FEC every six packets. + creator_.options()->max_packets_per_fec_group = 6; + + { + InSequence dummy; + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet_), Return(true))); + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet2_), Return(true))); + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet3_), Return(true))); + } + + // Send enough data to create 2 packets: one full and one partial. + size_t data_len = 1 * kMaxPacketSize + 100; + QuicConsumedData consumed = + generator_.ConsumeData(3, CreateData(data_len), 0, true); + EXPECT_EQ(data_len, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + EXPECT_FALSE(generator_.HasQueuedData()); + + CheckPacketHasSingleStreamFrame(packet_); + CheckPacketHasSingleStreamFrame(packet2_); + CheckPacketIsFec(packet3_, 1); +} + +TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) { + delegate_.SetCanWrite(false); + + generator_.SetShouldSendAck(true); + generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); + EXPECT_TRUE(generator_.HasQueuedData()); + + delegate_.SetCanWrite(true); + + generator_.StartBatchOperations(); + + // When the first write operation is invoked, the ack and feedback + // frames will be returned. + EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame())); + EXPECT_CALL(delegate_, CreateFeedbackFrame()).WillOnce( + Return(CreateFeedbackFrame())); + + // Send some data and a control frame + generator_.ConsumeData(3, "quux", 7, false); + generator_.AddControlFrame(QuicFrame(CreateGoAwayFrame())); + + // All five frames will be flushed out in a single packet. + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet_), Return(true))); + generator_.FinishBatchOperations(); + EXPECT_FALSE(generator_.HasQueuedData()); + + PacketContents contents; + contents.num_ack_frames = 1; + contents.num_goaway_frames = 1; + contents.num_feedback_frames = 1; + contents.num_rst_stream_frames = 1; + contents.num_stream_frames = 1; + CheckPacketContains(contents, packet_); +} + +TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) { + delegate_.SetCanWrite(false); + + generator_.SetShouldSendAck(true); + generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); + EXPECT_TRUE(generator_.HasQueuedData()); + + delegate_.SetCanWrite(true); + + generator_.StartBatchOperations(); + + // When the first write operation is invoked, the ack and feedback + // frames will be returned. + EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame())); + EXPECT_CALL(delegate_, CreateFeedbackFrame()).WillOnce( + Return(CreateFeedbackFrame())); + + { + InSequence dummy; + // All five frames will be flushed out in a single packet + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet_), Return(true))); + EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce( + DoAll(SaveArg<0>(&packet2_), Return(true))); + } + + // Send enough data to exceed one packet + size_t data_len = kMaxPacketSize + 100; + QuicConsumedData consumed = + generator_.ConsumeData(3, CreateData(data_len), 0, true); + EXPECT_EQ(data_len, consumed.bytes_consumed); + EXPECT_TRUE(consumed.fin_consumed); + generator_.AddControlFrame(QuicFrame(CreateGoAwayFrame())); + + generator_.FinishBatchOperations(); + EXPECT_FALSE(generator_.HasQueuedData()); + + // The first packet should have the queued data and part of the stream data. + PacketContents contents; + contents.num_ack_frames = 1; + contents.num_feedback_frames = 1; + contents.num_rst_stream_frames = 1; + contents.num_stream_frames = 1; + CheckPacketContains(contents, packet_); + + // The second should have the remainder of the stream data. + PacketContents contents2; + contents2.num_goaway_frames = 1; + contents2.num_stream_frames = 1; + CheckPacketContains(contents2, packet2_); +} + +} // namespace test +} // namespace net diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index 14ad48b..42ee620 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc @@ -9,6 +9,7 @@ using base::StringPiece; using std::map; using std::numeric_limits; using std::ostream; +using std::string; namespace net { @@ -24,43 +25,37 @@ QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id, data(data) { } +ostream& operator<<(ostream& os, const QuicPacketHeader& header) { + os << "{ guid: " << header.public_header.guid + << ", reset_flag: " << header.public_header.reset_flag + << ", version_flag: " << header.public_header.version_flag + << ", fec_flag: " << header.fec_flag + << ", entropy_flag: " << header.entropy_flag + << ", entropy hash: " << static_cast<int>(header.entropy_hash) + << ", sequence_number: " << header.packet_sequence_number + << ", fec_group: " << header.fec_group<< "}\n"; + return os; +} + // TODO(ianswett): Initializing largest_observed to 0 should not be necessary. -ReceivedPacketInfo::ReceivedPacketInfo() : largest_observed(0) {} +ReceivedPacketInfo::ReceivedPacketInfo() + : largest_observed(0) { +} ReceivedPacketInfo::~ReceivedPacketInfo() {} -void ReceivedPacketInfo::RecordReceived( - QuicPacketSequenceNumber sequence_number) { - DCHECK(IsAwaitingPacket(sequence_number)); - if (largest_observed < sequence_number) { - DCHECK_LT(sequence_number - largest_observed, - numeric_limits<uint16>::max()); - // We've got a new high sequence number. Note any new intermediate missing - // packets, and update the last_ack data. - for (QuicPacketSequenceNumber i = largest_observed + 1; - i < sequence_number; ++i) { - DVLOG(1) << "missing " << i; - missing_packets.insert(i); - } - largest_observed = sequence_number; - } else { - // We've gotten one of the out of order packets - remove it from our - // "missing packets" list. - DVLOG(1) << "Removing " << sequence_number << " from missing list"; - missing_packets.erase(sequence_number); - } -} - -bool ReceivedPacketInfo::IsAwaitingPacket( - QuicPacketSequenceNumber sequence_number) const { - return sequence_number > largest_observed || - ContainsKey(missing_packets, sequence_number); +bool IsAwaitingPacket(const ReceivedPacketInfo& received_info, + QuicPacketSequenceNumber sequence_number) { + return sequence_number > received_info.largest_observed || + ContainsKey(received_info.missing_packets, sequence_number); } -void ReceivedPacketInfo::ClearMissingBefore( - QuicPacketSequenceNumber least_unacked) { - missing_packets.erase(missing_packets.begin(), - missing_packets.lower_bound(least_unacked)); +void InsertMissingPacketsBetween(ReceivedPacketInfo* received_info, + QuicPacketSequenceNumber lower, + QuicPacketSequenceNumber higher) { + for (QuicPacketSequenceNumber i = lower; i < higher; ++i) { + received_info->missing_packets.insert(i); + } } SentPacketInfo::SentPacketInfo() {} @@ -70,24 +65,24 @@ SentPacketInfo::~SentPacketInfo() {} // Testing convenience method. QuicAckFrame::QuicAckFrame(QuicPacketSequenceNumber largest_observed, QuicPacketSequenceNumber least_unacked) { - for (QuicPacketSequenceNumber seq_num = 1; - seq_num <= largest_observed; ++seq_num) { - received_info.RecordReceived(seq_num); - } received_info.largest_observed = largest_observed; + received_info.entropy_hash = 0; sent_info.least_unacked = least_unacked; + sent_info.entropy_hash = 0; } ostream& operator<<(ostream& os, const SentPacketInfo& sent_info) { - os << "least_unacked: " << sent_info.least_unacked; + os << "entropy_hash: " << static_cast<int>(sent_info.entropy_hash); + os << " least_unacked: " << sent_info.least_unacked; return os; } ostream& operator<<(ostream& os, const ReceivedPacketInfo& received_info) { - os << "largest_observed: " - << received_info.largest_observed + os << "entropy_hash: " << static_cast<int>(received_info.entropy_hash) + << " largest_observed: " << received_info.largest_observed << " missing_packets: [ "; - for (SequenceSet::const_iterator it = received_info.missing_packets.begin(); + for (SequenceNumberSet::const_iterator it = + received_info.missing_packets.begin(); it != received_info.missing_packets.end(); ++it) { os << *it << " "; } @@ -151,6 +146,15 @@ CongestionFeedbackMessageInterArrival() {} CongestionFeedbackMessageInterArrival:: ~CongestionFeedbackMessageInterArrival() {} +QuicGoAwayFrame::QuicGoAwayFrame(QuicErrorCode error_code, + QuicStreamId last_good_stream_id, + const string& reason) + : error_code(error_code), + last_good_stream_id(last_good_stream_id), + reason_phrase(reason) { + DCHECK_LE(error_code, numeric_limits<uint8>::max()); +} + QuicFecData::QuicFecData() {} bool QuicFecData::operator==(const QuicFecData& other) const { @@ -169,6 +173,58 @@ QuicData::~QuicData() { } } +RetransmittableFrames::RetransmittableFrames() {} + +RetransmittableFrames::~RetransmittableFrames() { + for (QuicFrames::iterator it = frames_.begin(); it != frames_.end(); ++it) { + switch (it->type) { + case PADDING_FRAME: + delete it->padding_frame; + break; + case STREAM_FRAME: + delete it->stream_frame; + break; + case ACK_FRAME: + delete it->ack_frame; + break; + case CONGESTION_FEEDBACK_FRAME: + delete it->congestion_feedback_frame; + break; + case RST_STREAM_FRAME: + delete it->rst_stream_frame; + break; + case CONNECTION_CLOSE_FRAME: + delete it->connection_close_frame; + break; + case GOAWAY_FRAME: + delete it->goaway_frame; + break; + case NUM_FRAME_TYPES: + DCHECK(false) << "Cannot delete type: " << it->type; + } + } + STLDeleteElements(&stream_data_); +} + +const QuicFrame& RetransmittableFrames::AddStreamFrame( + QuicStreamFrame* stream_frame) { + // Make an owned copy of the StringPiece. + string* stream_data = new string(stream_frame->data.data(), + stream_frame->data.size()); + // Ensure the frame's StringPiece points to the owned copy of the data. + stream_frame->data = StringPiece(*stream_data); + stream_data_.push_back(stream_data); + frames_.push_back(QuicFrame(stream_frame)); + return frames_.back(); +} + +const QuicFrame& RetransmittableFrames::AddNonStreamFrame( + const QuicFrame& frame) { + DCHECK_NE(frame.type, STREAM_FRAME); + frames_.push_back(frame); + return frames_.back(); +} + ostream& operator<<(ostream& os, const QuicEncryptedPacket& s) { os << s.length() << "-byte data"; return os; diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index 3d5f73e..689167c 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -35,6 +35,7 @@ typedef uint64 QuicStreamOffset; typedef uint64 QuicPacketSequenceNumber; typedef QuicPacketSequenceNumber QuicFecGroupNumber; typedef uint64 QuicPublicResetNonceProof; +typedef uint8 QuicPacketEntropyHash; // TODO(rch): Consider Quic specific names for these constants. // Maximum size in bytes of a QUIC packet. @@ -105,8 +106,6 @@ const QuicStreamId kCryptoStreamId = 1; // Value which indicates this packet is not FEC protected. const uint8 kNoFecOffset = 0xFF; -typedef std::pair<QuicPacketSequenceNumber, QuicPacket*> PacketPair; - const int64 kDefaultTimeoutUs = 600000000; // 10 minutes. enum QuicFrameType { @@ -116,20 +115,23 @@ enum QuicFrameType { CONGESTION_FEEDBACK_FRAME, RST_STREAM_FRAME, CONNECTION_CLOSE_FRAME, + GOAWAY_FRAME, NUM_FRAME_TYPES }; enum QuicPacketPublicFlags { PACKET_PUBLIC_FLAGS_NONE = 0, - PACKET_PUBLIC_FLAGS_VERSION = 1, - PACKET_PUBLIC_FLAGS_RST = 2, // Packet is a public reset packet. - PACKET_PUBLIC_FLAGS_MAX = 3 // Both bit set. + PACKET_PUBLIC_FLAGS_VERSION = 1 << 0, + PACKET_PUBLIC_FLAGS_RST = 1 << 1, // Packet is a public reset packet. + PACKET_PUBLIC_FLAGS_MAX = (1 << 2) - 1 // All bits set. }; enum QuicPacketPrivateFlags { PACKET_PRIVATE_FLAGS_NONE = 0, - PACKET_PRIVATE_FLAGS_FEC = 1, // Payload is FEC as opposed to frames. - PACKET_PRIVATE_FLAGS_MAX = PACKET_PRIVATE_FLAGS_FEC + PACKET_PRIVATE_FLAGS_FEC = 1 << 0, // Payload is FEC as opposed to frames. + PACKET_PRIVATE_FLAGS_ENTROPY = 1 << 1, + PACKET_PRIVATE_FLAGS_FEC_ENTROPY = 1 << 2, + PACKET_PRIVATE_FLAGS_MAX = (1 << 3) - 1 // All bits set. }; enum QuicVersion { @@ -161,6 +163,8 @@ enum QuicErrorCode { QUIC_INVALID_RST_STREAM_DATA, // Connection close data is malformed. QUIC_INVALID_CONNECTION_CLOSE_DATA, + // GoAway data is malformed. + QUIC_INVALID_GOAWAY_DATA, // Ack data is malformed. QUIC_INVALID_ACK_DATA, // There was an error decrypting. @@ -171,10 +175,8 @@ enum QuicErrorCode { QUIC_PACKET_TOO_LARGE, // Data was sent for a stream which did not exist. QUIC_PACKET_FOR_NONEXISTENT_STREAM, - // The client is going away (browser close, etc.) - QUIC_CLIENT_GOING_AWAY, - // The server is going away (restart etc.) - QUIC_SERVER_GOING_AWAY, + // The peer is going away. May be a client or server. + QUIC_PEER_GOING_AWAY, // A stream ID was invalid. QUIC_INVALID_STREAM_ID, // Too many streams already open. @@ -210,7 +212,8 @@ struct NET_EXPORT_PRIVATE QuicPacketPublicHeader { // Universal header. All QuicPacket headers will have a guid and public flags. // TODO(satyamshekhar): Support versioning as per Protocol Negotiation Doc. QuicGuid guid; - QuicPacketPublicFlags flags; + bool reset_flag; + bool version_flag; }; // Header for Data or FEC packets. @@ -218,8 +221,15 @@ struct QuicPacketHeader { QuicPacketHeader() {} explicit QuicPacketHeader(const QuicPacketPublicHeader& header) : public_header(header) {} + + NET_EXPORT_PRIVATE friend std::ostream& operator<<( + std::ostream& os, const QuicPacketHeader& s); + QuicPacketPublicHeader public_header; - QuicPacketPrivateFlags private_flags; + bool fec_flag; + bool fec_entropy_flag; + bool entropy_flag; + QuicPacketEntropyHash entropy_hash; QuicPacketSequenceNumber packet_sequence_number; QuicFecGroupNumber fec_group; }; @@ -252,7 +262,7 @@ struct NET_EXPORT_PRIVATE QuicStreamFrame { // TODO(ianswett): Re-evaluate the trade-offs of hash_set vs set when framing // is finalized. -typedef std::set<QuicPacketSequenceNumber> SequenceSet; +typedef std::set<QuicPacketSequenceNumber> SequenceNumberSet; // TODO(pwestin): Add a way to enforce the max size of this map. typedef std::map<QuicPacketSequenceNumber, QuicTime> TimeMap; @@ -262,16 +272,9 @@ struct NET_EXPORT_PRIVATE ReceivedPacketInfo { NET_EXPORT_PRIVATE friend std::ostream& operator<<( std::ostream& os, const ReceivedPacketInfo& s); - // Records a packet receipt. - void RecordReceived(QuicPacketSequenceNumber sequence_number); - - // True if the sequence number is greater than largest_observed or is listed - // as missing. - // Always returns false for sequence numbers less than least_unacked. - bool IsAwaitingPacket(QuicPacketSequenceNumber sequence_number) const; - - // Clears all missing packets less than |least_unacked|. - void ClearMissingBefore(QuicPacketSequenceNumber least_unacked); + // Entropy hash of all packets up to largest observed not including missing + // packets. + QuicPacketEntropyHash entropy_hash; // The highest packet sequence number we've observed from the peer. // @@ -283,16 +286,34 @@ struct NET_EXPORT_PRIVATE ReceivedPacketInfo { // list. QuicPacketSequenceNumber largest_observed; + // TODO(satyamshekhar): Can be optimized using an interval set like data + // structure. // The set of packets which we're expecting and have not received. - SequenceSet missing_packets; + SequenceNumberSet missing_packets; }; +// True if the sequence number is greater than largest_observed or is listed +// as missing. +// Always returns false for sequence numbers less than least_unacked. +bool NET_EXPORT_PRIVATE IsAwaitingPacket( + const ReceivedPacketInfo& received_info, + QuicPacketSequenceNumber sequence_number); + +// Inserts missing packets between [lower, higher). +void NET_EXPORT_PRIVATE InsertMissingPacketsBetween( + ReceivedPacketInfo* received_info, + QuicPacketSequenceNumber lower, + QuicPacketSequenceNumber higher); + struct NET_EXPORT_PRIVATE SentPacketInfo { SentPacketInfo(); ~SentPacketInfo(); NET_EXPORT_PRIVATE friend std::ostream& operator<<( std::ostream& os, const SentPacketInfo& s); + // Entropy hash of all packets up to, but not including, the least unacked + // packet. + QuicPacketEntropyHash entropy_hash; // The lowest packet we've sent which is unacked, and we expect an ack for. QuicPacketSequenceNumber least_unacked; }; @@ -356,14 +377,12 @@ struct NET_EXPORT_PRIVATE QuicCongestionFeedbackFrame { struct NET_EXPORT_PRIVATE QuicRstStreamFrame { QuicRstStreamFrame() {} - QuicRstStreamFrame(QuicStreamId stream_id, uint64 offset, - QuicErrorCode error_code) - : stream_id(stream_id), offset(offset), error_code(error_code) { + QuicRstStreamFrame(QuicStreamId stream_id, QuicErrorCode error_code) + : stream_id(stream_id), error_code(error_code) { DCHECK_LE(error_code, std::numeric_limits<uint8>::max()); } QuicStreamId stream_id; - uint64 offset; QuicErrorCode error_code; std::string error_details; }; @@ -374,6 +393,17 @@ struct NET_EXPORT_PRIVATE QuicConnectionCloseFrame { QuicAckFrame ack_frame; }; +struct NET_EXPORT_PRIVATE QuicGoAwayFrame { + QuicGoAwayFrame() {} + QuicGoAwayFrame(QuicErrorCode error_code, + QuicStreamId last_good_stream_id, + const std::string& reason); + + QuicErrorCode error_code; + QuicStreamId last_good_stream_id; + std::string reason_phrase; +}; + struct NET_EXPORT_PRIVATE QuicFrame { QuicFrame() {} explicit QuicFrame(QuicPaddingFrame* padding_frame) @@ -400,6 +430,10 @@ struct NET_EXPORT_PRIVATE QuicFrame { : type(CONNECTION_CLOSE_FRAME), connection_close_frame(frame) { } + explicit QuicFrame(QuicGoAwayFrame* frame) + : type(GOAWAY_FRAME), + goaway_frame(frame) { + } QuicFrameType type; union { @@ -409,6 +443,7 @@ struct NET_EXPORT_PRIVATE QuicFrame { QuicCongestionFeedbackFrame* congestion_feedback_frame; QuicRstStreamFrame* rst_stream_frame; QuicConnectionCloseFrame* connection_close_frame; + QuicGoAwayFrame* goaway_frame; }; }; @@ -464,8 +499,8 @@ class NET_EXPORT_PRIVATE QuicData { class NET_EXPORT_PRIVATE QuicPacket : public QuicData { public: static QuicPacket* NewDataPacket(char* buffer, - size_t length, - bool owns_buffer) { + size_t length, + bool owns_buffer) { return new QuicPacket(buffer, length, owns_buffer, false); } @@ -530,6 +565,43 @@ class NET_EXPORT_PRIVATE QuicEncryptedPacket : public QuicData { DISALLOW_COPY_AND_ASSIGN(QuicEncryptedPacket); }; +class NET_EXPORT_PRIVATE RetransmittableFrames { + public: + RetransmittableFrames(); + ~RetransmittableFrames(); + + // Allocates a local copy of the referenced StringPiece has QuicStreamFrame + // use it. + // Takes ownership of |stream_frame|. + const QuicFrame& AddStreamFrame(QuicStreamFrame* stream_frame); + // Takes ownership of the frame inside |frame|. + const QuicFrame& AddNonStreamFrame(const QuicFrame& frame); + const QuicFrames& frames() const { return frames_; } + + private: + QuicFrames frames_; + // Data referenced by the StringPiece of a QuicStreamFrame. + std::vector<std::string*> stream_data_; + + DISALLOW_COPY_AND_ASSIGN(RetransmittableFrames); +}; + +struct NET_EXPORT_PRIVATE SerializedPacket { + SerializedPacket(QuicPacketSequenceNumber sequence_number, + QuicPacket* packet, + QuicPacketEntropyHash entropy_hash, + RetransmittableFrames* retransmittable_frames) + : sequence_number(sequence_number), + packet(packet), + entropy_hash(entropy_hash), + retransmittable_frames(retransmittable_frames) { } + + QuicPacketSequenceNumber sequence_number; + QuicPacket* packet; + QuicPacketEntropyHash entropy_hash; + RetransmittableFrames* retransmittable_frames; +}; + // A struct for functions which consume data payloads and fins. // The first member of the pair indicates bytes consumed. // The second member of the pair indicates if an incoming fin was consumed. diff --git a/net/quic/quic_protocol_test.cc b/net/quic/quic_protocol_test.cc index a77582f..80f6f6a 100644 --- a/net/quic/quic_protocol_test.cc +++ b/net/quic/quic_protocol_test.cc @@ -11,41 +11,26 @@ namespace net { namespace test { namespace { -TEST(QuicProtocolTest, ReceivedInfo_RecordReceived) { +TEST(QuicProtocolTest, IsAawaitingPacket) { ReceivedPacketInfo received_info; - received_info.RecordReceived(1u); + received_info.largest_observed = 10u; + EXPECT_TRUE(IsAwaitingPacket(received_info, 11u)); + EXPECT_FALSE(IsAwaitingPacket(received_info, 1u)); - EXPECT_EQ(1u, received_info.largest_observed); - EXPECT_EQ(0u, received_info.missing_packets.size()); - - received_info.RecordReceived(3u); - - EXPECT_EQ(3u, received_info.largest_observed); - EXPECT_EQ(1u, received_info.missing_packets.size()); - - received_info.RecordReceived(2u); - - EXPECT_EQ(3u, received_info.largest_observed); - EXPECT_EQ(0u, received_info.missing_packets.size()); + received_info.missing_packets.insert(10); + EXPECT_TRUE(IsAwaitingPacket(received_info, 10u)); } -TEST(QuicProtocolTest, ReceivedInfo_ClearMissingBefore) { +TEST(QuicProtocolTest, InsertMissingPacketsBetween) { ReceivedPacketInfo received_info; - received_info.RecordReceived(1u); - - // Clear nothing. - received_info.ClearMissingBefore(1); - EXPECT_EQ(0u, received_info.missing_packets.size()); - - received_info.RecordReceived(3u); - - // Clear the first packet. - received_info.ClearMissingBefore(2); - EXPECT_EQ(1u, received_info.missing_packets.size()); - - // Clear the second packet, which has not been received. - received_info.ClearMissingBefore(3); - EXPECT_EQ(0u, received_info.missing_packets.size()); + InsertMissingPacketsBetween(&received_info, 4u, 10u); + EXPECT_EQ(6u, received_info.missing_packets.size()); + + QuicPacketSequenceNumber i = 4; + for (SequenceNumberSet::iterator it = received_info.missing_packets.begin(); + it != received_info.missing_packets.end(); ++it, ++i) { + EXPECT_EQ(i, *it); + } } } // namespace diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index ef0efbe3..dfcea32 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc @@ -39,7 +39,12 @@ class VisitorShim : public QuicConnectionVisitorInterface { session_->PostProcessAfterData(); } - virtual void OnAck(AckedPackets acked_packets) OVERRIDE { + virtual void OnGoAway(const QuicGoAwayFrame& frame) OVERRIDE { + session_->OnGoAway(frame); + session_->PostProcessAfterData(); + } + + virtual void OnAck(const SequenceNumberSet& acked_packets) OVERRIDE { session_->OnAck(acked_packets); session_->PostProcessAfterData(); } @@ -65,7 +70,9 @@ QuicSession::QuicSession(QuicConnection* connection, bool is_server) max_open_streams_(kDefaultMaxStreamsPerConnection), next_stream_id_(is_server ? 2 : 3), is_server_(is_server), - largest_peer_created_stream_id_(0) { + largest_peer_created_stream_id_(0), + goaway_received_(false), + goaway_sent_(false) { connection->set_visitor(visitor_shim_.get()); } @@ -109,7 +116,12 @@ void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) { if (!stream) { return; // Errors are handled by GetStream. } - stream->OnStreamReset(frame.error_code, frame.offset); + stream->OnStreamReset(frame.error_code); +} + +void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) { + DCHECK(frame.last_good_stream_id < next_stream_id_); + goaway_received_ = true; } void QuicSession::ConnectionClose(QuicErrorCode error, bool from_peer) { @@ -150,18 +162,20 @@ QuicConsumedData QuicSession::WriteData(QuicStreamId id, StringPiece data, QuicStreamOffset offset, bool fin) { - // TODO(wtc): type mismatch -- connection_->SendStreamData() returns a - // size_t. return connection_->SendStreamData(id, data, offset, fin); } void QuicSession::SendRstStream(QuicStreamId id, - QuicErrorCode error, - QuicStreamOffset offset) { - connection_->SendRstStream(id, error, offset); + QuicErrorCode error) { + connection_->SendRstStream(id, error); CloseStream(id); } +void QuicSession::SendGoAway(QuicErrorCode error_code, const string& reason) { + goaway_sent_ = true; + connection_->SendGoAway(error_code, largest_peer_created_stream_id_, reason); +} + void QuicSession::CloseStream(QuicStreamId stream_id) { DLOG(INFO) << "Closing stream " << stream_id; @@ -226,6 +240,12 @@ ReliableQuicStream* QuicSession::GetIncomingReliableStream( return NULL; } + if (goaway_sent_) { + // We've already sent a GoAway + connection()->SendRstStream(stream_id, QUIC_PEER_GOING_AWAY); + return NULL; + } + implicitly_created_streams_.erase(stream_id); if (stream_id > largest_peer_created_stream_id_) { // TODO(rch) add unit test for this diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index 32bffc1..6f07b9a 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h @@ -40,9 +40,10 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { const QuicPacketHeader& header, const std::vector<QuicStreamFrame>& frame) OVERRIDE; virtual void OnRstStream(const QuicRstStreamFrame& frame) OVERRIDE; + virtual void OnGoAway(const QuicGoAwayFrame& frame) OVERRIDE; virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE; // Not needed for HTTP. - virtual void OnAck(AckedPackets acked_packets) OVERRIDE {} + virtual void OnAck(const SequenceNumberSet& acked_packets) OVERRIDE {} virtual bool OnCanWrite() OVERRIDE; // Called by streams when they want to write data to the peer. @@ -56,8 +57,10 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { bool fin); // Called by streams when they want to close the stream in both directions. void SendRstStream(QuicStreamId id, - QuicErrorCode error, - QuicStreamOffset offset); + QuicErrorCode error); + + // Called when the session wants to go away and not accept any new streams. + void SendGoAway(QuicErrorCode error_code, const std::string& reason); // Removes the stream associated with 'stream_id' from the active stream map. virtual void CloseStream(QuicStreamId stream_id); @@ -90,6 +93,14 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { void MarkWriteBlocked(QuicStreamId id); + bool goaway_received() const { + return goaway_received_; + } + + bool goaway_sent() const { + return goaway_sent_; + } + protected: // Creates a new stream, owned by the caller, to handle a peer-initiated // stream. Returns NULL and does error handling if the stream can not be @@ -111,15 +122,10 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { ReliableQuicStream* GetIncomingReliableStream(QuicStreamId stream_id); - size_t get_max_open_streams() const { - return max_open_streams_; - } - - protected: // This is called after every call other than OnConnectionClose from the // QuicConnectionVisitor to allow post-processing once the work has been done. // In this case, it deletes streams given that it's safe to do so (no other - // opterations are being done on the streams at this time) + // operations are being done on the streams at this time) virtual void PostProcessAfterData(); base::hash_map<QuicStreamId, ReliableQuicStream*>* streams() { @@ -129,6 +135,10 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { return &closed_streams_; } + size_t get_max_open_streams() const { + return max_open_streams_; + } + private: friend class test::QuicSessionPeer; friend class VisitorShim; @@ -161,6 +171,11 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { std::list<QuicStreamId> write_blocked_streams_; QuicStreamId largest_peer_created_stream_id_; + + // Whether a GoAway has been received. + bool goaway_received_; + // Whether a GoAway has been sent. + bool goaway_sent_; }; } // namespace net diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc index daf904e..b97a021 100644 --- a/net/quic/quic_session_test.cc +++ b/net/quic/quic_session_test.cc @@ -198,6 +198,17 @@ TEST_F(QuicSessionTest, OnCanWriteWithClosedStream) { EXPECT_TRUE(session_.OnCanWrite()); } +TEST_F(QuicSessionTest, SendGoAway) { + // After sending a GoAway, ensure new incoming streams cannot be created and + // result in a RST being sent. + EXPECT_CALL(*connection_, + SendGoAway(QUIC_PEER_GOING_AWAY, 0u, "Going Away.")); + session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); + EXPECT_TRUE(session_.goaway_sent()); + + EXPECT_CALL(*connection_, SendRstStream(3u, QUIC_PEER_GOING_AWAY)); + EXPECT_FALSE(session_.GetIncomingReliableStream(3u)); +} } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index f18e3b3..e817021 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc @@ -38,14 +38,14 @@ class QuicStreamFactoryTest : public ::testing::Test { host)); QuicFramer framer(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); - return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*chlo)); + return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *chlo)); } scoped_ptr<QuicEncryptedPacket> ConstructShlo() { scoped_ptr<QuicPacket> shlo(ConstructHandshakePacket(0xDEADBEEF, kSHLO)); QuicFramer framer(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); - return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*shlo)); + return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *shlo)); } scoped_ptr<QuicEncryptedPacket> ConstructRstPacket( @@ -53,12 +53,15 @@ class QuicStreamFactoryTest : public ::testing::Test { QuicStreamId stream_id) { QuicPacketHeader header; header.public_header.guid = 0xDEADBEEF; - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; header.packet_sequence_number = num; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.entropy_flag = false; + header.fec_entropy_flag = false; + header.fec_flag = false; header.fec_group = 0; - QuicRstStreamFrame rst(stream_id, 0, QUIC_NO_ERROR); + QuicRstStreamFrame rst(stream_id, QUIC_NO_ERROR); return scoped_ptr<QuicEncryptedPacket>( ConstructPacket(header, QuicFrame(&rst))); } @@ -68,13 +71,15 @@ class QuicStreamFactoryTest : public ::testing::Test { QuicPacketSequenceNumber least_unacked) { QuicPacketHeader header; header.public_header.guid = 0xDEADBEEF; - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; header.packet_sequence_number = 2; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.entropy_flag = false; + header.fec_entropy_flag = false; + header.fec_flag = false; header.fec_group = 0; QuicAckFrame ack(largest_received, least_unacked); - QuicCongestionFeedbackFrame feedback; feedback.type = kTCP; feedback.tcp.accumulated_number_of_lost_packets = 0; @@ -86,8 +91,9 @@ class QuicStreamFactoryTest : public ::testing::Test { frames.push_back(QuicFrame(&ack)); frames.push_back(QuicFrame(&feedback)); scoped_ptr<QuicPacket> packet( - framer.ConstructFrameDataPacket(header, frames)); - return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*packet)); + framer.ConstructFrameDataPacket(header, frames).packet); + return scoped_ptr<QuicEncryptedPacket>( + framer.EncryptPacket(header.packet_sequence_number, *packet)); } // Returns a newly created packet to send congestion feedback data. @@ -95,9 +101,12 @@ class QuicStreamFactoryTest : public ::testing::Test { QuicPacketSequenceNumber sequence_number) { QuicPacketHeader header; header.public_header.guid = 0xDEADBEEF; - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; header.packet_sequence_number = sequence_number; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.entropy_flag = false; + header.fec_entropy_flag = false; + header.fec_flag = false; header.fec_group = 0; QuicCongestionFeedbackFrame frame; @@ -117,8 +126,9 @@ class QuicStreamFactoryTest : public ::testing::Test { QuicFrames frames; frames.push_back(frame); scoped_ptr<QuicPacket> packet( - framer.ConstructFrameDataPacket(header, frames)); - return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*packet)); + framer.ConstructFrameDataPacket(header, frames).packet); + return scoped_ptr<QuicEncryptedPacket>( + framer.EncryptPacket(header.packet_sequence_number, *packet)); } MockHostResolver host_resolver_; diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc index f4959ae..ec2a410 100644 --- a/net/quic/quic_stream_sequencer.cc +++ b/net/quic/quic_stream_sequencer.cc @@ -44,11 +44,10 @@ bool QuicStreamSequencer::WillAcceptStreamFrame( size_t data_len = frame.data.size(); DCHECK_LE(data_len, max_frame_memory_); - QuicStreamOffset byte_offset = frame.offset; - if (byte_offset < num_bytes_consumed_ || - frames_.find(byte_offset) != frames_.end()) { - return false; + if (IsDuplicate(frame)) { + return true; } + QuicStreamOffset byte_offset = frame.offset; if (data_len > max_frame_memory_) { // We're never going to buffer this frame and we can't pass it up. // The stream might only consume part of it and we'd need a partial ack. @@ -72,6 +71,10 @@ bool QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { // OnStreamFrame. Error handling should be done by the caller. return false; } + if (IsDuplicate(frame)) { + // Silently ignore duplicates. + return true; + } QuicStreamOffset byte_offset = frame.offset; const char* data = frame.data.data(); @@ -98,7 +101,6 @@ bool QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { byte_offset += bytes_consumed; } } - DVLOG(1) << "Buffering packet at offset " << byte_offset; frames_.insert(make_pair(byte_offset, string(data, data_len))); return true; @@ -151,6 +153,15 @@ bool QuicStreamSequencer::IsClosed() const { return num_bytes_consumed_ >= close_offset_ && half_close_ == false; } +bool QuicStreamSequencer::IsDuplicate(const QuicStreamFrame& frame) const { + // A frame is duplicate if the frame offset is smaller than our bytes consumed + // or we have stored the frame in our map. + // TODO(pwestin): Is it possible that a new frame contain more data even if + // the offset is the same? + return (frame.offset < num_bytes_consumed_ || + frames_.find(frame.offset) != frames_.end()); +} + void QuicStreamSequencer::FlushBufferedFrames() { FrameMap::iterator it = frames_.find(num_bytes_consumed_); while (it != frames_.end()) { diff --git a/net/quic/quic_stream_sequencer.h b/net/quic/quic_stream_sequencer.h index 37da13e..04a47f0 100644 --- a/net/quic/quic_stream_sequencer.h +++ b/net/quic/quic_stream_sequencer.h @@ -49,6 +49,8 @@ class NET_EXPORT_PRIVATE QuicStreamSequencer { bool OnStreamFrame(const QuicStreamFrame& frame); // Wait until we've seen 'offset' bytes, and then terminate the stream. + // TODO(ianswett): Simplify this method by removing half_close, now that + // the sequencer is bypassed for stream resets and half_close is always true. void CloseStreamAtOffset(QuicStreamOffset offset, bool half_close); // Once data is buffered, it's up to the stream to read it when the stream @@ -63,6 +65,9 @@ class NET_EXPORT_PRIVATE QuicStreamSequencer { // Returns true if the sequencer has delivered a full close. bool IsClosed() const; + // Returns true if the sequencer has received this frame before. + bool IsDuplicate(const QuicStreamFrame& frame) const; + private: friend class test::QuicStreamSequencerPeer; diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc index 7d22c4c..74937ae 100644 --- a/net/quic/quic_stream_sequencer_test.cc +++ b/net/quic/quic_stream_sequencer_test.cc @@ -92,9 +92,9 @@ TEST_F(QuicStreamSequencerTest, RejectOldFrame) { EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); EXPECT_EQ(0u, sequencer_->frames()->size()); EXPECT_EQ(3u, sequencer_->num_bytes_consumed()); - // Nack this - it matches a past sequence number and we should not see it + // Ignore this - it matches a past sequence number and we should not see it // again. - EXPECT_FALSE(sequencer_->OnFrame(0, "def", 3)); + EXPECT_TRUE(sequencer_->OnFrame(0, "def", 3)); EXPECT_EQ(0u, sequencer_->frames()->size()); } @@ -122,7 +122,7 @@ TEST_F(QuicStreamSequencerTest, RejectBufferedFrame) { EXPECT_EQ(0u, sequencer_->num_bytes_consumed()); // Ignore this - it matches a buffered frame. // Right now there's no checking that the payload is consistent. - EXPECT_FALSE(sequencer_->OnFrame(0, "def", 3)); + EXPECT_TRUE(sequencer_->OnFrame(0, "def", 3)); EXPECT_EQ(1u, sequencer_->frames()->size()); } diff --git a/net/quic/quic_time_test.cc b/net/quic/quic_time_test.cc index fc7d7e3..a4a6c55 100644 --- a/net/quic/quic_time_test.cc +++ b/net/quic/quic_time_test.cc @@ -98,13 +98,13 @@ TEST_F(QuicTimeTest, SubtractDelta) { TEST_F(QuicTimeTest, MockClock) { clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); - QuicTime now = clock_.Now(); + QuicTime now = clock_.ApproximateNow(); QuicTime time = QuicTime::FromMicroseconds(1000); EXPECT_EQ(now, time); clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); - now = clock_.Now(); + now = clock_.ApproximateNow(); EXPECT_NE(now, time); diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc index 0cfac44..0628dee 100644 --- a/net/quic/quic_utils.cc +++ b/net/quic/quic_utils.cc @@ -55,13 +55,13 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_INVALID_FEC_DATA); RETURN_STRING_LITERAL(QUIC_INVALID_RST_STREAM_DATA); RETURN_STRING_LITERAL(QUIC_INVALID_CONNECTION_CLOSE_DATA); + RETURN_STRING_LITERAL(QUIC_INVALID_GOAWAY_DATA); RETURN_STRING_LITERAL(QUIC_INVALID_ACK_DATA); RETURN_STRING_LITERAL(QUIC_DECRYPTION_FAILURE); RETURN_STRING_LITERAL(QUIC_ENCRYPTION_FAILURE); RETURN_STRING_LITERAL(QUIC_PACKET_TOO_LARGE); RETURN_STRING_LITERAL(QUIC_PACKET_FOR_NONEXISTENT_STREAM); - RETURN_STRING_LITERAL(QUIC_CLIENT_GOING_AWAY); - RETURN_STRING_LITERAL(QUIC_SERVER_GOING_AWAY); + RETURN_STRING_LITERAL(QUIC_PEER_GOING_AWAY); RETURN_STRING_LITERAL(QUIC_CRYPTO_TAGS_OUT_OF_ORDER); RETURN_STRING_LITERAL(QUIC_CRYPTO_TOO_MANY_ENTRIES); RETURN_STRING_LITERAL(QUIC_CRYPTO_INVALID_VALUE_LENGTH) diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index 1de1eb9..79b060e 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc @@ -14,7 +14,6 @@ ReliableQuicStream::ReliableQuicStream(QuicStreamId id, QuicSession* session) : sequencer_(this), id_(id), - offset_(0), session_(session), visitor_(NULL), stream_bytes_read_(0), @@ -48,21 +47,21 @@ 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. + stream_bytes_read_ += frame.data.length(); bool accepted = sequencer_.OnStreamFrame(frame); if (frame.fin) { - sequencer_.CloseStreamAtOffset(frame.offset + frame.data.size(), - true); + sequencer_.CloseStreamAtOffset(frame.offset + frame.data.size(), true); } return accepted; } -void ReliableQuicStream::OnStreamReset(QuicErrorCode error, - QuicStreamOffset offset) { +void ReliableQuicStream::OnStreamReset(QuicErrorCode error) { error_ = error; - sequencer_.CloseStreamAtOffset(offset, false); // Full close. + TerminateFromPeer(false); // Full close. } void ReliableQuicStream::ConnectionClose(QuicErrorCode error, bool from_peer) { @@ -84,7 +83,7 @@ void ReliableQuicStream::TerminateFromPeer(bool half_close) { void ReliableQuicStream::Close(QuicErrorCode error) { error_ = error; - session()->SendRstStream(id(), error, offset_); + session()->SendRstStream(id(), error); } bool ReliableQuicStream::IsHalfClosed() const { @@ -151,8 +150,7 @@ QuicConsumedData ReliableQuicStream::WriteDataInternal( } QuicConsumedData consumed_data = - session()->WriteData(id(), data, offset_, fin); - offset_ += consumed_data.bytes_consumed; + session()->WriteData(id(), data, stream_bytes_written_, fin); stream_bytes_written_ += consumed_data.bytes_consumed; if (consumed_data.bytes_consumed == data.length()) { if (fin && consumed_data.fin_consumed) { diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h index 50ed951..1c35cf0 100644 --- a/net/quic/reliable_quic_stream.h +++ b/net/quic/reliable_quic_stream.h @@ -54,9 +54,7 @@ class NET_EXPORT_PRIVATE ReliableQuicStream { virtual void OnClose(); // Called when we get a stream reset from the client. - // The rst will be passed through the sequencer, which will call - // TerminateFromPeer when 'offset' bytes have been processed. - void OnStreamReset(QuicErrorCode error, QuicStreamOffset ofset); + void OnStreamReset(QuicErrorCode error); // Called when we get or send a connection close, and should immediately // close the stream. This is not passed through the sequencer, @@ -126,7 +124,6 @@ class NET_EXPORT_PRIVATE ReliableQuicStream { QuicStreamSequencer sequencer_; QuicStreamId id_; - QuicStreamOffset offset_; QuicSession* session_; // Optional visitor of this stream to be notified when the stream is closed. Visitor* visitor_; diff --git a/net/quic/test_tools/mock_clock.cc b/net/quic/test_tools/mock_clock.cc index b85ae19..d9fb386 100644 --- a/net/quic/test_tools/mock_clock.cc +++ b/net/quic/test_tools/mock_clock.cc @@ -21,6 +21,10 @@ QuicTime MockClock::Now() const { return now_; } +QuicTime MockClock::ApproximateNow() const { + return now_; +} + QuicTime::Delta MockClock::NowAsDeltaSinceUnixEpoch() const { return now_.Subtract(QuicTime::Zero()); } diff --git a/net/quic/test_tools/mock_clock.h b/net/quic/test_tools/mock_clock.h index e1e84c7..7497aa2 100644 --- a/net/quic/test_tools/mock_clock.h +++ b/net/quic/test_tools/mock_clock.h @@ -23,6 +23,8 @@ class MockClock : public QuicClock { virtual QuicTime Now() const OVERRIDE; + virtual QuicTime ApproximateNow() const OVERRIDE; + virtual QuicTime::Delta NowAsDeltaSinceUnixEpoch() const OVERRIDE; base::TimeTicks NowInTicks() const; diff --git a/net/quic/test_tools/mock_random.cc b/net/quic/test_tools/mock_random.cc index 3b522ae..f7b8ea0 100644 --- a/net/quic/test_tools/mock_random.cc +++ b/net/quic/test_tools/mock_random.cc @@ -14,6 +14,10 @@ uint64 MockRandom::RandUint64() { return 0xDEADBEEF; } +bool MockRandom::RandBool() { + return false; +} + void MockRandom::Reseed(const void* additional_entropy, size_t entropy_len) { } diff --git a/net/quic/test_tools/mock_random.h b/net/quic/test_tools/mock_random.h index 780057b..b583182 100644 --- a/net/quic/test_tools/mock_random.h +++ b/net/quic/test_tools/mock_random.h @@ -17,6 +17,8 @@ class MockRandom : public QuicRandom { virtual void RandBytes(void* data, size_t len) OVERRIDE; // Returns 0xDEADBEEF. virtual uint64 RandUint64() OVERRIDE; + // Returns false. + virtual bool RandBool() OVERRIDE; // Does nothing. virtual void Reseed(const void* additional_entropy, size_t entropy_len) OVERRIDE; diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc index 7befa32..d834d5e 100644 --- a/net/quic/test_tools/quic_connection_peer.cc +++ b/net/quic/test_tools/quic_connection_peer.cc @@ -33,7 +33,9 @@ void QuicConnectionPeer::SetSendAlgorithm( } // static -QuicAckFrame* QuicConnectionPeer::GetOutgoingAck(QuicConnection* connection) { +QuicAckFrame* QuicConnectionPeer::GetOutgoingAck( + QuicConnection* connection) { + connection->UpdateOutgoingAck(); return &connection->outgoing_ack_; } @@ -72,8 +74,33 @@ size_t QuicConnectionPeer::GetRetransmissionCount( QuicPacketSequenceNumber sequence_number) { QuicConnection::RetransmissionMap::iterator it = connection->retransmission_map_.find(sequence_number); + DCHECK(connection->retransmission_map_.end() != it); return it->second.number_retransmissions; } +// static +QuicPacketEntropyHash QuicConnectionPeer::GetSentEntropyHash( + QuicConnection* connection, + QuicPacketSequenceNumber sequence_number) { + return connection->entropy_manager_.SentEntropyHash(sequence_number); +} + +// static +bool QuicConnectionPeer::IsValidEntropy( + QuicConnection* connection, + QuicPacketSequenceNumber largest_observed, + const SequenceNumberSet& missing_packets, + QuicPacketEntropyHash entropy_hash) { + return connection->entropy_manager_.IsValidEntropy( + largest_observed, missing_packets, entropy_hash); +} + +// static +QuicPacketEntropyHash QuicConnectionPeer::ReceivedEntropyHash( + QuicConnection* connection, + QuicPacketSequenceNumber sequence_number) { + return connection->entropy_manager_.ReceivedEntropyHash(sequence_number); +} + } // 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 deb313e0..8c3ff67 100644 --- a/net/quic/test_tools/quic_connection_peer.h +++ b/net/quic/test_tools/quic_connection_peer.h @@ -49,6 +49,19 @@ class QuicConnectionPeer { QuicConnection* connection, QuicPacketSequenceNumber sequence_number); + static QuicPacketEntropyHash GetSentEntropyHash( + QuicConnection* connection, + QuicPacketSequenceNumber sequence_number); + + static bool IsValidEntropy(QuicConnection* connection, + QuicPacketSequenceNumber largest_observed, + const SequenceNumberSet& missing_packets, + QuicPacketEntropyHash entropy_hash); + + static QuicPacketEntropyHash ReceivedEntropyHash( + QuicConnection* connection, + QuicPacketSequenceNumber sequence_number); + 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 c53f797..a96949c 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc @@ -29,25 +29,52 @@ bool NoOpFramerVisitor::OnPacketHeader(const QuicPacketHeader& header) { return true; } -FramerVisitorCapturingAcks::FramerVisitorCapturingAcks() { +FramerVisitorCapturingFrames::FramerVisitorCapturingFrames() : frame_count_(0) { } -FramerVisitorCapturingAcks::~FramerVisitorCapturingAcks() { +FramerVisitorCapturingFrames::~FramerVisitorCapturingFrames() { } -bool FramerVisitorCapturingAcks::OnPacketHeader( +bool FramerVisitorCapturingFrames::OnPacketHeader( const QuicPacketHeader& header) { header_ = header; + frame_count_ = 0; return true; } -void FramerVisitorCapturingAcks::OnAckFrame(const QuicAckFrame& frame) { +void FramerVisitorCapturingFrames::OnStreamFrame(const QuicStreamFrame& frame) { + // TODO(ianswett): Own the underlying string, so it will not exist outside + // this callback. + stream_frames_.push_back(frame); + ++frame_count_; +} + +void FramerVisitorCapturingFrames::OnAckFrame(const QuicAckFrame& frame) { ack_.reset(new QuicAckFrame(frame)); + ++frame_count_; } -void FramerVisitorCapturingAcks::OnCongestionFeedbackFrame( +void FramerVisitorCapturingFrames::OnCongestionFeedbackFrame( const QuicCongestionFeedbackFrame& frame) { feedback_.reset(new QuicCongestionFeedbackFrame(frame)); + ++frame_count_; +} + +void FramerVisitorCapturingFrames::OnRstStreamFrame( + const QuicRstStreamFrame& frame) { + rst_.reset(new QuicRstStreamFrame(frame)); + ++frame_count_; +} + +void FramerVisitorCapturingFrames::OnConnectionCloseFrame( + const QuicConnectionCloseFrame& frame) { + close_.reset(new QuicConnectionCloseFrame(frame)); + ++frame_count_; +} + +void FramerVisitorCapturingFrames::OnGoAwayFrame(const QuicGoAwayFrame& frame) { + goaway_.reset(new QuicGoAwayFrame(frame)); + ++frame_count_; } FramerVisitorCapturingPublicReset::FramerVisitorCapturingPublicReset() { @@ -108,7 +135,7 @@ PacketSavingConnection::~PacketSavingConnection() { bool PacketSavingConnection::SendOrQueuePacket( QuicPacketSequenceNumber sequence_number, QuicPacket* packet, - bool force) { + QuicPacketEntropyHash hash) { packets_.push_back(packet); return true; } @@ -220,9 +247,13 @@ static QuicPacket* ConstructPacketFromHandshakeMessage( QuicPacketHeader header; header.public_header.guid = guid; - header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.public_header.reset_flag = false; + header.public_header.version_flag = false; header.packet_sequence_number = 1; - header.private_flags = PACKET_PRIVATE_FLAGS_NONE; + header.entropy_flag = false; + header.entropy_hash = 0; + header.fec_flag = false; + header.fec_entropy_flag = false; header.fec_group = 0; QuicStreamFrame stream_frame(kCryptoStreamId, false, 0, @@ -231,7 +262,7 @@ static QuicPacket* ConstructPacketFromHandshakeMessage( QuicFrame frame(&stream_frame); QuicFrames frames; frames.push_back(frame); - return quic_framer.ConstructFrameDataPacket(header, frames); + return quic_framer.ConstructFrameDataPacket(header, frames).packet; } QuicPacket* ConstructHandshakePacket(QuicGuid guid, CryptoTag tag) { @@ -268,5 +299,10 @@ QuicPacket* ConstructServerHelloPacket(QuicGuid guid, return ConstructPacketFromHandshakeMessage(guid, message); } +QuicPacketEntropyHash TestEntropyCalculator::ReceivedEntropyHash( + QuicPacketSequenceNumber sequence_number) const { + return 1u; +} + } // namespace test } // namespace net diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 1a23e48..7724d16 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h @@ -7,6 +7,8 @@ #ifndef NET_QUIC_TEST_TOOLS_QUIC_TEST_UTILS_H_ #define NET_QUIC_TEST_TOOLS_QUIC_TEST_UTILS_H_ +#include <vector> + #include "net/quic/congestion_control/send_algorithm_interface.h" #include "net/quic/quic_connection.h" #include "net/quic/quic_framer.h" @@ -63,6 +65,7 @@ class MockFramerVisitor : public QuicFramerVisitorInterface { MOCK_METHOD1(OnRstStreamFrame, void(const QuicRstStreamFrame& frame)); MOCK_METHOD1(OnConnectionCloseFrame, void(const QuicConnectionCloseFrame& frame)); + MOCK_METHOD1(OnGoAwayFrame, void(const QuicGoAwayFrame& frame)); MOCK_METHOD0(OnPacketComplete, void()); private: @@ -88,50 +91,68 @@ class NoOpFramerVisitor : public QuicFramerVisitorInterface { virtual void OnRstStreamFrame(const QuicRstStreamFrame& frame) OVERRIDE {} virtual void OnConnectionCloseFrame( const QuicConnectionCloseFrame& frame) OVERRIDE {} + virtual void OnGoAwayFrame(const QuicGoAwayFrame& frame) OVERRIDE {} virtual void OnPacketComplete() OVERRIDE {} private: DISALLOW_COPY_AND_ASSIGN(NoOpFramerVisitor); }; -class FramerVisitorCapturingAcks : public NoOpFramerVisitor { +class FramerVisitorCapturingPublicReset : public NoOpFramerVisitor { + public: + FramerVisitorCapturingPublicReset(); + virtual ~FramerVisitorCapturingPublicReset(); + + virtual void OnPublicResetPacket( + const QuicPublicResetPacket& packet) OVERRIDE; + + const QuicPublicResetPacket public_reset_packet() { + return public_reset_packet_; + } + + private: + QuicPublicResetPacket public_reset_packet_; +}; + +class FramerVisitorCapturingFrames : public NoOpFramerVisitor { public: - FramerVisitorCapturingAcks(); - virtual ~FramerVisitorCapturingAcks(); + FramerVisitorCapturingFrames(); + virtual ~FramerVisitorCapturingFrames(); // NoOpFramerVisitor + virtual bool OnPacketHeader(const QuicPacketHeader& header) OVERRIDE; + virtual void OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE; virtual void OnAckFrame(const QuicAckFrame& frame) OVERRIDE; virtual void OnCongestionFeedbackFrame( const QuicCongestionFeedbackFrame& frame) OVERRIDE; + virtual void OnRstStreamFrame(const QuicRstStreamFrame& frame) OVERRIDE; + virtual void OnConnectionCloseFrame( + const QuicConnectionCloseFrame& frame) OVERRIDE; + virtual void OnGoAwayFrame(const QuicGoAwayFrame& frame) OVERRIDE; + size_t frame_count() { return frame_count_; } QuicPacketHeader* header() { return &header_; } - + const std::vector<QuicStreamFrame>* stream_frames() { + return &stream_frames_; + } QuicAckFrame* ack() { return ack_.get(); } QuicCongestionFeedbackFrame* feedback() { return feedback_.get(); } + QuicRstStreamFrame* rst() { return rst_.get(); } + QuicConnectionCloseFrame* close() { return close_.get(); } + QuicGoAwayFrame* goaway() { return goaway_.get(); } private: + size_t frame_count_; QuicPacketHeader header_; + std::vector<QuicStreamFrame> stream_frames_; scoped_ptr<QuicAckFrame> ack_; scoped_ptr<QuicCongestionFeedbackFrame> feedback_; + scoped_ptr<QuicRstStreamFrame> rst_; + scoped_ptr<QuicConnectionCloseFrame> close_; + scoped_ptr<QuicGoAwayFrame> goaway_; - DISALLOW_COPY_AND_ASSIGN(FramerVisitorCapturingAcks); -}; - -class FramerVisitorCapturingPublicReset : public NoOpFramerVisitor { - public: - FramerVisitorCapturingPublicReset(); - virtual ~FramerVisitorCapturingPublicReset(); - - virtual void OnPublicResetPacket( - const QuicPublicResetPacket& packet) OVERRIDE; - - const QuicPublicResetPacket public_reset_packet() { - return public_reset_packet_; - } - - private: - QuicPublicResetPacket public_reset_packet_; + DISALLOW_COPY_AND_ASSIGN(FramerVisitorCapturingFrames); }; class MockConnectionVisitor : public QuicConnectionVisitorInterface { @@ -144,8 +165,9 @@ class MockConnectionVisitor : public QuicConnectionVisitorInterface { const QuicPacketHeader& header, const std::vector<QuicStreamFrame>& frame)); MOCK_METHOD1(OnRstStream, void(const QuicRstStreamFrame& frame)); + MOCK_METHOD1(OnGoAway, void(const QuicGoAwayFrame& frame)); MOCK_METHOD2(ConnectionClose, void(QuicErrorCode error, bool from_peer)); - MOCK_METHOD1(OnAck, void(AckedPackets acked_packets)); + MOCK_METHOD1(OnAck, void(const SequenceNumberSet& acked_packets)); MOCK_METHOD0(OnCanWrite, bool()); private: @@ -188,10 +210,11 @@ class MockConnection : public QuicConnection { const QuicEncryptedPacket& packet)); MOCK_METHOD1(SendConnectionClose, void(QuicErrorCode error)); - MOCK_METHOD3(SendRstStream, void(QuicStreamId id, - QuicErrorCode error, - QuicStreamOffset offset)); - + MOCK_METHOD2(SendRstStream, void(QuicStreamId id, + QuicErrorCode error)); + MOCK_METHOD3(SendGoAway, void(QuicErrorCode error, + QuicStreamId last_good_stream_id, + const string& reason)); MOCK_METHOD0(OnCanWrite, bool()); void ProcessUdpPacketInternal(const IPEndPoint& self_address, @@ -212,7 +235,7 @@ class PacketSavingConnection : public MockConnection { virtual bool SendOrQueuePacket(QuicPacketSequenceNumber sequence_number, QuicPacket* packet, - bool force) OVERRIDE; + QuicPacketEntropyHash entropy_hash) OVERRIDE; std::vector<QuicPacket*> packets_; @@ -249,19 +272,34 @@ class MockSendAlgorithm : public SendAlgorithmInterface { MockSendAlgorithm(); virtual ~MockSendAlgorithm(); - MOCK_METHOD2(OnIncomingQuicCongestionFeedbackFrame, - void(const QuicCongestionFeedbackFrame&, const SentPacketsMap&)); + MOCK_METHOD4(OnIncomingQuicCongestionFeedbackFrame, + void(const QuicCongestionFeedbackFrame&, + QuicTime feedback_receive_time, + QuicBandwidth sent_bandwidth, + const SentPacketsMap&)); MOCK_METHOD3(OnIncomingAck, void(QuicPacketSequenceNumber, QuicByteCount, QuicTime::Delta)); - MOCK_METHOD1(OnIncomingLoss, void(int number_of_lost_packets)); - MOCK_METHOD3(SentPacket, void(QuicPacketSequenceNumber, QuicByteCount, bool)); - MOCK_METHOD1(TimeUntilSend, QuicTime::Delta(bool)); + MOCK_METHOD1(OnIncomingLoss, void(QuicTime)); + MOCK_METHOD4(SentPacket, void(QuicTime sent_time, QuicPacketSequenceNumber, + QuicByteCount, bool)); + MOCK_METHOD2(TimeUntilSend, QuicTime::Delta(QuicTime now, bool)); MOCK_METHOD0(BandwidthEstimate, QuicBandwidth(void)); private: DISALLOW_COPY_AND_ASSIGN(MockSendAlgorithm); }; +class TestEntropyCalculator : + public QuicReceivedEntropyHashCalculatorInterface { + public: + TestEntropyCalculator() { } + virtual ~TestEntropyCalculator() { } + + virtual QuicPacketEntropyHash ReceivedEntropyHash( + QuicPacketSequenceNumber sequence_number) const OVERRIDE; + +}; + } // namespace test } // namespace net diff --git a/net/quic/test_tools/reliable_quic_stream_peer.cc b/net/quic/test_tools/reliable_quic_stream_peer.cc index 12ceca2..5119d03 100644 --- a/net/quic/test_tools/reliable_quic_stream_peer.cc +++ b/net/quic/test_tools/reliable_quic_stream_peer.cc @@ -16,9 +16,10 @@ void ReliableQuicStreamPeer::SetWriteSideClosed(bool value, } // static -void ReliableQuicStreamPeer::SetOffset(QuicStreamOffset offset, - ReliableQuicStream* stream) { - stream->offset_ = offset; +void ReliableQuicStreamPeer::SetStreamBytesWritten( + QuicStreamOffset stream_bytes_written, + ReliableQuicStream* stream) { + stream->stream_bytes_written_ = stream_bytes_written; } } // namespace test diff --git a/net/quic/test_tools/reliable_quic_stream_peer.h b/net/quic/test_tools/reliable_quic_stream_peer.h index aaa8434..da229da 100644 --- a/net/quic/test_tools/reliable_quic_stream_peer.h +++ b/net/quic/test_tools/reliable_quic_stream_peer.h @@ -17,7 +17,8 @@ namespace test { class ReliableQuicStreamPeer { public: static void SetWriteSideClosed(bool value, ReliableQuicStream* stream); - static void SetOffset(QuicStreamOffset offset, ReliableQuicStream* stream); + static void SetStreamBytesWritten(QuicStreamOffset stream_bytes_written, + ReliableQuicStream* stream); private: DISALLOW_COPY_AND_ASSIGN(ReliableQuicStreamPeer); diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc new file mode 100644 index 0000000..2ffd9ca --- /dev/null +++ b/net/quic/test_tools/simple_quic_framer.cc @@ -0,0 +1,180 @@ +// 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/test_tools/simple_quic_framer.h" + +using base::StringPiece; +using std::string; +using std::vector; + +namespace net { +namespace test { + +class SimpleFramerVisitor : public QuicFramerVisitorInterface { + public: + SimpleFramerVisitor() + : error_(QUIC_NO_ERROR) { + } + + virtual void OnError(QuicFramer* framer) { + error_ = framer->error(); + } + + virtual void OnPacket() {} + virtual void OnPublicResetPacket(const QuicPublicResetPacket& packet) {} + virtual void OnRevivedPacket() {} + virtual bool OnPacketHeader(const QuicPacketHeader& header) { + has_header_ = true; + header_ = header; + return true; + } + + virtual void OnFecProtectedPayload(StringPiece payload) {} + + virtual void OnStreamFrame(const QuicStreamFrame& frame) { + // Save a copy of the data so it is valid after the packet is processed. + stream_data_.push_back(frame.data.as_string()); + QuicStreamFrame stream_frame(frame); + // Make sure that the stream frame points to this data. + stream_frame.data = stream_data_.back(); + stream_frames_.push_back(stream_frame); + } + + virtual void OnAckFrame(const QuicAckFrame& frame) { + ack_frames_.push_back(frame); + } + + virtual void OnCongestionFeedbackFrame( + const QuicCongestionFeedbackFrame& frame) { + feedback_frames_.push_back(frame); + } + + virtual void OnFecData(const QuicFecData& fec) { + fec_data_ = fec; + fec_redundancy_ = fec_data_.redundancy.as_string(); + fec_data_.redundancy = fec_redundancy_; + } + + virtual void OnRstStreamFrame(const QuicRstStreamFrame& frame) { + rst_stream_frames_.push_back(frame); + } + + virtual void OnConnectionCloseFrame( + const QuicConnectionCloseFrame& frame) { + connection_close_frames_.push_back(frame); + } + + virtual void OnGoAwayFrame(const QuicGoAwayFrame& frame) { + goaway_frames_.push_back(frame); + } + + virtual void OnPacketComplete() {} + + const QuicPacketHeader& header() const { return header_; } + const vector<QuicAckFrame>& ack_frames() const { return ack_frames_; } + const vector<QuicConnectionCloseFrame>& connection_close_frames() const { + return connection_close_frames_; + } + const vector<QuicCongestionFeedbackFrame>& feedback_frames() const { + return feedback_frames_; + } + const vector<QuicGoAwayFrame>& goaway_frames() const { + return goaway_frames_; + } + const vector<QuicRstStreamFrame>& rst_stream_frames() const { + return rst_stream_frames_; + } + const vector<QuicStreamFrame>& stream_frames() const { + return stream_frames_; + } + const QuicFecData& fec_data() const { + return fec_data_; + } + + private: + QuicErrorCode error_; + bool has_header_; + QuicPacketHeader header_; + QuicFecData fec_data_; + string fec_redundancy_; + vector<QuicAckFrame> ack_frames_; + vector<QuicCongestionFeedbackFrame> feedback_frames_; + vector<QuicStreamFrame> stream_frames_; + vector<QuicRstStreamFrame> rst_stream_frames_; + vector<QuicGoAwayFrame> goaway_frames_; + vector<QuicConnectionCloseFrame> connection_close_frames_; + vector<string> stream_data_; + + DISALLOW_COPY_AND_ASSIGN(SimpleFramerVisitor); +}; + +SimpleQuicFramer::SimpleQuicFramer() + : framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)), + visitor_(NULL) { +} + +SimpleQuicFramer::~SimpleQuicFramer() { + delete visitor_; +} + +bool SimpleQuicFramer::ProcessPacket(const QuicPacket& packet) { + scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(0, packet)); + LOG(INFO) << __FUNCTION__ << encrypted.get(); + LOG(INFO) << __FUNCTION__ << encrypted->length(); + return ProcessPacket(*encrypted); +} + +bool SimpleQuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) { + delete visitor_; + visitor_ = new SimpleFramerVisitor; + framer_.set_visitor(visitor_); + return framer_.ProcessPacket(packet); +} + +const QuicPacketHeader& SimpleQuicFramer::header() const { + return visitor_->header(); +} + +const QuicFecData& SimpleQuicFramer::fec_data() const { + return visitor_->fec_data(); +} + +size_t SimpleQuicFramer::num_frames() const { + return ack_frames().size() + + stream_frames().size() + + feedback_frames().size() + + rst_stream_frames().size() + + goaway_frames().size() + + connection_close_frames().size(); +} + +const vector<QuicAckFrame>& SimpleQuicFramer::ack_frames() const { + return visitor_->ack_frames(); +} + +const vector<QuicStreamFrame>& SimpleQuicFramer::stream_frames() const { + return visitor_->stream_frames(); +} + +const vector<QuicRstStreamFrame>& SimpleQuicFramer::rst_stream_frames() const { + return visitor_->rst_stream_frames(); +} + +const vector<QuicCongestionFeedbackFrame>& +SimpleQuicFramer::feedback_frames() const { + return visitor_->feedback_frames(); +} + +const vector<QuicGoAwayFrame>& +SimpleQuicFramer::goaway_frames() const { + return visitor_->goaway_frames(); +} + +const vector<QuicConnectionCloseFrame>& +SimpleQuicFramer::connection_close_frames() const { + return visitor_->connection_close_frames(); +} + +} // namespace test +} // namespace net diff --git a/net/quic/test_tools/simple_quic_framer.h b/net/quic/test_tools/simple_quic_framer.h new file mode 100644 index 0000000..f794270 --- /dev/null +++ b/net/quic/test_tools/simple_quic_framer.h @@ -0,0 +1,55 @@ +// 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. + +#ifndef NET_QUIC_TEST_TOOLS_SIMPLE_QUIC_FRAMER_H_ +#define NET_QUIC_TEST_TOOLS_SIMPLE_QUIC_FRAMER_H_ + +#include <vector> + +#include "net/quic/quic_framer.h" +#include "net/quic/quic_protocol.h" + +namespace net { + +struct QuicAckFrame; +class QuicConnection; +class QuicConnectionVisitorInterface; +class QuicPacketCreator; +class ReceiveAlgorithmInterface; +class SendAlgorithmInterface; + +namespace test { + +class SimpleFramerVisitor; + +// Peer to make public a number of otherwise private QuicConnection methods. +class SimpleQuicFramer { + public: + SimpleQuicFramer(); + ~SimpleQuicFramer(); + + bool ProcessPacket(const QuicEncryptedPacket& packet); + bool ProcessPacket(const QuicPacket& packet); + + const QuicPacketHeader& header() const; + size_t num_frames() const; + const std::vector<QuicAckFrame>& ack_frames() const; + const std::vector<QuicConnectionCloseFrame>& connection_close_frames() const; + const std::vector<QuicCongestionFeedbackFrame>& feedback_frames() const; + const std::vector<QuicGoAwayFrame>& goaway_frames() const; + const std::vector<QuicRstStreamFrame>& rst_stream_frames() const; + const std::vector<QuicStreamFrame>& stream_frames() const; + const QuicFecData& fec_data() const; + + private: + QuicFramer framer_; + SimpleFramerVisitor* visitor_; + DISALLOW_COPY_AND_ASSIGN(SimpleQuicFramer); +}; + +} // namespace test + +} // namespace net + +#endif // NET_QUIC_TEST_TOOLS_SIMPLE_QUIC_FRAMER_H_ |