diff options
author | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-18 05:43:20 +0000 |
---|---|---|
committer | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-18 05:43:20 +0000 |
commit | c995c57ac3cbf7c29c56dd4aba5ab8d1ed54c73f (patch) | |
tree | efdaf02c88a1809609cb65488c75e27f31bb3cf2 /net/quic | |
parent | 736337679a839a57b9a39e2c0677d52a44e31dc6 (diff) | |
download | chromium_src-c995c57ac3cbf7c29c56dd4aba5ab8d1ed54c73f.zip chromium_src-c995c57ac3cbf7c29c56dd4aba5ab8d1ed54c73f.tar.gz chromium_src-c995c57ac3cbf7c29c56dd4aba5ab8d1ed54c73f.tar.bz2 |
Cleaning up constructors for QuicData, QuicPacket and QuicEncryptedPacket to not take unnamed bool values.
Merge internal change: 41194576
Simplify the interface between the QuicConnection and the congestion control system. Add a QuicCongestionManager to wrap the the SendScheduler and ReceiptMetricsCollector in a single class for all congestion-related functionality. (Narrows the SendScheduler-specific interface to just those methods called by the QuicConnection.) This is a minor cleanup in advance of moving the RTO management out of QuicConnection (since it is algorithm specific).
Merge internal change: 41188949
Refactor SendStreamData to frame one StreamFrame at once and send it, instea d of framing and serializing multiple in DataToStream.
Merge internal change: 41155771
Expand the 48 bit on-the-wire packet sequence number into the full 64 bit se quence number.
Merge internal change: 41147680
Enable encryption of private flags.
Merge internal change: 41147034
Splitting flags into private and public and implementing framing for both.
Merge internal change: 41145985
Add a zero length padding frame.
Merge internal change: 41141396
Remove "support" for PDUs
Merge internal change: 41133537
Remove the Clear method from QuicPacketCreator options, and explicitly initialize all field in the constructor.
Merge internal change: 41128100
Cleanup from chrome cl 11820003
Merge internal change: 41118012
Refactor to pull out connection close so that connection can be closed without sending connection close frame.
Merge internal change: 41026182
Keep a bool to check if a QuicPacket is an FEC packet instead of taking whol e packet flag as an input to the constructor.
Merge internal change: 41026127
Remove default constructors for QuicTime and QuicTime::Delta and used static Zero() methods instead to make it clear what value is being used. One annoying side-effect is this means that maps which have these objects as keys can't not be accessed with []. Thankfully, this is not a huge problem. (It only affects us in one place). But I can add the default constructors back to support this use case, if necessary. (I'd prefer not to since I think Zero() is more clear, but can go either way).
Merge internal change: 40993340
Replace boolean literals with named constants ini QuicConnection::SendPacket() calls.
Merge internal change: 40991762
Consistently use Retransmit/Retransmission (instead of Resend) when talking about sending QUIC data a second time (in a new packet).
Merge internal change: 40988697
Move the logic for RTO timeout handling from the Helper to the QuicConnection.
Merge internal change: 40980852
Fixing a bug where a non-existant frame corresponding to an FEC was being deleted.
Merge internal change: 40883214
Change the QUIC FEC group number from an ad-hoc id to the sequence number of the first packet in the group. Over the wire, however, send a 1 byte delta from the sequence number of the current packet to the sequence number of the first protected packet in the group.
Merge internal change: 40881017
TBR=jar@chromium.org
Review URL: https://chromiumcodereview.appspot.com/11959039
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@177612 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/quic')
51 files changed, 1535 insertions, 938 deletions
diff --git a/net/quic/congestion_control/cubic.cc b/net/quic/congestion_control/cubic.cc index 6ea46bd..c1faeb3 100644 --- a/net/quic/congestion_control/cubic.cc +++ b/net/quic/congestion_control/cubic.cc @@ -70,7 +70,9 @@ const uint32 cube_root_table[] = { } // namespace Cubic::Cubic(const QuicClock* clock) - : clock_(clock) { + : clock_(clock), + epoch_(QuicTime::Zero()), + last_update_time_(QuicTime::Zero()) { Reset(); } @@ -103,8 +105,8 @@ uint32 Cubic::CubeRoot(uint64 a) { } void Cubic::Reset() { - epoch_ = QuicTime(); // Reset time. - last_update_time_ = QuicTime(); // Reset time. + epoch_ = QuicTime::Zero(); // Reset time. + last_update_time_ = QuicTime::Zero(); // Reset time. last_congestion_window_ = 0; last_max_congestion_window_ = 0; acked_packets_count_ = 0; @@ -124,7 +126,7 @@ QuicTcpCongestionWindow Cubic::CongestionWindowAfterPacketLoss( } else { last_max_congestion_window_ = current_congestion_window; } - epoch_ = QuicTime(); // Reset time. + epoch_ = QuicTime::Zero(); // Reset time. return (current_congestion_window * kBeta) >> 10; } diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc index fc9b6c7..46ca0b5 100644 --- a/net/quic/congestion_control/fix_rate_sender.cc +++ b/net/quic/congestion_control/fix_rate_sender.cc @@ -51,21 +51,21 @@ void FixRateSender::OnIncomingLoss(int /*number_of_lost_packets*/) { void FixRateSender::SentPacket(QuicPacketSequenceNumber /*sequence_number*/, size_t bytes, - bool retransmit) { + bool is_retransmission) { fix_rate_leaky_bucket_.Add(bytes); paced_sender_.SentPacket(bytes); - if (!retransmit) { + if (!is_retransmission) { bytes_in_flight_ += bytes; } } -QuicTime::Delta FixRateSender::TimeUntilSend(bool /*retransmit*/) { +QuicTime::Delta FixRateSender::TimeUntilSend(bool /*is_retransmission*/) { if (CongestionWindow() > fix_rate_leaky_bucket_.BytesPending()) { if (CongestionWindow() <= bytes_in_flight_) { // We need an ack before we send more. return QuicTime::Delta::Infinite(); } - QuicTime::Delta zero_time; + QuicTime::Delta zero_time(QuicTime::Delta::Zero()); return paced_sender_.TimeUntilSend(zero_time); } QuicTime::Delta time_remaining = fix_rate_leaky_bucket_.TimeRemaining(); diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h index c81581c..146ea23 100644 --- a/net/quic/congestion_control/fix_rate_sender.h +++ b/net/quic/congestion_control/fix_rate_sender.h @@ -31,8 +31,8 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface { virtual void OnIncomingLoss(int number_of_lost_packets) OVERRIDE; virtual void SentPacket(QuicPacketSequenceNumber equence_number, size_t bytes, - bool retransmit) OVERRIDE; - virtual QuicTime::Delta TimeUntilSend(bool retransmit) OVERRIDE; + bool is_retransmission) OVERRIDE; + virtual QuicTime::Delta TimeUntilSend(bool is_retransmission) OVERRIDE; virtual size_t AvailableCongestionWindow() OVERRIDE; virtual int BandwidthEstimate() OVERRIDE; // End implementation of SendAlgorithmInterface. diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc index 5edabb0..6cb4956 100644 --- a/net/quic/congestion_control/fix_rate_test.cc +++ b/net/quic/congestion_control/fix_rate_test.cc @@ -34,7 +34,7 @@ class FixRateTest : public ::testing::Test { TEST_F(FixRateTest, ReceiverAPI) { QuicCongestionFeedbackFrame feedback; - QuicTime timestamp; + QuicTime timestamp(QuicTime::Zero()); receiver_->SetBitrate(300000); // Bytes per second. receiver_->RecordIncomingPacket(1, 1, timestamp, false); ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); @@ -75,7 +75,7 @@ TEST_F(FixRateTest, FixRatePacing) { receiver_->SetBitrate(240000); // Bytes per second. ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); sender_->OnIncomingQuicCongestionFeedbackFrame(feedback); - QuicTime acc_advance_time; + QuicTime acc_advance_time(QuicTime::Zero()); QuicPacketSequenceNumber sequence_number = 0; for (int i = 0; i < num_packets; i += 2) { EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); diff --git a/net/quic/congestion_control/hybrid_slow_start.cc b/net/quic/congestion_control/hybrid_slow_start.cc index dcd2e4a5..cbdd1bb 100644 --- a/net/quic/congestion_control/hybrid_slow_start.cc +++ b/net/quic/congestion_control/hybrid_slow_start.cc @@ -19,8 +19,11 @@ HybridSlowStart::HybridSlowStart(const QuicClock* clock) started_(false), found_ack_train_(false), found_delay_(false), + round_start_(QuicTime::Zero()), end_sequence_number_(0), - sample_count_(0) { + last_time_(QuicTime::Zero()), + sample_count_(0), + current_rtt_(QuicTime::Delta::Zero()) { } void HybridSlowStart::Restart() { @@ -32,7 +35,7 @@ void HybridSlowStart::Reset(QuicPacketSequenceNumber end_sequence_number) { DLOG(INFO) << "Reset hybrid slow start @" << end_sequence_number; round_start_ = last_time_ = clock_->Now(); end_sequence_number_ = end_sequence_number; - current_rtt_ = QuicTime::Delta(); // Reset to 0. + current_rtt_ = QuicTime::Delta::Zero(); sample_count_ = 0; started_ = true; } diff --git a/net/quic/congestion_control/leaky_bucket.cc b/net/quic/congestion_control/leaky_bucket.cc index d3dd513..60ec7a6 100644 --- a/net/quic/congestion_control/leaky_bucket.cc +++ b/net/quic/congestion_control/leaky_bucket.cc @@ -11,6 +11,7 @@ namespace net { LeakyBucket::LeakyBucket(const QuicClock* clock, int bytes_per_second) : clock_(clock), bytes_(0), + time_last_updated_(QuicTime::Zero()), draining_rate_bytes_per_s_(bytes_per_second) { } diff --git a/net/quic/congestion_control/paced_sender_test.cc b/net/quic/congestion_control/paced_sender_test.cc index c49f654..e93261b 100644 --- a/net/quic/congestion_control/paced_sender_test.cc +++ b/net/quic/congestion_control/paced_sender_test.cc @@ -18,7 +18,8 @@ const int kHundredKBytesPerS = 100000; class PacedSenderTest : public ::testing::Test { protected: PacedSenderTest() - : paced_sender_(new PacedSender(&clock_, kHundredKBytesPerS)) { + : zero_time_(QuicTime::Delta::Zero()), + paced_sender_(new PacedSender(&clock_, kHundredKBytesPerS)) { } const QuicTime::Delta zero_time_; diff --git a/net/quic/congestion_control/quic_congestion_manager.cc b/net/quic/congestion_control/quic_congestion_manager.cc new file mode 100644 index 0000000..8e300bb --- /dev/null +++ b/net/quic/congestion_control/quic_congestion_manager.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/congestion_control/quic_congestion_manager.h" + +#include "net/quic/congestion_control/quic_receipt_metrics_collector.h" +#include "net/quic/congestion_control/quic_send_scheduler.h" + +namespace net { + +QuicCongestionManager::QuicCongestionManager( + const QuicClock* clock, + CongestionFeedbackType type) + : collector_(new QuicReceiptMetricsCollector(clock, type)), + scheduler_(new QuicSendScheduler(clock, type)) { +} + +QuicCongestionManager::~QuicCongestionManager() { +} + +void QuicCongestionManager::SentPacket(QuicPacketSequenceNumber sequence_number, + size_t bytes, + bool is_retransmission) { + scheduler_->SentPacket(sequence_number, bytes, is_retransmission); +} + +void QuicCongestionManager::OnIncomingQuicCongestionFeedbackFrame( + const QuicCongestionFeedbackFrame& frame) { + scheduler_->OnIncomingQuicCongestionFeedbackFrame(frame); +} + +void QuicCongestionManager::OnIncomingAckFrame(const QuicAckFrame& frame) { + scheduler_->OnIncomingAckFrame(frame); +} + +QuicTime::Delta QuicCongestionManager::TimeUntilSend(bool is_retransmission) { + return scheduler_->TimeUntilSend(is_retransmission); +} + +bool QuicCongestionManager::GenerateCongestionFeedback( + QuicCongestionFeedbackFrame* feedback) { + return collector_->GenerateCongestionFeedback(feedback); +} + +void QuicCongestionManager::RecordIncomingPacket( + size_t bytes, + QuicPacketSequenceNumber sequence_number, + QuicTime timestamp, + bool revived) { + collector_->RecordIncomingPacket(bytes, sequence_number, timestamp, revived); +} + +} // namespace net diff --git a/net/quic/congestion_control/quic_congestion_manager.h b/net/quic/congestion_control/quic_congestion_manager.h new file mode 100644 index 0000000..9402213 --- /dev/null +++ b/net/quic/congestion_control/quic_congestion_manager.h @@ -0,0 +1,80 @@ +// 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. +// +// This is the interface from the QuicConnection into the QUIC +// congestion control code. It wraps the QuicSendScheduler and +// QuicReceiptMetricsCollector and provides a single interface +// for consumers. + +#ifndef NET_QUIC_CONGESTION_CONTROL_QUIC_CONGESTION_MANAGER_H_ +#define NET_QUIC_CONGESTION_CONTROL_QUIC_CONGESTION_MANAGER_H_ + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "net/quic/quic_protocol.h" + +namespace net { + +namespace test { +class QuicConnectionPeer; +} // namespace test + +class QuicClock; +class QuicReceiptMetricsCollector; +class QuicSendScheduler; + +class QuicCongestionManager { + public: + QuicCongestionManager(const QuicClock* clock, + CongestionFeedbackType congestion_type); + virtual ~QuicCongestionManager(); + + // Called when we have received an ack frame from peer. + virtual void OnIncomingAckFrame(const QuicAckFrame& frame); + + // Called when a congestion feedback frame is received from peer. + virtual void OnIncomingQuicCongestionFeedbackFrame( + const QuicCongestionFeedbackFrame& frame); + + // 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, + size_t bytes, + bool is_retransmission); + + // Calculate the time until we can send the next packet to the wire. + // Note 1: When kUnknownWaitTime is returned, there is no need to poll + // 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); + + // Should be called before sending an ACK packet, to decide if we need + // to attach a QuicCongestionFeedbackFrame block. + // Returns false if no QuicCongestionFeedbackFrame block is needed. + // Otherwise fills in feedback and returns true. + virtual bool GenerateCongestionFeedback( + QuicCongestionFeedbackFrame* feedback); + + // Should be called for each incoming packet. + // bytes: the packet size in bytes including IP headers. + // sequence_number: the unique sequence number from the QUIC packet header. + // timestamp: the arrival time of the packet. + // revived: true if the packet was lost and then recovered with help of a + // FEC packet. + virtual void RecordIncomingPacket(size_t bytes, + QuicPacketSequenceNumber sequence_number, + QuicTime timestamp, + bool revived); + + private: + friend class test::QuicConnectionPeer; + + scoped_ptr<QuicReceiptMetricsCollector> collector_; + scoped_ptr<QuicSendScheduler> scheduler_; +}; + +} // namespace net + +#endif // NET_QUIC_CONGESTION_CONTROL_QUIC_CONGESTION_MANAGER_H_ diff --git a/net/quic/congestion_control/quic_receipt_metrics_collector.h b/net/quic/congestion_control/quic_receipt_metrics_collector.h index dbd3c3c..d985cff 100644 --- a/net/quic/congestion_control/quic_receipt_metrics_collector.h +++ b/net/quic/congestion_control/quic_receipt_metrics_collector.h @@ -27,19 +27,18 @@ class NET_EXPORT_PRIVATE QuicReceiptMetricsCollector { virtual ~QuicReceiptMetricsCollector(); - // Should be called for each ACK packet to decide if we need to attach a - // QuicCongestionFeedbackFrame block. + // Should be called before sending an ACK packet, to decide if we need + // to attach a QuicCongestionFeedbackFrame block. // Returns false if no QuicCongestionFeedbackFrame block is needed. - // Otherwise fills in feedback and return true. + // Otherwise fills in feedback and returns true. virtual bool GenerateCongestionFeedback( QuicCongestionFeedbackFrame* feedback); // Should be called for each incoming packet. - // bytes: is the packet size in bytes including IP headers. - // sequence_number: is the unique sequence number from the QUIC packet header. - // timestamp: is the sent timestamp from the QUIC packet header. - // TODO(pwestin) which type should we use for timestamp? - // revived: is set if the packet is lost and then recovered with help of a + // bytes: the packet size in bytes including IP headers. + // sequence_number: the unique sequence number from the QUIC packet header. + // timestamp: the arrival time of the packet. + // revived: true if the packet was lost and then recovered with help of a // FEC packet. virtual void RecordIncomingPacket(size_t bytes, QuicPacketSequenceNumber sequence_number, diff --git a/net/quic/congestion_control/quic_receipt_metrics_collector_test.cc b/net/quic/congestion_control/quic_receipt_metrics_collector_test.cc index 52f661c..891fcba 100644 --- a/net/quic/congestion_control/quic_receipt_metrics_collector_test.cc +++ b/net/quic/congestion_control/quic_receipt_metrics_collector_test.cc @@ -24,7 +24,7 @@ class QuicReceiptMetricsCollectorTest : public ::testing::Test { TEST_F(QuicReceiptMetricsCollectorTest, FixedRateReceiverAPI) { SetUpCongestionType(kFixRate); QuicCongestionFeedbackFrame feedback; - QuicTime timestamp; + QuicTime timestamp(QuicTime::Zero()); receiver_->RecordIncomingPacket(1, 1, timestamp, false); ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); EXPECT_EQ(kFixRate, feedback.type); diff --git a/net/quic/congestion_control/quic_send_scheduler.cc b/net/quic/congestion_control/quic_send_scheduler.cc index 7b30ee0..ba18c96 100644 --- a/net/quic/congestion_control/quic_send_scheduler.cc +++ b/net/quic/congestion_control/quic_send_scheduler.cc @@ -67,11 +67,11 @@ int QuicSendScheduler::UpdatePacketHistory() { void QuicSendScheduler::SentPacket(QuicPacketSequenceNumber sequence_number, size_t bytes, - bool retransmit) { + bool is_retransmission) { int bucket = UpdatePacketHistory(); packet_history_[bucket] += bytes; - send_algorithm_->SentPacket(sequence_number, bytes, retransmit); - if (!retransmit) { + send_algorithm_->SentPacket(sequence_number, bytes, is_retransmission); + if (!is_retransmission) { pending_packets_[sequence_number] = new PendingPacket(bytes, clock_->Now()); } @@ -125,8 +125,8 @@ void QuicSendScheduler::OnIncomingAckFrame(const QuicAckFrame& ack_frame) { } } -QuicTime::Delta QuicSendScheduler::TimeUntilSend(bool retransmit) { - return send_algorithm_->TimeUntilSend(retransmit); +QuicTime::Delta QuicSendScheduler::TimeUntilSend(bool is_retransmission) { + return send_algorithm_->TimeUntilSend(is_retransmission); } size_t QuicSendScheduler::AvailableCongestionWindow() { diff --git a/net/quic/congestion_control/quic_send_scheduler.h b/net/quic/congestion_control/quic_send_scheduler.h index 66324ae..c5f1c83 100644 --- a/net/quic/congestion_control/quic_send_scheduler.h +++ b/net/quic/congestion_control/quic_send_scheduler.h @@ -54,25 +54,25 @@ class NET_EXPORT_PRIVATE QuicSendScheduler { CongestionFeedbackType congestion_type); virtual ~QuicSendScheduler(); - // Called when we have received an ack frame from remote peer. - virtual void OnIncomingAckFrame(const QuicAckFrame& ack_frame); + // Called when we have received an ack frame from peer. + virtual void OnIncomingAckFrame(const QuicAckFrame& frame); - // Called when we have received an congestion feedback frame from remote peer. + // Called when a congestion feedback frame is received from peer. virtual void OnIncomingQuicCongestionFeedbackFrame( - const QuicCongestionFeedbackFrame& congestion_feedback_frame); + const QuicCongestionFeedbackFrame& frame); - // Inform that we sent x bytest to the wire, and if that was a retransmission. - // Note: this function must be called for every packet sent to the wire. + // 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, size_t bytes, - bool retransmit); + bool is_retransmission); // Calculate the time until we can send the next packet to the wire. // Note 1: When kUnknownWaitTime is returned, there is no need to poll // 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 retransmit); + virtual QuicTime::Delta TimeUntilSend(bool is_retransmission); // Returns the current available congestion window in bytes, the number of // bytes that can be sent now. diff --git a/net/quic/congestion_control/quic_send_scheduler_test.cc b/net/quic/congestion_control/quic_send_scheduler_test.cc index f28a6db..a59c0e7 100644 --- a/net/quic/congestion_control/quic_send_scheduler_test.cc +++ b/net/quic/congestion_control/quic_send_scheduler_test.cc @@ -54,7 +54,7 @@ TEST_F(QuicSendSchedulerTest, FixedRatePacing) { feedback.fix_rate.bitrate_in_bytes_per_second = 100000; sender_->OnIncomingQuicCongestionFeedbackFrame(feedback); - QuicTime acc_advance_time; + QuicTime acc_advance_time(QuicTime::Zero()); for (int i = 1; i <= 100; ++i) { EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); EXPECT_EQ(kMaxPacketSize, sender_->AvailableCongestionWindow()); @@ -174,7 +174,7 @@ TEST_F(QuicSendSchedulerTest, Pacing) { feedback.fix_rate.bitrate_in_bytes_per_second = 1000000; sender_->OnIncomingQuicCongestionFeedbackFrame(feedback); - QuicTime acc_advance_time; + QuicTime acc_advance_time(QuicTime::Zero()); for (int i = 1; i <= 100;) { EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero()); EXPECT_EQ(kMaxPacketSize * 2, sender_->AvailableCongestionWindow()); diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h index 5590d49..63aef3a 100644 --- a/net/quic/congestion_control/send_algorithm_interface.h +++ b/net/quic/congestion_control/send_algorithm_interface.h @@ -39,12 +39,12 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface { // Note: this function must be called for every packet sent to the wire. virtual void SentPacket(QuicPacketSequenceNumber sequence_number, size_t bytes, - bool retransmit) = 0; + 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 retransmit) = 0; + virtual QuicTime::Delta TimeUntilSend(bool is_retransmission) = 0; // The current available congestion window in bytes. virtual size_t AvailableCongestionWindow() = 0; diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc index 7aab66c..001fff5 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.cc +++ b/net/quic/congestion_control/tcp_cubic_sender.cc @@ -30,7 +30,7 @@ TcpCubicSender::TcpCubicSender(const QuicClock* clock, bool reno) end_sequence_number_(0), congestion_window_(kInitialCongestionWindow), slowstart_threshold_(kMaxCongestionWindow), - delay_min_() { + delay_min_(QuicTime::Delta::Zero()) { } void TcpCubicSender::OnIncomingQuicCongestionFeedbackFrame( @@ -81,11 +81,12 @@ void TcpCubicSender::OnIncomingLoss(int /*number_of_lost_packets*/) { } void TcpCubicSender::SentPacket(QuicPacketSequenceNumber sequence_number, - size_t bytes, bool retransmit) { - if (!retransmit) { + size_t bytes, + bool is_retransmission) { + if (!is_retransmission) { bytes_in_flight_ += bytes; } - if (!retransmit && update_end_sequence_number_) { + if (!is_retransmission && update_end_sequence_number_) { end_sequence_number_ = sequence_number; if (AvailableCongestionWindow() == 0) { update_end_sequence_number_ = false; @@ -94,15 +95,15 @@ void TcpCubicSender::SentPacket(QuicPacketSequenceNumber sequence_number, } } -QuicTime::Delta TcpCubicSender::TimeUntilSend(bool retransmit) { - if (retransmit) { - // For TCP we can always send a retransmit immediately. - return QuicTime::Delta(); +QuicTime::Delta TcpCubicSender::TimeUntilSend(bool is_retransmission) { + if (is_retransmission) { + // For TCP we can always send a retransmission immediately. + return QuicTime::Delta::Zero(); } if (AvailableCongestionWindow() == 0) { return QuicTime::Delta::Infinite(); } - return QuicTime::Delta(); + return QuicTime::Delta::Zero(); } size_t TcpCubicSender::AvailableCongestionWindow() { @@ -126,7 +127,7 @@ int TcpCubicSender::BandwidthEstimate() { } void TcpCubicSender::Reset() { - delay_min_ = QuicTime::Delta(); // Reset to 0. + delay_min_ = QuicTime::Delta::Zero(); hybrid_slow_start_.Restart(); } diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h index bb2fe06..628ff56 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.h +++ b/net/quic/congestion_control/tcp_cubic_sender.h @@ -33,8 +33,8 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { virtual void OnIncomingLoss(int number_of_lost_packets) OVERRIDE; virtual void SentPacket(QuicPacketSequenceNumber sequence_number, size_t bytes, - bool retransmit) OVERRIDE; - virtual QuicTime::Delta TimeUntilSend(bool retransmit) OVERRIDE; + bool is_retransmission) OVERRIDE; + virtual QuicTime::Delta TimeUntilSend(bool is_retransmission) OVERRIDE; virtual size_t AvailableCongestionWindow() OVERRIDE; virtual int BandwidthEstimate() OVERRIDE; // End implementation of SendAlgorithmInterface. diff --git a/net/quic/congestion_control/tcp_receiver_test.cc b/net/quic/congestion_control/tcp_receiver_test.cc index 6fb2a82..1d4a2bb 100644 --- a/net/quic/congestion_control/tcp_receiver_test.cc +++ b/net/quic/congestion_control/tcp_receiver_test.cc @@ -21,7 +21,7 @@ class QuicTcpReceiverTest : public ::testing::Test { TEST_F(QuicTcpReceiverTest, SimpleReceiver) { QuicCongestionFeedbackFrame feedback; - QuicTime timestamp; + QuicTime timestamp(QuicTime::Zero()); receiver_->RecordIncomingPacket(1, 1, timestamp, false); ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback)); EXPECT_EQ(kTCP, feedback.type); diff --git a/net/quic/crypto/crypto_protocol.cc b/net/quic/crypto/crypto_protocol.cc index 993a4d2..e9220ec 100644 --- a/net/quic/crypto/crypto_protocol.cc +++ b/net/quic/crypto/crypto_protocol.cc @@ -9,7 +9,10 @@ namespace net { CryptoHandshakeMessage::CryptoHandshakeMessage() {} CryptoHandshakeMessage::~CryptoHandshakeMessage() {} -QuicClientCryptoConfig::QuicClientCryptoConfig() : version(0) { +QuicClientCryptoConfig::QuicClientCryptoConfig() + : version(0), + idle_connection_state_lifetime(QuicTime::Delta::Zero()), + keepalive_timeout(QuicTime::Delta::Zero()) { } QuicClientCryptoConfig::~QuicClientCryptoConfig() {} @@ -36,7 +39,7 @@ void QuicClientCryptoConfig::SetDefaults() { idle_connection_state_lifetime = QuicTime::Delta::FromMilliseconds(300000); // Keepalive timeout. - keepalive_timeout = QuicTime::Delta(); // Don't send keepalive probes. + keepalive_timeout = QuicTime::Delta::Zero(); // Don't send keepalive probes. } } // namespace net diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index debc017..bf09e91 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -27,6 +27,8 @@ namespace net { // TODO(pwestin): kDefaultTimeoutUs is in int64. int32 kNegotiatedTimeoutUs = kDefaultTimeoutUs; +namespace { + // The largest gap in packets we'll accept without closing the connection. // This will likely have to be tuned. const QuicPacketSequenceNumber kMaxPacketGap = 5000; @@ -35,29 +37,37 @@ const QuicPacketSequenceNumber kMaxPacketGap = 5000; // without exceeding kMaxPacketSize. const QuicPacketSequenceNumber kMaxUnackedPackets = 192u; -// The amount of time we wait before resending a packet. -const int64 kDefaultResendTimeMs = 500; - // 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. -const int kMaxResendPerAck = 10; +const int kMaxRetransmissionsPerAck = 10; -// TCP resends after 2 nacks. We allow for a third in case of out-of-order +// TCP retransmits after 2 nacks. We allow for a third in case of out-of-order // delivery. -// TODO(ianswett): Change to match TCP's rule of resending once an ack at least -// 3 sequence numbers larger arrives. -const int kNumberOfNacksBeforeResend = 3; +// TODO(ianswett): Change to match TCP's rule of retransmitting once an ack +// at least 3 sequence numbers larger arrives. +const int kNumberOfNacksBeforeRetransmission = 3; // The maxiumum number of packets we'd like to queue. We may end up queueing // more in the case of many control frames. // 6 is arbitrary. const int kMaxPacketsToSerializeAtOnce = 6; +// Limit the number of packets we send per retransmission-alarm so we +// eventually cede. 10 is arbitrary. +const int kMaxPacketsPerRetransmissionAlarm = 10; + +// Named constants for SendPacket options. +const bool kForce = true; +const bool kShouldRetransmit = true; +const bool kIsRetransmission = true; + bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) { QuicPacketSequenceNumber delta = (a > b) ? a - b : b - a; return delta <= kMaxPacketGap; } +} // namespace + QuicConnection::UnackedPacket::UnackedPacket(QuicFrames unacked_frames) : frames(unacked_frames), number_nacks(0) { @@ -87,16 +97,15 @@ QuicConnection::QuicConnection(QuicGuid guid, largest_seen_packet_with_ack_(0), peer_largest_observed_packet_(0), peer_least_packet_awaiting_ack_(0), + handling_retransmission_timeout_(false), write_blocked_(false), packet_creator_(guid_, &framer_), timeout_(QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs)), time_of_last_packet_(clock_->Now()), - collector_(new QuicReceiptMetricsCollector(clock_, kTCP)), - scheduler_(new QuicSendScheduler(clock_, kTCP)), + congestion_manager_(clock_, kTCP), connected_(true), received_truncated_ack_(false), send_ack_in_response_to_packet_(false) { - options()->max_num_packets = kMaxPacketsToSerializeAtOnce; helper_->SetConnection(this); helper_->SetTimeoutAlarm(timeout_); framer_.set_visitor(this); @@ -128,6 +137,9 @@ 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; @@ -143,7 +155,6 @@ void QuicConnection::DeleteEnclosedFrame(QuicFrame* frame) { case CONNECTION_CLOSE_FRAME: delete frame->connection_close_frame; break; - case PDU_FRAME: // Fall through. case NUM_FRAME_TYPES: DCHECK(false) << "Cannot delete type: " << frame->type; } @@ -152,12 +163,12 @@ void QuicConnection::DeleteEnclosedFrame(QuicFrame* frame) { void QuicConnection::DeleteUnackedPacket(UnackedPacket* unacked) { for (QuicFrames::iterator it = unacked->frames.begin(); it != unacked->frames.end(); ++it) { - DCHECK(ShouldResend(*it)); + DCHECK(ShouldRetransmit(*it)); DeleteEnclosedFrame(&(*it)); } } -bool QuicConnection::ShouldResend(const QuicFrame& frame) { +bool QuicConnection::ShouldRetransmit(const QuicFrame& frame) { return frame.type != ACK_FRAME && frame.type != CONGESTION_FEEDBACK_FRAME; } @@ -188,7 +199,7 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { } // If this packet has already been seen, or that the sender - // has told us will not be resent, then stop processing the packet. + // has told us will not be retransmitted, then stop processing the packet. if (!outgoing_ack_.received_info.IsAwaitingPacket( header.packet_sequence_number)) { return false; @@ -199,7 +210,7 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { } void QuicConnection::OnFecProtectedPayload(StringPiece payload) { - DCHECK_NE(0, last_header_.fec_group); + DCHECK_NE(0u, last_header_.fec_group); QuicFecGroup* group = GetFecGroup(); group->Update(last_header_, payload); } @@ -227,14 +238,14 @@ void QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) { UpdatePacketInformationReceivedByPeer(incoming_ack); UpdatePacketInformationSentByPeer(incoming_ack); - scheduler_->OnIncomingAckFrame(incoming_ack); + congestion_manager_.OnIncomingAckFrame(incoming_ack); // Now the we have received an ack, we might be able to send queued packets. if (queued_packets_.empty()) { return; } - QuicTime::Delta delay = scheduler_->TimeUntilSend(false); + QuicTime::Delta delay = congestion_manager_.TimeUntilSend(false); if (delay.IsZero()) { helper_->UnregisterSendAlarmIfRegistered(); if (!write_blocked_) { @@ -247,7 +258,7 @@ void QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) { void QuicConnection::OnCongestionFeedbackFrame( const QuicCongestionFeedbackFrame& feedback) { - scheduler_->OnIncomingQuicCongestionFeedbackFrame(feedback); + congestion_manager_.OnIncomingQuicCongestionFeedbackFrame(feedback); } bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) { @@ -309,7 +320,7 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer( packet_creator_.sequence_number() + 1, peer_largest_observed_packet_ + 1); - int resent_packets = 0; + 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. @@ -323,7 +334,8 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer( // 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 resend had been attempted). + // 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 == it->first) { @@ -338,7 +350,7 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer( ++it; unacked_packets_.erase(it_tmp); } else { - // This is a packet which we planned on resending and has not been + // This is a packet which we planned on retransmitting and has not been // seen at the time of this ack being sent out. See if it's our new // lowest unacked packet. DVLOG(1) << "still missing " << it->first; @@ -347,24 +359,24 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer( } // Determine if this packet is being explicitly nacked and, if so, if it - // is worth resending. - QuicPacketSequenceNumber resend_number = 0; + // is worth retransmitting. + QuicPacketSequenceNumber retransmission_number = 0; if (it->first < peer_largest_observed_packet_) { // The peer got packets after this sequence number. This is an explicit // nack. ++(it->second->number_nacks); - if (it->second->number_nacks >= kNumberOfNacksBeforeResend && - resent_packets < kMaxResendPerAck) { - resend_number = it->first; + if (it->second->number_nacks >= kNumberOfNacksBeforeRetransmission && + retransmitted_packets < kMaxRetransmissionsPerAck) { + retransmission_number = it->first; } } ++it; - if (resend_number > 0) { - ++resent_packets; - DVLOG(1) << "Trying to resend packet " << resend_number + if (retransmission_number > 0) { + ++retransmitted_packets; + DVLOG(1) << "Trying to retransmit packet " << retransmission_number << " as it has been nacked 3 or more times."; - MaybeResendPacket(resend_number); + MaybeRetransmitPacket(retransmission_number); } } } @@ -376,7 +388,7 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer( 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 resend. + // 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; } @@ -412,7 +424,7 @@ void QuicConnection::UpdatePacketInformationSentByPeer( } void QuicConnection::OnFecData(const QuicFecData& fec) { - DCHECK_NE(0, last_header_.fec_group); + DCHECK_NE(0u, last_header_.fec_group); QuicFecGroup* group = GetFecGroup(); group->UpdateFec(last_header_.packet_sequence_number, fec); } @@ -427,16 +439,15 @@ void QuicConnection::OnConnectionCloseFrame( const QuicConnectionCloseFrame& frame) { DLOG(INFO) << "Connection closed with error " << QuicUtils::ErrorToString(frame.error_code); - connected_ = false; - visitor_->ConnectionClose(frame.error_code, true); + CloseConnection(frame.error_code, true); } void QuicConnection::OnPacketComplete() { if (!last_packet_revived_) { DLOG(INFO) << "Got packet " << last_header_.packet_sequence_number << " with " << last_stream_frames_.size() - << " stream frames for " << last_header_.guid; - collector_->RecordIncomingPacket(last_size_, + << " stream frames for " << last_header_.public_header.guid; + congestion_manager_.RecordIncomingPacket(last_size_, last_header_.packet_sequence_number, clock_->Now(), last_packet_revived_); @@ -461,8 +472,7 @@ void QuicConnection::MaybeSendAckInResponseToPacket() { } else if (!last_stream_frames_.empty()) { // TODO(alyssar) this case should really be "if the packet contained any // non-ack frame", rather than "if the packet contained a stream frame" - helper_->SetAckAlarm( - QuicTime::Delta::FromMicroseconds(kDefaultResendTimeMs)); + helper_->SetAckAlarm(DefaultRetransmissionTime()); } send_ack_in_response_to_packet_ = !send_ack_in_response_to_packet_; } @@ -471,46 +481,37 @@ QuicConsumedData QuicConnection::SendStreamData( QuicStreamId id, StringPiece data, QuicStreamOffset offset, - bool fin, - QuicPacketSequenceNumber* last_packet) { + bool fin) { size_t total_bytes_consumed = 0; bool fin_consumed = false; + packet_creator_.MaybeStartFEC(); while (queued_packets_.empty()) { - vector<PacketPair> packets; QuicFrames frames; size_t bytes_consumed = - packet_creator_.DataToStream(id, data, offset, fin, &packets, &frames); + packet_creator_.CreateStreamFrame(id, data, offset, fin, &frames); total_bytes_consumed += bytes_consumed; offset += bytes_consumed; fin_consumed = fin && bytes_consumed == data.size(); data.remove_prefix(bytes_consumed); - DCHECK_LT(0u, packets.size()); - - for (size_t i = 0; i < packets.size(); ++i) { - // Resend is false for FEC packets. - bool should_resend = !packets[i].second->IsFecPacket(); - SendPacket(packets[i].first, - packets[i].second, - should_resend, - false, - false); - if (should_resend) { - QuicFrames unacked_frames; - unacked_frames.push_back(frames[i]); - UnackedPacket* unacked = new UnackedPacket( - unacked_frames, frames[i].stream_frame->data.as_string()); - // Ensure the string piece points to the owned copy of the data. - unacked->frames[0].stream_frame->data = StringPiece(unacked->data); - unacked_packets_.insert(make_pair(packets[i].first, unacked)); - } else { - DeleteEnclosedFrame(&frames[i]); - } - } - if (last_packet != NULL) { - *last_packet = packets[packets.size() - 1].first; + PacketPair pair = packet_creator_.SerializeAllFrames(frames); + // TODO(ianswett): Restore packet reordering. + SendPacket(pair.first, pair.second, kShouldRetransmit, !kForce, + !kIsRetransmission); + UnackedPacket* unacked = new UnackedPacket( + frames, frames[0].stream_frame->data.as_string()); + // Ensure the string piece points to the owned copy of the data. + unacked->frames[0].stream_frame->data = StringPiece(unacked->data); + unacked_packets_.insert(make_pair(pair.first, unacked)); + + if (packet_creator_.ShouldSendFec(data.size() == 0)) { + PacketPair fec_pair = packet_creator_.SerializeFec(); + // Never resend FEC packets. + SendPacket(fec_pair.first, fec_pair.second, !kShouldRetransmit, !kForce, + !kIsRetransmission); } + if (data.size() == 0) { // We're done writing the data. Exit the loop. // We don't make this a precondition beacuse we could have 0 bytes of data @@ -561,7 +562,7 @@ bool QuicConnection::OnCanWrite() { // 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. - helper_->SetSendAlarm(QuicTime::Delta()); + helper_->SetSendAlarm(QuicTime::Delta::Zero()); } } @@ -581,11 +582,12 @@ bool QuicConnection::WriteData() { size_t num_serialized; PacketPair pair = packet_creator_.SerializeFrames( queued_control_frames_, &num_serialized); - // If any serialized frames need to be resent, add them to unacked_packets. + // If any serialized frames need to be retransmitted, add them to + // unacked_packets. QuicFrames unacked_frames; for (QuicFrames::const_iterator iter = queued_control_frames_.begin(); iter != queued_control_frames_.begin() + num_serialized; ++iter) { - if (ShouldResend(*iter)) { + if (ShouldRetransmit(*iter)) { unacked_frames.push_back(*iter); } } @@ -612,7 +614,8 @@ bool QuicConnection::WriteData() { num_queued_packets = queued_packets_.size(); QueuedPacket p = queued_packets_.front(); queued_packets_.pop_front(); - SendPacket(p.sequence_number, p.packet, p.resend, false, p.retransmit); + SendPacket(p.sequence_number, p.packet, p.should_retransmit, !kForce, + p.is_retransmission); } return !write_blocked_; @@ -624,7 +627,7 @@ void QuicConnection::RecordPacketReceived(const QuicPacketHeader& header) { outgoing_ack_.received_info.RecordReceived(sequence_number); } -bool QuicConnection::MaybeResendPacketForRTO( +bool QuicConnection::MaybeRetransmitPacketForRTO( QuicPacketSequenceNumber sequence_number) { // If the packet hasn't been acked and we're getting truncated acks, ignore // any RTO for packets larger than the peer's largest observed packet; it may @@ -635,12 +638,12 @@ bool QuicConnection::MaybeResendPacketForRTO( ContainsKey(unacked_packets_, sequence_number)) { return false; } else { - MaybeResendPacket(sequence_number); + MaybeRetransmitPacket(sequence_number); return true; } } -void QuicConnection::MaybeResendPacket( +void QuicConnection::MaybeRetransmitPacket( QuicPacketSequenceNumber sequence_number) { UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number); @@ -648,30 +651,31 @@ void QuicConnection::MaybeResendPacket( UnackedPacket* unacked = it->second; // TODO(ianswett): Never change the sequence number of the connect packet. unacked_packets_.erase(it); - // Re-packetize the frames with a new sequence number for resend. - // Resent data packets do not use FEC, even when it's enabled. + // 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); - DVLOG(1) << "Resending unacked packet " << sequence_number << " as " + 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); - SendPacket(packetpair.first, packetpair.second, true, false, true); + SendPacket(packetpair.first, packetpair.second, kShouldRetransmit, + !kForce, kIsRetransmission); } else { DVLOG(2) << "alarm fired for " << sequence_number << " but it has been acked"; } } -bool QuicConnection::CanWrite(bool is_retransmit) { +bool QuicConnection::CanWrite(bool is_retransmission) { // TODO(ianswett): If the packet is a retransmit, the current send alarm may // be too long. if (write_blocked_ || helper_->IsSendAlarmSet()) { return false; } - QuicTime::Delta delay = scheduler_->TimeUntilSend(is_retransmit); + QuicTime::Delta delay = congestion_manager_.TimeUntilSend(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() seperately. @@ -683,21 +687,31 @@ bool QuicConnection::CanWrite(bool is_retransmit) { bool QuicConnection::SendPacket(QuicPacketSequenceNumber sequence_number, QuicPacket* packet, - bool should_resend, + bool should_retransmit, bool force, - bool is_retransmit) { + bool is_retransmission) { // If this packet is being forced, don't bother checking to see if we should // write, just write. if (!force) { // If we can't write, then simply queue the packet. - if (!CanWrite(is_retransmit)) { + if (!CanWrite(is_retransmission)) { queued_packets_.push_back( - QueuedPacket(sequence_number, packet, should_resend, is_retransmit)); + QueuedPacket(sequence_number, packet, should_retransmit, + is_retransmission)); return false; } } - if (should_resend) { - helper_->SetResendAlarm(sequence_number, DefaultResendTime()); + if (should_retransmit) { + // Do not set the retransmisson alarm if we're already handling the + // retransmission alarm because the retransmission alarm will be reset when + // OnRetransmissionTimeout completes. + if (!handling_retransmission_timeout_) { + helper_->SetRetransmissionAlarm(DefaultRetransmissionTime()); + } + retransmission_timeouts_.push_back( + make_pair(sequence_number, clock_->Now().Add( + DefaultRetransmissionTime()))); + // 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 || @@ -709,7 +723,8 @@ bool QuicConnection::SendPacket(QuicPacketSequenceNumber sequence_number, scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*packet)); int error; DLOG(INFO) << "Sending packet : " - << (should_resend ? "data bearing " : " ack only ") + << (packet->is_fec_packet() ? "FEC " : + (should_retransmit ? "data bearing " : " ack only ")) << "packet " << sequence_number; DCHECK(encrypted->length() <= kMaxPacketSize) << "Packet " << sequence_number << " will not be read; too large: " @@ -724,7 +739,8 @@ bool QuicConnection::SendPacket(QuicPacketSequenceNumber sequence_number, // UDP sockets. /* queued_packets_.push_front( - QueuedPacket(sequence_number, packet, should_resend, is_retransmit)); + QueuedPacket(sequence_number, packet, should_retransmit, + is_retransmission)); */ return false; } @@ -734,7 +750,8 @@ bool QuicConnection::SendPacket(QuicPacketSequenceNumber sequence_number, time_of_last_packet_ = clock_->Now(); DVLOG(1) << "last packet: " << time_of_last_packet_.ToMicroseconds(); - scheduler_->SentPacket(sequence_number, packet->length(), is_retransmit); + congestion_manager_.SentPacket(sequence_number, packet->length(), + is_retransmission); delete packet; return true; } @@ -753,7 +770,7 @@ void QuicConnection::SendAck() { 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 resend. Make sure we update it. + // packet we will not retransmit. Make sure we update it. UpdateLeastUnacked(outgoing_ack_.sent_info.least_unacked); } @@ -761,7 +778,8 @@ void QuicConnection::SendAck() { should_send_ack_ = true; - if (collector_->GenerateCongestionFeedback(&outgoing_congestion_feedback_)) { + if (congestion_manager_.GenerateCongestionFeedback( + &outgoing_congestion_feedback_)) { DVLOG(1) << "Sending feedback " << outgoing_congestion_feedback_; should_send_congestion_feedback_ = true; } @@ -771,6 +789,46 @@ void QuicConnection::SendAck() { } } +QuicTime QuicConnection::OnRetransmissionTimeout() { + // This guards against registering the alarm later than we should. + // + // If we have packet A and B in the list and we call + // MaybeRetransmitPacketForRTO on A, that may trigger a call to + // SetRetransmissionAlarm if A is retransmitted as C. In that case we + // don't want to register the alarm under SetRetransmissionAlarm; we + // want to set it to the RTO of B when we return from this function. + handling_retransmission_timeout_ = true; + + for (int i = 0; i < kMaxPacketsPerRetransmissionAlarm; ++i) { + if (retransmission_timeouts_.empty() || + retransmission_timeouts_.front().second > clock_->Now()) { + break; + } + if (!MaybeRetransmitPacketForRTO(retransmission_timeouts_.front().first)) { + DLOG(INFO) << "MaybeRetransmitPacketForRTO failed: " + << "adding an extra delay."; + // This implicitly delays the RTO for all subsequent packets, since + // MaybeRetransmitPacketForRTO will return false for all packets with + // a larger sequence number anyway. + retransmission_timeouts_.front().second = + retransmission_timeouts_.front().second.Add( + DefaultRetransmissionTime()); + break; + } + retransmission_timeouts_.pop_front(); + } + + handling_retransmission_timeout_ = false; + + if (retransmission_timeouts_.empty()) { + return QuicTime::FromMilliseconds(0); + } + + // We have packets remaining. Return the absolute RTO of the oldest packet + // on the list. + return retransmission_timeouts_.front().second; +} + void QuicConnection::MaybeProcessRevivedPacket() { QuicFecGroup* group = GetFecGroup(); if (group == NULL || !group->CanRevive()) { @@ -809,10 +867,17 @@ void QuicConnection::SendConnectionClose(QuicErrorCode error) { frame.ack_frame = outgoing_ack_; PacketPair packetpair = packet_creator_.CloseConnection(&frame); - // There's no point in resending this: we're closing the connection. - SendPacket(packetpair.first, packetpair.second, false, true, false); + // There's no point in retransmitting this: we're closing the connection. + SendPacket(packetpair.first, packetpair.second, !kShouldRetransmit, kForce, + !kIsRetransmission); + CloseConnection(error, false); +} + +void QuicConnection::CloseConnection(QuicErrorCode error, bool from_peer) { + // TODO(satyamshekhar): Ask the dispatcher to delete visitor and hence self + // if the visitor will always be deleted by closing the connection. connected_ = false; - visitor_->ConnectionClose(error, false); + visitor_->ConnectionClose(error, from_peer); } void QuicConnection::CloseFecGroupsBefore( diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index 1e3bf81..6515e01 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -22,6 +22,7 @@ #include "base/hash_tables.h" #include "net/base/ip_endpoint.h" +#include "net/quic/congestion_control/quic_congestion_manager.h" #include "net/quic/quic_fec_group.h" #include "net/quic/quic_framer.h" #include "net/quic/quic_packet_creator.h" @@ -34,8 +35,6 @@ class QuicConnection; class QuicEncrypter; class QuicFecGroup; class QuicRandom; -class QuicReceiptMetricsCollector; -class QuicSendScheduler; namespace test { class QuicConnectionPeer; @@ -93,12 +92,12 @@ class NET_EXPORT_PRIVATE QuicConnectionHelperInterface { virtual int WritePacketToWire(const QuicEncryptedPacket& packet, int* error) = 0; - // Sets up an alarm to resend the packet with the given sequence number if we - // haven't gotten an ack in the expected time frame. Implementations must - // invoke MaybeResendPacketForRTO when the alarm fires. Implementations must - // also handle the case where |this| is deleted before the alarm fires. - virtual void SetResendAlarm(QuicPacketSequenceNumber sequence_number, - QuicTime::Delta delay) = 0; + // Sets up an alarm to retransmit a packet if we haven't received an ack + // in the expected time frame. Implementations must invoke + // OnRetransmissionAlarm when the alarm fires. Implementations must also + // handle the case where |this| is deleted before the alarm fires. If the + // alarm is already set, this call is a no-op. + virtual void SetRetransmissionAlarm(QuicTime::Delta delay) = 0; // Sets an alarm to send packets after |delay_in_us|. Implementations must // invoke OnCanWrite when the alarm fires. Implementations must also @@ -146,15 +145,17 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface { QuicConsumedData SendStreamData(QuicStreamId id, base::StringPiece data, QuicStreamOffset offset, - bool fin, - QuicPacketSequenceNumber* last_packet); + bool fin); + // Send a stream reset frame to the peer. virtual void SendRstStream(QuicStreamId id, QuicErrorCode error, QuicStreamOffset offset); - // Sends a connection close frame to the peer, and notifies the visitor of - // the close. + // 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); + // Notifies the visitor of the close and marks the connection as disconnected. + void CloseConnection(QuicErrorCode error, bool from_peer); // Processes an incoming UDP packet (consisting of a QuicEncryptedPacket) from // the peer. If processing this packet permits a packet to be revived from @@ -197,14 +198,14 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface { // Updates the internal state concerning which packets have been acked. void RecordPacketReceived(const QuicPacketHeader& header); - // Called by a ResendAlarm when the timer goes off. If the peer appears to be - // sending truncated acks, this returns false to indicate failure, otherwise - // it calls MaybeResendPacket and returns true. - bool MaybeResendPacketForRTO(QuicPacketSequenceNumber sequence_number); + // Called by a RetransmissionAlarm when the timer goes off. If the peer + // appears to be sending truncated acks, this returns false to indicate + // failure, otherwise it calls MaybeRetransmitPacket and returns true. + bool MaybeRetransmitPacketForRTO(QuicPacketSequenceNumber sequence_number); - // Called to resend a packet, in the case a packet was sufficiently nacked by - // the peer, or not acked within the time out window. - void MaybeResendPacket(QuicPacketSequenceNumber sequence_number); + // Called to retransmit a packet, in the case a packet was sufficiently + // nacked by the peer, or not acked within the time out window. + void MaybeRetransmitPacket(QuicPacketSequenceNumber sequence_number); QuicPacketCreator::Options* options() { return packet_creator_.options(); } @@ -229,19 +230,23 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface { // Sets up a packet with an QuicAckFrame and sends it out. void SendAck(); + // Called when an RTO fires. Returns the time when this alarm + // should next fire, or 0 if no retransmission alarm should be set. + QuicTime OnRetransmissionTimeout(); + protected: - // Send a packet to the peer. If should_resend is true, this packet contains - // data, and contents will be resent with a new sequence number if we don't - // get an ack. If force is true, then the packet will be sent immediately and - // the send scheduler will not be consulted. If is_retransmit is true, this - // packet is being retransmitted with a new sequence number. Always takes - // ownership of packet. + // Send a packet to the peer. If should_retransmit is true, this packet + // contains data, and contents will be retransmitted with a new sequence + // number if we don't get an ack. If force is true, then the packet will + // be sent immediately and the send scheduler will not be consulted. If + // is_retransmission is true, this packet is being retransmitted with a new + // sequence number. Always takes ownership of packet. // TODO(wtc): none of the callers check the return value. virtual bool SendPacket(QuicPacketSequenceNumber number, QuicPacket* packet, - bool should_resend, + bool should_retransmit, bool force, - bool is_retransmit); + bool is_retransmission); // Make sure an ack we got from our peer is sane. bool ValidateAckFrame(const QuicAckFrame& incoming_ack); @@ -272,18 +277,18 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface { struct QueuedPacket { QueuedPacket(QuicPacketSequenceNumber sequence_number, QuicPacket* packet, - bool resend, - bool retransmit) + bool should_retransmit, + bool is_retransmission) : sequence_number(sequence_number), packet(packet), - resend(resend), - retransmit(retransmit) { + should_retransmit(should_retransmit), + is_retransmission(is_retransmission) { } QuicPacketSequenceNumber sequence_number; QuicPacket* packet; - bool resend; - bool retransmit; + bool should_retransmit; + bool is_retransmission; }; struct UnackedPacket { @@ -301,17 +306,19 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface { typedef base::hash_map<QuicPacketSequenceNumber, UnackedPacket*> UnackedPacketMap; typedef std::map<QuicFecGroupNumber, QuicFecGroup*> FecGroupMap; + typedef std::list<std::pair<QuicPacketSequenceNumber, QuicTime> > + RetransmissionTimeouts; - // The amount of time we wait before resending a packet. - static const QuicTime::Delta DefaultResendTime() { + // The amount of time we wait before retransmitting a packet. + static const QuicTime::Delta DefaultRetransmissionTime() { return QuicTime::Delta::FromMilliseconds(500); } static void DeleteUnackedPacket(UnackedPacket* unacked); - static bool ShouldResend(const QuicFrame& frame); + static bool ShouldRetransmit(const QuicFrame& frame); // Checks if a packet can be written now, and sets the timer if necessary. - bool CanWrite(bool is_retransmit); + bool CanWrite(bool is_retransmission); // Writes as much queued data as possible. The connection must not be // blocked when this is called. @@ -356,13 +363,24 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface { QuicPacketSequenceNumber peer_largest_observed_packet_; QuicPacketSequenceNumber peer_least_packet_awaiting_ack_; - // When new packets are created which may be resent, they are added + // When new packets are created which may be retransmitted, they are added // to this map, which contains owning pointers to the contained frames. UnackedPacketMap unacked_packets_; + // List of packets that we might need to retransmission, and the time at + // which we should retransmission them. This is currently a FIFO queue which + // means we will never fire an RTO for packet 2 if we are waiting to fire + // the RTO for packet 1. This logic is likely suboptimal but it will + // change when it moves to the SendScheduler so it is fine for now. + RetransmissionTimeouts retransmission_timeouts_; + + // True while OnRetransmissionTimeout is running to prevent + // SetRetransmissionAlarm from being called erroneously. + bool handling_retransmission_timeout_; + // When packets could not be sent because the socket was not writable, // they are added to this list. All corresponding frames are in - // unacked_packets_ if they are to be resent. + // unacked_packets_ if they are to be retransmitted. QueuedPacketList queued_packets_; // Pending control frames, besides the ack and congestion control frames. @@ -383,10 +401,9 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface { // The time that we got or tried to send a packet for this connection. QuicTime time_of_last_packet_; - scoped_ptr<QuicReceiptMetricsCollector> collector_; - - // Scheduler which drives packet send rate. - scoped_ptr<QuicSendScheduler> scheduler_; + // Congestion manager which controls the rate the connection sends packets + // as well as collecting and generating congestion feedback. + QuicCongestionManager congestion_manager_; // True by default. False if we've received or sent an explicit connection // close. diff --git a/net/quic/quic_connection_helper.cc b/net/quic/quic_connection_helper.cc index b53646db..18fd69d 100644 --- a/net/quic/quic_connection_helper.cc +++ b/net/quic/quic_connection_helper.cc @@ -15,13 +15,6 @@ namespace net { -// Limit the number of packets we send per resend-alarm so we eventually cede. -// 10 is arbitrary. -const size_t kMaxPacketsPerResendAlarm = 10; - -// The time to wait if an RTO alarm fires but is ignored due to truncated acks. -const int kExtraRTODelayUs = 500 * 1000; - QuicConnectionHelper::QuicConnectionHelper(base::TaskRunner* task_runner, const QuicClock* clock, QuicRandom* random_generator, @@ -33,10 +26,10 @@ QuicConnectionHelper::QuicConnectionHelper(base::TaskRunner* task_runner, random_generator_(random_generator), send_alarm_registered_(false), timeout_alarm_registered_(false), - resend_alarm_registered_(false), - resend_alarm_running_(false), + retransmission_alarm_registered_(false), + retransmission_alarm_running_(false), ack_alarm_registered_(false), - ack_alarm_time_(QuicTime()) { + ack_alarm_time_(QuicTime::Zero()) { } QuicConnectionHelper::~QuicConnectionHelper() { @@ -78,19 +71,14 @@ int QuicConnectionHelper::WritePacketToWire( return rv; } -void QuicConnectionHelper::SetResendAlarm( - QuicPacketSequenceNumber sequence_number, - QuicTime::Delta delay) { - if (!resend_alarm_registered_ && - !resend_alarm_running_) { - resend_alarm_registered_ = true; +void QuicConnectionHelper::SetRetransmissionAlarm(QuicTime::Delta delay) { + if (!retransmission_alarm_registered_) { task_runner_->PostDelayedTask( FROM_HERE, - base::Bind(&QuicConnectionHelper::OnResendAlarm, + base::Bind(&QuicConnectionHelper::OnRetransmissionAlarm, weak_factory_.GetWeakPtr()), base::TimeDelta::FromMicroseconds(delay.ToMicroseconds())); } - resend_times_[sequence_number] = clock_->Now().Add(delay); } void QuicConnectionHelper::SetAckAlarm(QuicTime::Delta delay) { @@ -106,7 +94,7 @@ void QuicConnectionHelper::SetAckAlarm(QuicTime::Delta delay) { } void QuicConnectionHelper::ClearAckAlarm() { - ack_alarm_time_ = QuicTime(); + ack_alarm_time_ = QuicTime::Zero(); } void QuicConnectionHelper::SetSendAlarm(QuicTime::Delta delay) { @@ -149,41 +137,11 @@ void QuicConnectionHelper::GetPeerAddress(IPEndPoint* peer_address) { socket_->GetPeerAddress(peer_address); } -void QuicConnectionHelper::OnResendAlarm() { - // This guards against registering the alarm later than we should. - // - // If we have packet A and B in the list and we call MaybeResendPacketForRTO - // on A, that may trigger a call to SetResendAlarm if A is resent as C. In - // that case we don't want to register the alarm under SetResendAlarm; we - // want to set it to the RTO of B at the end of this method. - resend_alarm_registered_ = false; - resend_alarm_running_ = true; - - for (size_t i = 0; i < kMaxPacketsPerResendAlarm; ++i) { - if (resend_times_.empty() || - resend_times_.begin()->second > clock_->Now()) { - break; - } - QuicPacketSequenceNumber sequence_number = resend_times_.begin()->first; - if (!connection_->MaybeResendPacketForRTO(sequence_number)) { - DLOG(INFO) << "MaybeResendPacketForRTO failed: adding an extra delay."; - SetResendAlarm(sequence_number, - QuicTime::Delta::FromMicroseconds(kExtraRTODelayUs)); - break; - } - resend_times_.erase(sequence_number); - } - - // Nothing from here on does external calls. - resend_alarm_running_ = false; - if (resend_times_.empty()) { - return; +void QuicConnectionHelper::OnRetransmissionAlarm() { + QuicTime when = connection_->OnRetransmissionTimeout(); + if (!when.IsInitialized()) { + SetRetransmissionAlarm(clock_->Now().Subtract(when)); } - - // We have packet remaining. Reschedule for the RTO of the oldest packet - // on the list. - SetResendAlarm(resend_times_.begin()->first, - resend_times_.begin()->second.Subtract(clock_->Now())); } void QuicConnectionHelper::OnSendAlarm() { @@ -211,7 +169,7 @@ void QuicConnectionHelper::OnAckAlarm() { return; } - ack_alarm_time_ = QuicTime(); + ack_alarm_time_ = QuicTime::Zero(); connection_->SendAck(); } diff --git a/net/quic/quic_connection_helper.h b/net/quic/quic_connection_helper.h index 994ab54..a119371 100644 --- a/net/quic/quic_connection_helper.h +++ b/net/quic/quic_connection_helper.h @@ -47,8 +47,7 @@ class NET_EXPORT_PRIVATE QuicConnectionHelper virtual QuicRandom* GetRandomGenerator() OVERRIDE; virtual int WritePacketToWire(const QuicEncryptedPacket& packet, int* error) OVERRIDE; - virtual void SetResendAlarm(QuicPacketSequenceNumber sequence_number, - QuicTime::Delta delay) OVERRIDE; + virtual void SetRetransmissionAlarm(QuicTime::Delta delay) OVERRIDE; virtual void SetSendAlarm(QuicTime::Delta delay) OVERRIDE; virtual void SetTimeoutAlarm(QuicTime::Delta delay) OVERRIDE; virtual bool IsSendAlarmSet() OVERRIDE; @@ -66,8 +65,8 @@ class NET_EXPORT_PRIVATE QuicConnectionHelper // An alarm is scheduled for each data-bearing packet as it is sent out. // When the alarm goes off, the connection checks to see if the packet has - // been acked, and resends if it has not. - void OnResendAlarm(); + // been acked, and retransmits if it has not. + void OnRetransmissionAlarm(); // An alarm that is scheduled when the sent scheduler requires a // a delay before sending packets and fires when the packet may be sent. void OnSendAlarm(); @@ -86,12 +85,12 @@ class NET_EXPORT_PRIVATE QuicConnectionHelper QuicRandom* random_generator_; bool send_alarm_registered_; bool timeout_alarm_registered_; - bool resend_alarm_registered_; - bool resend_alarm_running_; + bool retransmission_alarm_registered_; + bool retransmission_alarm_running_; bool ack_alarm_registered_; QuicTime ack_alarm_time_; - // Times that packets should be resent. - std::map<QuicPacketSequenceNumber, QuicTime> resend_times_; + // Times that packets should be retransmitted. + std::map<QuicPacketSequenceNumber, QuicTime> retransmission_times_; DISALLOW_COPY_AND_ASSIGN(QuicConnectionHelper); }; diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc index 67b073e..7bd6ff8 100644 --- a/net/quic/quic_connection_helper_test.cc +++ b/net/quic/quic_connection_helper_test.cc @@ -101,7 +101,7 @@ class QuicConnectionHelperTest : public ::testing::Test { &random_generator_, socket)); scheduler_ = new testing::StrictMock<MockScheduler>(); EXPECT_CALL(*scheduler_, TimeUntilSend(_)). - WillRepeatedly(testing::Return(QuicTime::Delta())); + WillRepeatedly(testing::Return(QuicTime::Delta::Zero())); connection_.reset(new TestConnection(guid_, IPEndPoint(), helper_.get())); connection_->set_visitor(&visitor_); connection_->SetScheduler(scheduler_); @@ -161,9 +161,10 @@ class QuicConnectionHelperTest : public ::testing::Test { private: void InitializeHeader(QuicPacketSequenceNumber sequence_number) { - header_.guid = guid_; + header_.public_header.guid = guid_; + header_.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; header_.packet_sequence_number = sequence_number; - header_.flags = PACKET_FLAGS_NONE; + header_.private_flags = PACKET_PRIVATE_FLAGS_NONE; header_.fec_group = 0; } @@ -199,12 +200,12 @@ TEST_F(QuicConnectionHelperTest, IsSendAlarmSet) { } TEST_F(QuicConnectionHelperTest, SetSendAlarm) { - helper_->SetSendAlarm(QuicTime::Delta()); + helper_->SetSendAlarm(QuicTime::Delta::Zero()); EXPECT_TRUE(helper_->IsSendAlarmSet()); } TEST_F(QuicConnectionHelperTest, UnregisterSendAlarmIfRegistered) { - helper_->SetSendAlarm(QuicTime::Delta()); + helper_->SetSendAlarm(QuicTime::Delta::Zero()); helper_->UnregisterSendAlarmIfRegistered() ; EXPECT_FALSE(helper_->IsSendAlarmSet()); } @@ -226,7 +227,7 @@ TEST_F(QuicConnectionHelperTest, SetAckAlarm) { EXPECT_CALL(*scheduler_, SentPacket(1, _, false)); runner_->RunNextTask(); - EXPECT_EQ(QuicTime().Add(delta), clock_.Now()); + EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now()); } TEST_F(QuicConnectionHelperTest, ClearAckAlarm) { @@ -242,7 +243,7 @@ TEST_F(QuicConnectionHelperTest, ClearAckAlarm) { // When the AckAlarm actually fires, no ack will be sent. runner_->RunNextTask(); - EXPECT_EQ(QuicTime().Add(delta), clock_.Now()); + EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now()); } TEST_F(QuicConnectionHelperTest, ResetAckAlarm) { @@ -263,32 +264,34 @@ 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().Add(delta1), clock_.Now()); + EXPECT_EQ(QuicTime::Zero().Add(delta1), clock_.Now()); // Verify that the ack alarm task has been re-posted. ASSERT_EQ(2u, runner_->GetPostedTasks().size()); EXPECT_CALL(*scheduler_, SentPacket(1, _, false)); runner_->RunNextTask(); - EXPECT_EQ(QuicTime().Add(delta2), clock_.Now()); + EXPECT_EQ(QuicTime::Zero().Add(delta2), clock_.Now()); } -TEST_F(QuicConnectionHelperTest, TestResend) { +TEST_F(QuicConnectionHelperTest, TestRetransmission) { AddWrite(SYNCHRONOUS, ConstructDataPacket(1)); AddWrite(SYNCHRONOUS, ConstructDataPacket(2)); Initialize(); - QuicTime::Delta kDefaultResendTime = QuicTime::Delta::FromMilliseconds(500); + QuicTime::Delta kDefaultRetransmissionTime = + QuicTime::Delta::FromMilliseconds(500); QuicTime start = clock_.Now(); EXPECT_CALL(*scheduler_, SentPacket(1, _, false)); // Send a packet. - connection_->SendStreamData(1, kData, 0, false, NULL); + connection_->SendStreamData(1, kData, 0, false); EXPECT_CALL(*scheduler_, SentPacket(2, _, true)); - // Since no ack was received, the resend alarm will fire and resend it. + // Since no ack was received, the retransmission alarm will fire and + // retransmit it. runner_->RunNextTask(); - EXPECT_EQ(kDefaultResendTime, clock_.Now().Subtract(start)); + EXPECT_EQ(kDefaultRetransmissionTime, clock_.Now().Subtract(start)); EXPECT_TRUE(AtEof()); } @@ -347,7 +350,7 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) { EXPECT_EQ(5000u, clock_.Now().ToMicroseconds()); EXPECT_CALL(*scheduler_, SentPacket(1, _, false)); - // Send an ack so we don't set the resend alarm. + // Send an ack so we don't set the retransmission alarm. connection_->SendAck(); // The original alarm will fire. We should not time out because we had a @@ -374,14 +377,14 @@ TEST_F(QuicConnectionHelperTest, SendSchedulerDelayThenSend) { EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return( QuicTime::Delta::FromMicroseconds(1))); - connection_->SendStreamData(1, kData, 0, false, NULL); + connection_->SendStreamData(1, kData, 0, false); EXPECT_CALL(*scheduler_, 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(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta())); + 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_test.cc b/net/quic/quic_connection_test.cc index 4f0bf6e..3e80dc9 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -64,6 +64,9 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { TestConnectionHelper(MockClock* clock, MockRandom* random_generator) : clock_(clock), random_generator_(random_generator), + retransmission_alarm_(QuicTime::Zero()), + send_alarm_(QuicTime::Zero()), + timeout_alarm_(QuicTime::Zero()), blocked_(false) { } @@ -100,9 +103,8 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { return packet.length(); } - virtual void SetResendAlarm(QuicPacketSequenceNumber sequence_number, - QuicTime::Delta delay) { - resend_alarms_[sequence_number] = clock_->Now().Add(delay); + virtual void SetRetransmissionAlarm(QuicTime::Delta delay) { + retransmission_alarm_ = clock_->Now().Add(delay); } virtual void SetSendAlarm(QuicTime::Delta delay) { @@ -118,14 +120,14 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { } virtual void UnregisterSendAlarmIfRegistered() { - send_alarm_ = QuicTime(); + send_alarm_ = QuicTime::Zero(); } virtual void SetAckAlarm(QuicTime::Delta delay) {} virtual void ClearAckAlarm() {} - const map<QuicPacketSequenceNumber, QuicTime>& resend_alarms() const { - return resend_alarms_; + QuicTime retransmission_alarm() const { + return retransmission_alarm_; } QuicTime timeout_alarm() const { return timeout_alarm_; } @@ -141,7 +143,7 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { private: MockClock* clock_; MockRandom* random_generator_; - map<QuicPacketSequenceNumber, QuicTime> resend_alarms_; + QuicTime retransmission_alarm_; QuicTime send_alarm_; QuicTime timeout_alarm_; QuicPacketHeader header_; @@ -174,11 +176,11 @@ class TestConnection : public QuicConnection { bool SendPacket(QuicPacketSequenceNumber sequence_number, QuicPacket* packet, - bool should_resend, + bool should_retransmit, bool force, - bool is_retransmit) { + bool is_retransmission) { return QuicConnection::SendPacket( - sequence_number, packet, should_resend, force, is_retransmit); + sequence_number, packet, should_retransmit, force, is_retransmission); } private: @@ -202,7 +204,7 @@ class QuicConnectionTest : public ::testing::Test { // Simplify tests by not sending feedback unless specifically configured. SetFeedback(NULL); EXPECT_CALL(*scheduler_, TimeUntilSend(_)).WillRepeatedly(Return( - QuicTime::Delta())); + QuicTime::Delta::Zero())); EXPECT_CALL(*collector_, RecordIncomingPacket(_, _, _, _)).Times(AnyNumber()); EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(AnyNumber()); @@ -262,13 +264,13 @@ class QuicConnectionTest : public ::testing::Test { // redundancy. scoped_ptr<QuicPacket> data_packet(ConstructDataPacket(number, 1)); - header_.guid = guid_; + header_.public_header.guid = guid_; + header_.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header_.private_flags = PACKET_PRIVATE_FLAGS_FEC; header_.packet_sequence_number = number; - header_.flags = PACKET_FLAGS_FEC; - header_.fec_group = 1; + header_.fec_group = min_protected_packet; QuicFecData fec_data; - fec_data.min_protected_packet_sequence_number = min_protected_packet; - fec_data.fec_group = 1; + fec_data.fec_group = header_.fec_group; // Since all data packets in this test have the same payload, the // redundancy is either equal to that payload or the xor of that payload // with itself, depending on the number of packets. @@ -291,7 +293,11 @@ class QuicConnectionTest : public ::testing::Test { QuicStreamOffset offset, bool fin, QuicPacketSequenceNumber* last_packet) { EXPECT_CALL(*scheduler_, SentPacket(_, _, _)); - connection_.SendStreamData(id, data, offset, fin, last_packet); + connection_.SendStreamData(id, data, offset, fin); + if (last_packet != NULL) { + *last_packet = + QuicConnectionPeer::GetPacketCreator(&connection_)->sequence_number(); + } EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(AnyNumber()); } @@ -321,9 +327,10 @@ class QuicConnectionTest : public ::testing::Test { QuicPacket* ConstructDataPacket(QuicPacketSequenceNumber number, QuicFecGroupNumber fec_group) { - header_.guid = guid_; + header_.public_header.guid = guid_; + header_.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header_.private_flags = PACKET_PRIVATE_FLAGS_NONE; header_.packet_sequence_number = number; - header_.flags = PACKET_FLAGS_NONE; header_.fec_group = fec_group; QuicFrames frames; @@ -602,7 +609,7 @@ TEST_F(QuicConnectionTest, BasicSending) { EXPECT_EQ(9u, last_ack()->sent_info.least_unacked); } -TEST_F(QuicConnectionTest, ResendOnNack) { +TEST_F(QuicConnectionTest, RetransmitOnNack) { QuicPacketSequenceNumber last_packet; SendStreamDataToPeer(1, "foo", 0, false, &last_packet); // Packet 1 SendStreamDataToPeer(1, "foos", 3, false, &last_packet); // Packet 2 @@ -612,8 +619,8 @@ TEST_F(QuicConnectionTest, ResendOnNack) { expected_acks.insert(1); EXPECT_CALL(visitor_, OnAck(ContainerEq(expected_acks))); - // Client acks one but not two or three. Right now we only resend on explicit - // nack, so it should not trigger resend. + // 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); ProcessAckPacket(&ack_one); ProcessAckPacket(&ack_one); @@ -630,8 +637,8 @@ TEST_F(QuicConnectionTest, ResendOnNack) { ProcessAckPacket(&nack_two); ProcessAckPacket(&nack_two); - // The third nack should trigger resend. - EXPECT_CALL(*scheduler_, SentPacket(_, 37, true)).Times(1); + // The third nack should trigger a retransimission. + EXPECT_CALL(*scheduler_, SentPacket(_, 38, true)).Times(1); ProcessAckPacket(&nack_two); } @@ -658,11 +665,11 @@ TEST_F(QuicConnectionTest, LimitPacketsPerNack) { // The second call will trigger an ack. EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(1); ProcessAckPacket(&nack); - // The third call should trigger resending 10 packets. + // The third call should trigger retransmitting 10 packets. EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(10); ProcessAckPacket(&nack); - // The fourth call should trigger resending the 11th packet and an ack. + // The fourth call should trigger retransmitting the 11th packet and an ack. EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(2); ProcessAckPacket(&nack); } @@ -764,26 +771,25 @@ TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPackets) { ProcessFecProtectedPacket(5, true); } -TEST_F(QuicConnectionTest, TestResend) { +TEST_F(QuicConnectionTest, TestRetransmit) { // TODO(rch): make this work // FLAGS_fake_packet_loss_percentage = 100; - const QuicTime::Delta kDefaultResendTime = + const QuicTime::Delta kDefaultRetransmissionTime = QuicTime::Delta::FromMilliseconds(500); - QuicTime default_resend_time = clock_.Now().Add(kDefaultResendTime); + QuicTime default_retransmission_time = clock_.Now().Add( + kDefaultRetransmissionTime); QuicAckFrame* outgoing_ack = QuicConnectionPeer::GetOutgoingAck(&connection_); SendStreamDataToPeer(1, "foo", 0, false, NULL); EXPECT_EQ(1u, outgoing_ack->sent_info.least_unacked); EXPECT_EQ(1u, last_header()->packet_sequence_number); - EXPECT_EQ(1u, helper_->resend_alarms().size()); - EXPECT_EQ(default_resend_time, - helper_->resend_alarms().find(1)->second); - // Simulate the resend alarm firing - clock_.AdvanceTime(kDefaultResendTime); + EXPECT_EQ(default_retransmission_time, helper_->retransmission_alarm()); + // Simulate the retransimission alarm firing + clock_.AdvanceTime(kDefaultRetransmissionTime); EXPECT_CALL(*scheduler_, SentPacket(_, _, _)); - connection_.MaybeResendPacket(1); + connection_.MaybeRetransmitPacket(1); EXPECT_EQ(2u, last_header()->packet_sequence_number); EXPECT_EQ(2u, outgoing_ack->sent_info.least_unacked); } @@ -792,7 +798,7 @@ TEST_F(QuicConnectionTest, TestResend) { TEST_F(QuicConnectionTest, DISABLED_TestQueued) { EXPECT_EQ(0u, connection_.NumQueuedPackets()); helper_->set_blocked(true); - connection_.SendStreamData(1, "foo", 0, false, NULL); + connection_.SendStreamData(1, "foo", 0, false); EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Attempt to send all packets, but since we're actually still @@ -876,7 +882,7 @@ TEST_F(QuicConnectionTest, TimeoutAfterSend) { // When we send a packet, the timeout will change to 5000 + kDefaultTimeout. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - // Send an ack so we don't set the resend alarm. + // Send an ack so we don't set the retransimission alarm. SendAckPacketToPeer(); EXPECT_EQ(default_timeout, helper_->timeout_alarm()); @@ -900,12 +906,12 @@ TEST_F(QuicConnectionTest, TimeoutAfterSend) { EXPECT_FALSE(connection_.connected()); } -// TODO(ianswett): Add scheduler tests when resend is false. +// 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(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta())); + QuicTime::Delta::Zero())); EXPECT_CALL(*scheduler_, SentPacket(_, _, _)); connection_.SendPacket(1, packet, true, false, false); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -935,7 +941,7 @@ TEST_F(QuicConnectionTest, DISABLED_SendSchedulerEAGAIN) { QuicPacket* packet = ConstructDataPacket(1, 0); helper_->set_blocked(true); EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta())); + QuicTime::Delta::Zero())); EXPECT_CALL(*scheduler_, SentPacket(1, _, _)).Times(0); connection_.SendPacket(1, packet, true, false, false); EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -952,7 +958,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) { // Advance the clock to fire the alarm, and configure the scheduler // to permit the packet to be sent. EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return( - QuicTime::Delta())); + QuicTime::Delta::Zero())); clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1)); EXPECT_CALL(*scheduler_, SentPacket(_, _, _)); EXPECT_CALL(visitor_, OnCanWrite()); @@ -971,7 +977,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) { // Advance the clock to fire the alarm, and configure the scheduler // to permit the packet to be sent. EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return( - QuicTime::Delta())); + QuicTime::Delta::Zero())); // Ensure the scheduler is notified this is a retransmit. EXPECT_CALL(*scheduler_, SentPacket(1, _, true)); @@ -1001,11 +1007,11 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) { connection_.SendPacket(1, packet, true, false, false); EXPECT_EQ(1u, connection_.NumQueuedPackets()); - // Now send non-retransmitting information, that we're not going to resend 3. - // The far end should stop waiting for it. + // 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(*scheduler_, TimeUntilSend(false)).WillRepeatedly(testing::Return( - QuicTime::Delta())); + QuicTime::Delta::Zero())); EXPECT_CALL(*scheduler_, SentPacket(_, _, _)); EXPECT_CALL(visitor_, OnCanWrite()); ProcessAckPacket(&frame); @@ -1022,8 +1028,8 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) { connection_.SendPacket(1, packet, true, false, false); EXPECT_EQ(1u, connection_.NumQueuedPackets()); - // Now send non-resending information, that we're not going to resend 3. - // The far end should stop waiting for it. + // 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(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return( QuicTime::Delta::FromMicroseconds(1))); @@ -1055,9 +1061,9 @@ TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) { // Queue the first packet. EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return( QuicTime::Delta::FromMicroseconds(10))); - EXPECT_EQ(6u, connection_.SendStreamData( - 1, "EnoughDataToQueue", 0, false, NULL).bytes_consumed); - EXPECT_EQ(6u, connection_.NumQueuedPackets()); + EXPECT_EQ(1u, connection_.SendStreamData( + 1, "EnoughDataToQueue", 0, false).bytes_consumed); + EXPECT_EQ(1u, connection_.NumQueuedPackets()); } TEST_F(QuicConnectionTest, LoopThroughSendingPackets) { @@ -1069,7 +1075,7 @@ TEST_F(QuicConnectionTest, LoopThroughSendingPackets) { // Queue the first packet. EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(17); EXPECT_EQ(17u, connection_.SendStreamData( - 1, "EnoughDataToQueue", 0, false, NULL).bytes_consumed); + 1, "EnoughDataToQueue", 0, false).bytes_consumed); } } // namespace diff --git a/net/quic/quic_data_writer.cc b/net/quic/quic_data_writer.cc index c4f7552..3bbad4e 100644 --- a/net/quic/quic_data_writer.cc +++ b/net/quic/quic_data_writer.cc @@ -98,6 +98,11 @@ bool QuicDataWriter::WriteBytes(const void* data, size_t data_len) { return true; } +void QuicDataWriter::WritePadding() { + memset(buffer_ + length_, 0x00, capacity_ - length_); + length_ = capacity_; +} + bool QuicDataWriter::WriteUInt8ToOffset(uint8 value, size_t offset) { DCHECK_LT(offset, capacity_); int latched_length = length_; diff --git a/net/quic/quic_data_writer.h b/net/quic/quic_data_writer.h index 3ca4fa3..f80e905 100644 --- a/net/quic/quic_data_writer.h +++ b/net/quic/quic_data_writer.h @@ -46,6 +46,8 @@ class NET_EXPORT_PRIVATE QuicDataWriter { bool WriteUInt128(uint128 value); bool WriteStringPiece16(base::StringPiece val); bool WriteBytes(const void* data, size_t data_len); + // Fills the remaining buffer with null characters. + void WritePadding(); // Methods for editing the payload at a specific offset, where the // offset must be within the writer's capacity. diff --git a/net/quic/quic_fec_group.cc b/net/quic/quic_fec_group.cc index c678787..2a2695d 100644 --- a/net/quic/quic_fec_group.cc +++ b/net/quic/quic_fec_group.cc @@ -26,6 +26,10 @@ QuicFecGroup::QuicFecGroup() QuicFecGroup::~QuicFecGroup() {} +size_t QuicFecGroup::GroupSize() const { + return max_protected_packet_ - min_protected_packet_ + 1; +} + bool QuicFecGroup::Update(const QuicPacketHeader& header, StringPiece decrypted_payload) { if (received_packets_.count(header.packet_sequence_number) != 0) { @@ -54,7 +58,7 @@ bool QuicFecGroup::UpdateFec( } set<QuicPacketSequenceNumber>::const_iterator it = received_packets_.begin(); while (it != received_packets_.end()) { - if ((*it < fec.min_protected_packet_sequence_number) || + if ((*it < fec.fec_group) || (*it >= fec_packet_sequence_number)) { DLOG(ERROR) << "FEC group does not cover received packet: " << *it; return false; @@ -64,7 +68,7 @@ bool QuicFecGroup::UpdateFec( if (!UpdateParity(fec.redundancy)) { return false; } - min_protected_packet_ = fec.min_protected_packet_sequence_number; + min_protected_packet_ = fec.fec_group; max_protected_packet_ = fec_packet_sequence_number - 1; return true; } diff --git a/net/quic/quic_fec_group.h b/net/quic/quic_fec_group.h index 63a3253..67cba64 100644 --- a/net/quic/quic_fec_group.h +++ b/net/quic/quic_fec_group.h @@ -21,6 +21,12 @@ class NET_EXPORT_PRIVATE QuicFecGroup { QuicFecGroup(); ~QuicFecGroup(); + QuicPacketSequenceNumber min_protected_packet() const { + return min_protected_packet_; + } + + size_t GroupSize() const; + // Updates the FEC group based on the delivery of a data packet. // Returns false if this packet has already been seen, true otherwise. bool Update(const QuicPacketHeader& header, diff --git a/net/quic/quic_fec_group_test.cc b/net/quic/quic_fec_group_test.cc index a53942f..4e4dd20 100644 --- a/net/quic/quic_fec_group_test.cc +++ b/net/quic/quic_fec_group_test.cc @@ -53,7 +53,7 @@ class QuicFecGroupTest : public ::testing::Test { if (packet == lost_packet) { ASSERT_FALSE(group.IsFinished()); QuicFecData fec; - fec.min_protected_packet_sequence_number = 0; + fec.fec_group = 0; fec.redundancy = StringPiece(redundancy.get(), strlen(kData[0])); ASSERT_TRUE(group.UpdateFec(num_packets, fec)); } else { @@ -79,7 +79,7 @@ class QuicFecGroupTest : public ::testing::Test { ASSERT_FALSE(group.IsFinished()); // Attempt to revive the missing packet. QuicFecData fec; - fec.min_protected_packet_sequence_number = 0; + fec.fec_group = 0; fec.redundancy = StringPiece(redundancy.get(), strlen(kData[0])); ASSERT_TRUE(group.UpdateFec(num_packets, fec)); @@ -134,7 +134,7 @@ TEST_F(QuicFecGroupTest, UpdateFecIfReceivedPacketIsNotCovered) { group.Update(header, data1); QuicFecData fec; - fec.min_protected_packet_sequence_number = 1; + fec.fec_group = 1; fec.redundancy = redundancy; ASSERT_FALSE(group.UpdateFec(2, fec)); @@ -182,7 +182,7 @@ TEST_F(QuicFecGroupTest, ProtectsPacketsBeforeWithSeveralPackets) { TEST_F(QuicFecGroupTest, ProtectsPacketsBeforeWithFecData) { QuicFecData fec; - fec.min_protected_packet_sequence_number = 2; + fec.fec_group = 2; fec.redundancy = kData[0]; QuicFecGroup group; diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index cae0b85..2c359ed 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc @@ -12,17 +12,41 @@ #include "net/quic/quic_utils.h" using base::StringPiece; +using std::make_pair; using std::map; using std::numeric_limits; namespace net { -bool kQuicAllowOversizedPacketsForTest = false; +namespace { + +// Mask to select the lowest 48 bits of a sequence number. +const QuicPacketSequenceNumber kSequenceNumberMask = + GG_UINT64_C(0x0000FFFFFFFFFFFF); + +// Returns the absolute value of the difference between |a| and |b|. +QuicPacketSequenceNumber Delta(QuicPacketSequenceNumber a, + QuicPacketSequenceNumber b) { + // Since these are unsigned numbers, we can't just return abs(a - b) + if (a < b) { + return b - a; + } + return a - b; +} + +QuicPacketSequenceNumber ClosestTo(QuicPacketSequenceNumber target, + QuicPacketSequenceNumber a, + QuicPacketSequenceNumber b) { + return (Delta(target, a) < Delta(target, b)) ? a : b; +} + +} // namespace QuicFramer::QuicFramer(QuicDecrypter* decrypter, QuicEncrypter* encrypter) : visitor_(NULL), fec_builder_(NULL), error_(QUIC_NO_ERROR), + last_sequence_number_(0), decrypter_(decrypter), encrypter_(encrypter) { } @@ -59,6 +83,14 @@ QuicPacket* QuicFramer::ConstructMaxFrameDataPacket( len += 1; // frame count bool truncating = false; for (size_t i = 0; i < frames.size(); ++i) { + if (frames[i].type == PADDING_FRAME) { + // PADDING implies end of packet so make sure we don't have + // more frames on the list. + DCHECK_EQ(i, frames.size() - 1); + len = max_plaintext_size; + *num_consumed = i + 1; + break; + } size_t frame_len = 1; // Space for the 8 bit type. frame_len += ComputeFramePayloadLength(frames[i]); if (len + frame_len > max_plaintext_size) { @@ -104,15 +136,15 @@ QuicPacket* QuicFramer::ConstructMaxFrameDataPacket( } switch (frame.type) { + case PADDING_FRAME: + writer.WritePadding(); + break; case STREAM_FRAME: if (!AppendStreamFramePayload(*frame.stream_frame, &writer)) { return NULL; } break; - case PDU_FRAME: - RaiseError(QUIC_INVALID_FRAME_DATA); - return NULL; case ACK_FRAME: if (!AppendAckFramePayload(*frame.ack_frame, &writer)) { return NULL; @@ -143,8 +175,8 @@ QuicPacket* QuicFramer::ConstructMaxFrameDataPacket( } DCHECK(truncating || len == writer.length()); - QuicPacket* packet = new QuicPacket(writer.take(), len, true, - PACKET_FLAGS_NONE); + QuicPacket* packet = QuicPacket::NewDataPacket(writer.take(), len, true); + if (fec_builder_) { fec_builder_->OnBuiltFecProtectedPayload(header, packet->FecProtectedData()); @@ -155,10 +187,7 @@ QuicPacket* QuicFramer::ConstructMaxFrameDataPacket( QuicPacket* QuicFramer::ConstructFecPacket(const QuicPacketHeader& header, const QuicFecData& fec) { - // Compute the length of the packet. We use "magic numbers" here because - // sizeof(member_) is not necessairly the same as sizeof(member_wire_format). size_t len = kPacketHeaderSize; - len += 6; // first protected packet sequence number len += fec.redundancy.length(); QuicDataWriter writer(len); @@ -167,33 +196,51 @@ QuicPacket* QuicFramer::ConstructFecPacket(const QuicPacketHeader& header, return NULL; } - if (!writer.WriteUInt48(fec.min_protected_packet_sequence_number)) { - return NULL; - } - if (!writer.WriteBytes(fec.redundancy.data(), fec.redundancy.length())) { return NULL; } - return new QuicPacket(writer.take(), len, true, PACKET_FLAGS_FEC); + return QuicPacket::NewFecPacket(writer.take(), len, true); } +// TODO(satyamshekhar): Framer doesn't need addresses. Get rid of them. bool QuicFramer::ProcessPacket(const IPEndPoint& self_address, const IPEndPoint& peer_address, const QuicEncryptedPacket& packet) { DCHECK(!reader_.get()); reader_.reset(new QuicDataReader(packet.data(), packet.length())); + + // First parse the public header. + QuicPacketPublicHeader public_header; + if (!ProcessPublicHeader(&public_header)) { + DLOG(WARNING) << "Unable to process header."; + reader_.reset(NULL); + return RaiseError(QUIC_INVALID_PACKET_HEADER); + } + + if (!ProcessDataPacket(public_header, self_address, peer_address, packet)) { + reader_.reset(NULL); + return false; + }; + + reader_.reset(NULL); + return true; +} + +bool QuicFramer::ProcessDataPacket( + const QuicPacketPublicHeader& public_header, + const IPEndPoint& self_address, + const IPEndPoint& peer_address, + const QuicEncryptedPacket& packet) { visitor_->OnPacket(self_address, peer_address); - // First parse the packet header. - QuicPacketHeader header; + QuicPacketHeader header(public_header); if (!ProcessPacketHeader(&header, packet)) { - DLOG(WARNING) << "Unable to process header."; + DLOG(WARNING) << "Unable to process data packet header."; return RaiseError(QUIC_INVALID_PACKET_HEADER); } if (!visitor_->OnPacketHeader(header)) { - reader_.reset(NULL); return true; } @@ -203,7 +250,7 @@ bool QuicFramer::ProcessPacket(const IPEndPoint& self_address, } // Handle the payload. - if ((header.flags & PACKET_FLAGS_FEC) == 0) { + if ((header.private_flags & PACKET_PRIVATE_FLAGS_FEC) == 0) { if (header.fec_group != 0) { StringPiece payload = reader_->PeekRemainingPayload(); visitor_->OnFecProtectedPayload(payload); @@ -216,18 +263,11 @@ bool QuicFramer::ProcessPacket(const IPEndPoint& self_address, } else { QuicFecData fec_data; fec_data.fec_group = header.fec_group; - if (!reader_->ReadUInt48( - &fec_data.min_protected_packet_sequence_number)) { - set_detailed_error("Unable to read first protected packet."); - return RaiseError(QUIC_INVALID_FEC_DATA); - } - fec_data.redundancy = reader_->ReadRemainingPayload(); visitor_->OnFecData(fec_data); } visitor_->OnPacketComplete(); - reader_.reset(NULL); return true; } @@ -258,69 +298,140 @@ bool QuicFramer::ProcessRevivedPacket(const QuicPacketHeader& header, bool QuicFramer::WritePacketHeader(const QuicPacketHeader& header, QuicDataWriter* writer) { - if (!writer->WriteUInt64(header.guid)) { + if (!writer->WriteUInt64(header.public_header.guid)) { + return false; + } + + uint8 flags =static_cast<uint8>(header.public_header.flags); + if (!writer->WriteBytes(&flags, 1)) { return false; } - if (!writer->WriteUInt48(header.packet_sequence_number)) { + if (!AppendPacketSequenceNumber(header.packet_sequence_number, writer)) { return false; } - uint8 flags = static_cast<uint8>(header.flags); + flags = static_cast<uint8>(header.private_flags); if (!writer->WriteBytes(&flags, 1)) { return false; } - if (!writer->WriteBytes(&header.fec_group, 1)) { + // Offset from the current packet sequence number to the first fec + // protected packet, or kNoFecOffset to signal no FEC protection. + uint8 first_fec_protected_packet_offset = kNoFecOffset; + + // The FEC group number is the sequence number of the first fec + // protected packet, or 0 if this packet is not protected. + if (header.fec_group != 0) { + DCHECK_GE(header.packet_sequence_number, header.fec_group); + DCHECK_GT(255u, header.packet_sequence_number - header.fec_group); + first_fec_protected_packet_offset = + header.packet_sequence_number - header.fec_group; + } + if (!writer->WriteBytes(&first_fec_protected_packet_offset, 1)) { return false; } return true; } -bool QuicFramer::ProcessPacketHeader(QuicPacketHeader* header, - const QuicEncryptedPacket& packet) { - if (!reader_->ReadUInt64(&header->guid)) { +QuicPacketSequenceNumber QuicFramer::CalculatePacketSequenceNumberFromWire( + QuicPacketSequenceNumber packet_sequence_number) const { + // The new sequence number might have wrapped to the next epoc, 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. + QuicPacketSequenceNumber epoch = last_sequence_number_ & ~kSequenceNumberMask; + QuicPacketSequenceNumber prev_epoch = epoch - (GG_UINT64_C(1) << 48); + QuicPacketSequenceNumber next_epoch = epoch + (GG_UINT64_C(1) << 48); + + return ClosestTo(last_sequence_number_, + epoch + packet_sequence_number, + ClosestTo(last_sequence_number_, + prev_epoch + packet_sequence_number, + next_epoch + packet_sequence_number)); +} + +bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) { + if (!reader_->ReadUInt64(&public_header->guid)) { set_detailed_error("Unable to read GUID."); return false; } - if (!reader_->ReadUInt48(&header->packet_sequence_number)) { + uint8 public_flags; + if (!reader_->ReadBytes(&public_flags, 1)) { + set_detailed_error("Unable to read public flags."); + return false; + } + + if (public_flags > PACKET_PUBLIC_FLAGS_MAX) { + set_detailed_error("Illegal flags value."); + return false; + } + + public_header->flags = static_cast<QuicPacketPublicFlags>(public_flags); + return true; +} + +bool QuicFramer::ProcessPacketHeader( + QuicPacketHeader* header, + const QuicEncryptedPacket& packet) { + if (!ProcessPacketSequenceNumber(&header->packet_sequence_number)) { set_detailed_error("Unable to read sequence number."); return false; } + if (header->packet_sequence_number == 0u) { set_detailed_error("Packet sequence numbers cannot be 0."); return false; } - unsigned char flags; - if (!reader_->ReadBytes(&flags, 1)) { - set_detailed_error("Unable to read flags."); + if (!DecryptPayload(packet)) { + DLOG(WARNING) << "Unable to decrypt payload."; + return RaiseError(QUIC_DECRYPTION_FAILURE); + } + + uint8 private_flags; + if (!reader_->ReadBytes(&private_flags, 1)) { + set_detailed_error("Unable to read private flags."); return false; } - if (flags > PACKET_FLAGS_MAX) { - set_detailed_error("Illegal flags value."); + if (private_flags > PACKET_PRIVATE_FLAGS_MAX) { + set_detailed_error("Illegal private flags value."); return false; } - header->flags = static_cast<QuicPacketFlags>(flags); + header->private_flags = static_cast<QuicPacketPrivateFlags>(private_flags); - if (!DecryptPayload(packet)) { - DLOG(WARNING) << "Unable to decrypt payload."; - return RaiseError(QUIC_DECRYPTION_FAILURE); + uint8 first_fec_protected_packet_offset; + if (!reader_->ReadBytes(&first_fec_protected_packet_offset, 1)) { + set_detailed_error("Unable to read first fec protected packet offset."); + return false; } + header->fec_group = first_fec_protected_packet_offset == kNoFecOffset ? 0 : + header->packet_sequence_number - first_fec_protected_packet_offset; + + // 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; + return true; +} - if (!reader_->ReadBytes(&header->fec_group, 1)) { - set_detailed_error("Unable to read fec group."); +bool QuicFramer::ProcessPacketSequenceNumber( + QuicPacketSequenceNumber* sequence_number) { + QuicPacketSequenceNumber wire_sequence_number; + if (!reader_->ReadUInt48(&wire_sequence_number)) { return false; } + *sequence_number = + CalculatePacketSequenceNumberFromWire(wire_sequence_number); return true; } bool QuicFramer::ProcessFrameData() { + // TODO(ianswett): remove frame_count uint8 frame_count; if (!reader_->ReadBytes(&frame_count, 1)) { set_detailed_error("Unable to read frame count."); @@ -334,16 +445,14 @@ bool QuicFramer::ProcessFrameData() { return RaiseError(QUIC_INVALID_FRAME_DATA); } switch (frame_type) { + case PADDING_FRAME: + // We're done with the packet + return true; case STREAM_FRAME: if (!ProcessStreamFrame()) { return RaiseError(QUIC_INVALID_FRAME_DATA); } break; - case PDU_FRAME: - if (!ProcessPDUFrame()) { - return RaiseError(QUIC_INVALID_FRAME_DATA); - } - break; case ACK_FRAME: { QuicAckFrame frame; if (!ProcessAckFrame(&frame)) { @@ -410,10 +519,6 @@ bool QuicFramer::ProcessStreamFrame() { return true; } -bool QuicFramer::ProcessPDUFrame() { - return false; -} - bool QuicFramer::ProcessAckFrame(QuicAckFrame* frame) { if (!ProcessSentInfo(&frame->sent_info)) { return false; @@ -426,7 +531,7 @@ bool QuicFramer::ProcessAckFrame(QuicAckFrame* frame) { } bool QuicFramer::ProcessReceivedInfo(ReceivedPacketInfo* received_info) { - if (!reader_->ReadUInt48(&received_info->largest_observed)) { + if (!ProcessPacketSequenceNumber(&received_info->largest_observed)) { set_detailed_error("Unable to read largest observed."); return false; } @@ -439,7 +544,7 @@ bool QuicFramer::ProcessReceivedInfo(ReceivedPacketInfo* received_info) { for (int i = 0; i < num_missing_packets; ++i) { QuicPacketSequenceNumber sequence_number; - if (!reader_->ReadUInt48(&sequence_number)) { + if (!ProcessPacketSequenceNumber(&sequence_number)) { set_detailed_error("Unable to read sequence number in missing packets."); return false; } @@ -450,7 +555,7 @@ bool QuicFramer::ProcessReceivedInfo(ReceivedPacketInfo* received_info) { } bool QuicFramer::ProcessSentInfo(SentPacketInfo* sent_info) { - if (!reader_->ReadUInt48(&sent_info->least_unacked)) { + if (!ProcessPacketSequenceNumber(&sent_info->least_unacked)) { set_detailed_error("Unable to read least unacked."); return false; } @@ -486,7 +591,7 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame( if (num_received_packets > 0u) { uint64 smallest_received; - if (!reader_->ReadUInt48(&smallest_received)) { + if (!ProcessPacketSequenceNumber(&smallest_received)) { set_detailed_error("Unable to read smallest received."); return false; } @@ -497,8 +602,9 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame( return false; } - inter_arrival->received_packet_times[smallest_received] = - QuicTime::FromMicroseconds(time_received_us); + inter_arrival->received_packet_times.insert( + make_pair(smallest_received, + QuicTime::FromMicroseconds(time_received_us))); for (int i = 0; i < num_received_packets - 1; ++i) { uint16 sequence_delta; @@ -515,8 +621,9 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame( return false; } QuicPacketSequenceNumber packet = smallest_received + sequence_delta; - inter_arrival->received_packet_times[packet] = - QuicTime::FromMicroseconds(time_received_us + time_delta_us); + inter_arrival->received_packet_times.insert( + make_pair(packet, QuicTime::FromMicroseconds(time_received_us + + time_delta_us))); } } break; @@ -655,9 +762,6 @@ size_t QuicFramer::ComputeFramePayloadLength(const QuicFrame& frame) { len += 2; // space for the 16 bit length len += frame.stream_frame->data.size(); break; - case PDU_FRAME: - DLOG(INFO) << "PDU_FRAME not yet supported"; - break; // Need to support this eventually :> case ACK_FRAME: { const QuicAckFrame& ack = *frame.ack_frame; len += 6; // largest observed packet sequence number @@ -720,6 +824,12 @@ size_t QuicFramer::ComputeFramePayloadLength(const QuicFrame& frame) { return len; } +bool QuicFramer::AppendPacketSequenceNumber( + QuicPacketSequenceNumber packet_sequence_number, + QuicDataWriter* writer) { + return writer->WriteUInt48(packet_sequence_number & kSequenceNumberMask); +} + bool QuicFramer::AppendStreamFramePayload( const QuicStreamFrame& frame, QuicDataWriter* writer) { @@ -763,12 +873,13 @@ QuicPacketSequenceNumber QuicFramer::CalculateLargestObserved( bool QuicFramer::AppendAckFramePayload( const QuicAckFrame& frame, QuicDataWriter* writer) { - if (!writer->WriteUInt48(frame.sent_info.least_unacked)) { + if (!AppendPacketSequenceNumber(frame.sent_info.least_unacked, writer)) { return false; } size_t largest_observed_offset = writer->length(); - if (!writer->WriteUInt48(frame.received_info.largest_observed)) { + if (!AppendPacketSequenceNumber(frame.received_info.largest_observed, + writer)) { return false; } @@ -783,11 +894,12 @@ bool QuicFramer::AppendAckFramePayload( SequenceSet::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 (!writer->WriteUInt48(*it)) { + if (!AppendPacketSequenceNumber(*it, writer)) { // We are truncating. Overwrite largest_observed. QuicPacketSequenceNumber largest_observed = CalculateLargestObserved(frame.received_info.missing_packets, --it); - writer->WriteUInt48ToOffset(largest_observed, largest_observed_offset); + writer->WriteUInt48ToOffset(largest_observed & kSequenceNumberMask, + largest_observed_offset); writer->WriteUInt8ToOffset(num_missing_packets_written, num_missing_packets_offset); return true; @@ -831,7 +943,7 @@ bool QuicFramer::AppendQuicCongestionFeedbackFramePayload( inter_arrival.received_packet_times.begin(); QuicPacketSequenceNumber lowest_sequence = it->first; - if (!writer->WriteUInt48(lowest_sequence)) { + if (!AppendPacketSequenceNumber(lowest_sequence, writer)) { return false; } diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h index f749e29..81c944a 100644 --- a/net/quic/quic_framer.h +++ b/net/quic/quic_framer.h @@ -18,6 +18,10 @@ namespace net { +namespace test { +class QuicFramerPeer; +} // namespace test + class QuicDataReader; class QuicDataWriter; class QuicDecrypter; @@ -164,15 +168,24 @@ class NET_EXPORT_PRIVATE QuicFramer { const std::string& detailed_error() { return detailed_error_; } private: + friend class test::QuicFramerPeer; + + bool ProcessDataPacket(const QuicPacketPublicHeader& public_header, + const IPEndPoint& self_address, + const IPEndPoint& peer_address, + const QuicEncryptedPacket& packet); + bool WritePacketHeader(const QuicPacketHeader& header, - QuicDataWriter* builder); + QuicDataWriter* writer); + + bool ProcessPublicHeader(QuicPacketPublicHeader* header); bool ProcessPacketHeader(QuicPacketHeader* header, const QuicEncryptedPacket& packet); + bool ProcessPacketSequenceNumber(QuicPacketSequenceNumber* sequence_number); bool ProcessFrameData(); bool ProcessStreamFrame(); - bool ProcessPDUFrame(); bool ProcessAckFrame(QuicAckFrame* frame); bool ProcessReceivedInfo(ReceivedPacketInfo* received_info); bool ProcessSentInfo(SentPacketInfo* sent_info); @@ -183,9 +196,18 @@ class NET_EXPORT_PRIVATE QuicFramer { bool DecryptPayload(const QuicEncryptedPacket& packet); + // Returns the full packet sequence number from the truncated + // wire format version and the last seen packet sequence number. + QuicPacketSequenceNumber CalculatePacketSequenceNumberFromWire( + QuicPacketSequenceNumber packet_sequence_number) const; + // Computes the wire size in bytes of the payload of |frame|. size_t ComputeFramePayloadLength(const QuicFrame& frame); + bool AppendPacketSequenceNumber( + QuicPacketSequenceNumber packet_sequence_number, + QuicDataWriter* writer); + bool AppendStreamFramePayload(const QuicStreamFrame& frame, QuicDataWriter* builder); bool AppendAckFramePayload(const QuicAckFrame& frame, @@ -213,6 +235,7 @@ class NET_EXPORT_PRIVATE QuicFramer { QuicFramerVisitorInterface* visitor_; QuicFecBuilderInterface* fec_builder_; QuicErrorCode error_; + QuicPacketSequenceNumber last_sequence_number_; // Buffer containing decrypted payload data during parsing. scoped_ptr<QuicData> decrypted_; // Decrypter used to decrypt packets during parsing. diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index 2b8832c..6b10890 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc @@ -19,6 +19,7 @@ using base::hash_set; using base::StringPiece; +using std::make_pair; using std::map; using std::string; using std::vector; @@ -26,6 +27,24 @@ using std::vector; namespace net { namespace test { +const QuicPacketSequenceNumber kEpoch = GG_UINT64_C(1) << 48; +const QuicPacketSequenceNumber kMask = kEpoch - 1; + +class QuicFramerPeer { + public: + static QuicPacketSequenceNumber CalculatePacketSequenceNumberFromWire( + QuicFramer* framer, + QuicPacketSequenceNumber packet_sequence_number) { + return framer->CalculatePacketSequenceNumberFromWire( + packet_sequence_number); + } + static void SetLastSequenceNumber( + QuicFramer* framer, + QuicPacketSequenceNumber packet_sequence_number) { + framer->last_sequence_number_ = packet_sequence_number; + } +}; + class TestEncrypter : public QuicEncrypter { public: virtual ~TestEncrypter() {} @@ -232,6 +251,19 @@ class QuicFramerTest : public ::testing::Test { EXPECT_EQ(keys, ack->received_info.largest_observed); } + void CheckCalculatePacketSequenceNumber( + QuicPacketSequenceNumber expected_sequence_number, + QuicPacketSequenceNumber last_sequence_number) { + QuicPacketSequenceNumber wire_sequence_number = + expected_sequence_number & kMask; + QuicFramerPeer::SetLastSequenceNumber(&framer_, last_sequence_number); + EXPECT_EQ(expected_sequence_number, + QuicFramerPeer::CalculatePacketSequenceNumberFromWire( + &framer_, wire_sequence_number)) + << "last_sequence_number: " << last_sequence_number + << "wire_sequence_number: " << wire_sequence_number; + } + test::TestEncrypter* encrypter_; test::TestDecrypter* decrypter_; QuicFramer framer_; @@ -240,6 +272,105 @@ class QuicFramerTest : public ::testing::Test { IPEndPoint peer_address_; }; +TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearEpochStart) { + // A few quick manual sanity checks + CheckCalculatePacketSequenceNumber(GG_UINT64_C(1), GG_UINT64_C(0)); + CheckCalculatePacketSequenceNumber(kEpoch + 1, kMask); + CheckCalculatePacketSequenceNumber(kEpoch, kMask); + + // Cases where the last number was close to the start of the range + for (uint64 last = 0; last < 10; last++) { + // Small numbers should not wrap (even if they're out of order). + for (uint64 j = 0; j < 10; j++) { + CheckCalculatePacketSequenceNumber(j, last); + } + + // Large numbers should not wrap either (because we're near 0 already). + for (uint64 j = 0; j < 10; j++) { + CheckCalculatePacketSequenceNumber(kEpoch - 1 - j, last); + } + } +} + +TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearEpochEnd) { + // Cases where the last number was close to the end of the range + for (uint64 i = 0; i < 10; i++) { + QuicPacketSequenceNumber last = kEpoch - i; + + // Small numbers should wrap. + for (uint64 j = 0; j < 10; j++) { + CheckCalculatePacketSequenceNumber(kEpoch + j, last); + } + + // Large numbers should not (even if they're out of order). + for (uint64 j = 0; j < 10; j++) { + CheckCalculatePacketSequenceNumber(kEpoch - 1 - j, last); + } + } +} + +// Next check where we're in a non-zero epoch to verify we handle +// reverse wrapping, too. +TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearPrevEpoch) { + const uint64 prev_epoch = 1 * kEpoch; + const uint64 cur_epoch = 2 * kEpoch; + // Cases where the last number was close to the start of the range + for (uint64 i = 0; i < 10; i++) { + uint64 last = cur_epoch + i; + // Small number should not wrap (even if they're out of order). + for (uint64 j = 0; j < 10; j++) { + CheckCalculatePacketSequenceNumber(cur_epoch + j, last); + } + + // But large numbers should reverse wrap. + for (uint64 j = 0; j < 10; j++) { + uint64 num = kEpoch - 1 - j; + CheckCalculatePacketSequenceNumber(prev_epoch + num, last); + } + } +} + +TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearNextEpoch) { + const uint64 cur_epoch = 2 * kEpoch; + const uint64 next_epoch = 3 * kEpoch; + // Cases where the last number was close to the end of the range + for (uint64 i = 0; i < 10; i++) { + QuicPacketSequenceNumber last = next_epoch - 1 - i; + + // Small numbers should wrap. + for (uint64 j = 0; j < 10; j++) { + CheckCalculatePacketSequenceNumber(next_epoch + j, last); + } + + // but large numbers should not (even if they're out of order). + for (uint64 j = 0; j < 10; j++) { + uint64 num = kEpoch - 1 - j; + CheckCalculatePacketSequenceNumber(cur_epoch + num, last); + } + } +} + +TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearNextMax) { + const uint64 max_number = std::numeric_limits<uint64>::max(); + const uint64 max_epoch = max_number & ~kMask; + + // Cases where the last number was close to the end of the range + for (uint64 i = 0; i < 10; i++) { + QuicPacketSequenceNumber last = max_number - i; + + // Small numbers should not wrap (because they have nowhere to go. + for (uint64 j = 0; j < 10; j++) { + CheckCalculatePacketSequenceNumber(max_epoch + j, last); + } + + // Large numbers should not wrap either. + for (uint64 j = 0; j < 10; j++) { + uint64 num = kEpoch - 1 - j; + CheckCalculatePacketSequenceNumber(max_epoch + num, last); + } + } +} + TEST_F(QuicFramerTest, EmptyPacket) { char packet[] = { 0x00 }; QuicEncryptedPacket encrypted(packet, 0, false); @@ -252,13 +383,15 @@ TEST_F(QuicFramerTest, LargePacket) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, }; @@ -270,7 +403,8 @@ TEST_F(QuicFramerTest, LargePacket) { ASSERT_TRUE(visitor_.header_.get()); // Make sure we've parsed the packet header, so we can send an error. - EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210), visitor_.header_->guid); + EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210), + visitor_.header_->public_header.guid); // Make sure the correct error is propogated. EXPECT_EQ(QUIC_PACKET_TOO_LARGE, framer_.error()); } @@ -280,59 +414,121 @@ TEST_F(QuicFramerTest, PacketHeader) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, }; QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_FALSE(framer_.ProcessPacket(self_address_, peer_address_, encrypted)); - EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210), visitor_.header_->guid); + 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_EQ(GG_UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number); - EXPECT_EQ(0x00, visitor_.header_->flags); - EXPECT_EQ(0x00, visitor_.header_->fec_group); + EXPECT_EQ(0x00u, visitor_.header_->fec_group); // Now test framing boundaries - for (int i = 0; i < 16; ++i) { + for (size_t i = 0; i < kPacketHeaderSize; ++i) { string expected_error; - if (i < 8) { + if (i < kPublicFlagsOffset) { expected_error = "Unable to read GUID."; - } else if (i < 14) { + } else if (i < kSequenceNumberOffset) { + expected_error = "Unable to read public flags."; + } else if (i < kPrivateFlagsOffset) { expected_error = "Unable to read sequence number."; - } else if (i < 15) { - expected_error = "Unable to read flags."; - } else if (i < 16) { - expected_error = "Unable to read fec group."; + } else if (i < kFecGroupOffset) { + expected_error = "Unable to read private flags."; + } else { + expected_error = "Unable to read first fec protected packet offset."; } CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); } } -TEST_F(QuicFramerTest, StreamFrame) { +TEST_F(QuicFramerTest, PaddingFrame) { unsigned char packet[] = { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags + // private flags 0x00, - // fec group + // first fec protected packet offset + 0xFF, + + // frame count + 0x01, + // frame type (padding frame) 0x00, + // Ignored data (which in this case is a stream frame) + 0x01, + 0x04, 0x03, 0x02, 0x01, + 0x01, + 0x54, 0x76, 0x10, 0x32, + 0xDC, 0xFE, 0x98, 0xBA, + 0x0c, 0x00, + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + }; + + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted)); + EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + ASSERT_EQ(peer_address_, visitor_.peer_address_); + ASSERT_EQ(self_address_, visitor_.self_address_); + + ASSERT_EQ(0u, visitor_.stream_frames_.size()); + EXPECT_EQ(0u, visitor_.ack_frames_.size()); + + // Now test framing boundaries + for (size_t i = 0; i < 2; ++i) { + string expected_error; + if (i < 1) { + expected_error = "Unable to read frame count."; + } else if (i < 2) { + expected_error = "Unable to read frame type."; + } + CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, + QUIC_INVALID_FRAME_DATA); + } +} + +TEST_F(QuicFramerTest, StreamFrame) { + 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 count 0x01, // frame type (stream frame) - 0x00, + 0x01, // stream id 0x04, 0x03, 0x02, 0x01, // fin @@ -394,18 +590,20 @@ TEST_F(QuicFramerTest, RejectPacket) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, // frame type (stream frame) - 0x00, + 0x01, // stream id 0x04, 0x03, 0x02, 0x01, // fin @@ -438,7 +636,7 @@ TEST_F(QuicFramerTest, RevivedStreamFrame) { // frame count 0x01, // frame type (stream frame) - 0x00, + 0x01, // stream id 0x04, 0x03, 0x02, 0x01, // fin @@ -455,9 +653,10 @@ TEST_F(QuicFramerTest, RevivedStreamFrame) { }; QuicPacketHeader header; - header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); - header.flags = PACKET_FLAGS_NONE; header.fec_group = 0; // Do not encrypt the payload because the revived payload is post-encryption. @@ -468,12 +667,13 @@ TEST_F(QuicFramerTest, RevivedStreamFrame) { EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_EQ(1, visitor_.revived_packets_); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210), visitor_.header_->guid); + 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_EQ(GG_UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number); - EXPECT_EQ(0x00, visitor_.header_->flags); - EXPECT_EQ(0x00, visitor_.header_->fec_group); - + EXPECT_EQ(0x00u, visitor_.header_->fec_group); ASSERT_EQ(1u, visitor_.stream_frames_.size()); EXPECT_EQ(0u, visitor_.ack_frames_.size()); @@ -489,18 +689,20 @@ TEST_F(QuicFramerTest, StreamFrameInFecGroup) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x12, 0x34, - // flags + // private flags 0x00, - // fec group + // first fec protected packet offset 0x02, // frame count 0x01, // frame type (stream frame) - 0x00, + 0x01, // stream id 0x04, 0x03, 0x02, 0x01, // fin @@ -522,7 +724,8 @@ TEST_F(QuicFramerTest, StreamFrameInFecGroup) { EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_EQ(2, visitor_.header_->fec_group); + EXPECT_EQ(GG_UINT64_C(0x341256789ABA), + visitor_.header_->fec_group); EXPECT_EQ(string(AsChars(packet) + kStartOfFecProtectedData, arraysize(packet) - kStartOfFecProtectedData), visitor_.fec_protected_payload_); @@ -542,13 +745,15 @@ TEST_F(QuicFramerTest, AckFrame) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, @@ -609,13 +814,15 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameTCP) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, @@ -669,13 +876,15 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, @@ -768,13 +977,15 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameFixRate) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, @@ -824,13 +1035,15 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInvalidFeedback) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, @@ -851,13 +1064,15 @@ TEST_F(QuicFramerTest, RstStreamFrame) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, @@ -916,14 +1131,15 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags + // private flags 0x00, - // fec group - 0x00, - + // first fec protected packet offset + 0xFF, // frame count 0x01, @@ -1001,17 +1217,16 @@ TEST_F(QuicFramerTest, FecPacket) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags (FEC) + // private flags (FEC) 0x01, - // fec group + // first fec protected packet offset 0x01, - // first protected packet - 0xBB, 0x9A, 0x78, 0x56, - 0x34, 0x12, // redundancy 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', @@ -1030,16 +1245,61 @@ TEST_F(QuicFramerTest, FecPacket) { EXPECT_EQ(0u, visitor_.ack_frames_.size()); ASSERT_EQ(1, visitor_.fec_count_); const QuicFecData& fec_data = *visitor_.fec_data_[0]; - EXPECT_EQ(GG_UINT64_C(0x0123456789ABB), - fec_data.min_protected_packet_sequence_number); + EXPECT_EQ(GG_UINT64_C(0x0123456789ABB), fec_data.fec_group); EXPECT_EQ("abcdefghijklmnop", fec_data.redundancy); } -TEST_F(QuicFramerTest, ConstructStreamFramePacket) { +TEST_F(QuicFramerTest, ConstructPaddingFramePacket) { QuicPacketHeader header; - header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); - header.flags = PACKET_FLAGS_NONE; + header.fec_group = 0; + + QuicPaddingFrame padding_frame; + + QuicFrames frames; + frames.push_back(QuicFrame(&padding_frame)); + + unsigned char packet[kMaxPacketSize] = { + // 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 count + 0x01, + // frame type (padding frame) + 0x00, + }; + + // unsigned char packet[kMaxPacketSize]; + memset(packet + kPacketHeaderSize + 1, 0x00, + kMaxPacketSize - kPacketHeaderSize - 1); + + scoped_ptr<QuicPacket> data(framer_.ConstructFrameDataPacket(header, frames)); + ASSERT_TRUE(data != NULL); + + test::CompareCharArraysWithHexError("constructed packet", + data->data(), data->length(), + AsChars(packet), arraysize(packet)); +} + +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.packet_sequence_number = GG_UINT64_C(0x77123456789ABC); header.fec_group = 0; QuicStreamFrame stream_frame; @@ -1055,18 +1315,20 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacket) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, // frame type (stream frame) - 0x00, + 0x01, // stream id 0x04, 0x03, 0x02, 0x01, // fin @@ -1092,15 +1354,17 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacket) { TEST_F(QuicFramerTest, ConstructAckFramePacket) { QuicPacketHeader header; - header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); - header.flags = PACKET_FLAGS_NONE; header.fec_group = 0; QuicAckFrame ack_frame; - 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.least_unacked = GG_UINT64_C(0x0123456789AA0); + 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.least_unacked = GG_UINT64_C(0x770123456789AA0); QuicFrames frames; frames.push_back(QuicFrame(&ack_frame)); @@ -1109,13 +1373,15 @@ TEST_F(QuicFramerTest, ConstructAckFramePacket) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, @@ -1144,9 +1410,10 @@ TEST_F(QuicFramerTest, ConstructAckFramePacket) { TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) { QuicPacketHeader header; - header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); - header.flags = PACKET_FLAGS_NONE; header.fec_group = 0; QuicCongestionFeedbackFrame congestion_feedback_frame; @@ -1161,13 +1428,15 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, @@ -1191,22 +1460,24 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) { TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) { QuicPacketHeader header; - header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); - header.flags = PACKET_FLAGS_NONE; header.fec_group = 0; QuicCongestionFeedbackFrame frame; frame.type = kInterArrival; - frame.inter_arrival.accumulated_number_of_lost_packets - = 0x0302; - frame.inter_arrival.received_packet_times[GG_UINT64_C(0x0123456789ABA)] = - QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59687)); - frame.inter_arrival.received_packet_times[GG_UINT64_C(0x0123456789ABB)] = - QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59688)); - frame.inter_arrival.received_packet_times[GG_UINT64_C(0x0123456789ABD)] = - QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59689)); - + frame.inter_arrival.accumulated_number_of_lost_packets = 0x0302; + frame.inter_arrival.received_packet_times.insert( + make_pair(GG_UINT64_C(0x0123456789ABA), + QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59687)))); + frame.inter_arrival.received_packet_times.insert( + make_pair(GG_UINT64_C(0x0123456789ABB), + QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59688)))); + frame.inter_arrival.received_packet_times.insert( + make_pair(GG_UINT64_C(0x0123456789ABD), + QuicTime::FromMicroseconds(GG_UINT64_C(0x07E1D2C3B4A59689)))); QuicFrames frames; frames.push_back(QuicFrame(&frame)); @@ -1214,13 +1485,15 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, @@ -1258,9 +1531,10 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) { TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) { QuicPacketHeader header; - header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); - header.flags = PACKET_FLAGS_NONE; header.fec_group = 0; QuicCongestionFeedbackFrame congestion_feedback_frame; @@ -1275,13 +1549,15 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, @@ -1303,9 +1579,10 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) { TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInvalidFeedback) { QuicPacketHeader header; - header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); - header.flags = PACKET_FLAGS_NONE; header.fec_group = 0; QuicCongestionFeedbackFrame congestion_feedback_frame; @@ -1321,9 +1598,10 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketInvalidFeedback) { TEST_F(QuicFramerTest, ConstructRstFramePacket) { QuicPacketHeader header; - header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); - header.flags = PACKET_FLAGS_NONE; header.fec_group = 0; QuicRstStreamFrame rst_frame; @@ -1336,13 +1614,15 @@ TEST_F(QuicFramerTest, ConstructRstFramePacket) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, @@ -1377,9 +1657,10 @@ TEST_F(QuicFramerTest, ConstructRstFramePacket) { TEST_F(QuicFramerTest, ConstructCloseFramePacket) { QuicPacketHeader header; - header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); - header.flags = PACKET_FLAGS_NONE; header.fec_group = 0; QuicConnectionCloseFrame close_frame; @@ -1398,13 +1679,15 @@ TEST_F(QuicFramerTest, ConstructCloseFramePacket) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags - 0x00, - // fec group + // private flags 0x00, + // first fec protected packet offset + 0xFF, // frame count 0x01, @@ -1444,31 +1727,30 @@ TEST_F(QuicFramerTest, ConstructCloseFramePacket) { TEST_F(QuicFramerTest, ConstructFecPacket) { QuicPacketHeader header; - header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_FEC; header.packet_sequence_number = (GG_UINT64_C(0x123456789ABC)); - header.flags = PACKET_FLAGS_FEC; - header.fec_group = 1; + header.fec_group = GG_UINT64_C(0x123456789ABB);; QuicFecData fec_data; fec_data.fec_group = 1; - fec_data.min_protected_packet_sequence_number = - GG_UINT64_C(0x123456789ABB); fec_data.redundancy = "abcdefghijklmnop"; unsigned char packet[] = { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags + // private flags 0x01, - // fec group + // first fec protected packet offset 0x01, - // first protected packet - 0xBB, 0x9A, 0x78, 0x56, - 0x34, 0x12, + // redundancy 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', @@ -1489,16 +1771,16 @@ TEST_F(QuicFramerTest, EncryptPacket) { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet id + // public flags + 0x00, + // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // flags + // private flags 0x01, - // fec group + // first fec protected packet offset 0x01, - // first protected packet - 0xBB, 0x9A, 0x78, 0x56, - 0x34, 0x12, + // redundancy 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', @@ -1506,8 +1788,9 @@ TEST_F(QuicFramerTest, EncryptPacket) { 'm', 'n', 'o', 'p', }; - QuicPacket raw(AsChars(packet), arraysize(packet), false, PACKET_FLAGS_NONE); - scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(raw)); + scoped_ptr<QuicPacket> raw( + QuicPacket::NewDataPacket(AsChars(packet), arraysize(packet), false)); + scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*raw)); ASSERT_TRUE(encrypted.get() != NULL); EXPECT_TRUE(CheckEncryption(StringPiece(AsChars(packet), arraysize(packet)))); @@ -1534,11 +1817,13 @@ TEST_F(QuicFramerTest, DISABLED_CalculateLargestReceived) { EXPECT_EQ(4u, QuicFramer::CalculateLargestObserved(missing, missing.find(2))); } -TEST_F(QuicFramerTest, Truncation) { +// TODO(rch) enable after landing the revised truncation CL. +TEST_F(QuicFramerTest, DISABLED_Truncation) { QuicPacketHeader header; - header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); - header.flags = PACKET_FLAGS_NONE; header.fec_group = 0; QuicConnectionCloseFrame close_frame; diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index 58a0e83..fd53f85 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc @@ -162,7 +162,7 @@ class QuicHttpStreamTest : public ::testing::Test { scheduler_ = new MockScheduler(); collector_ = new TestCollector(NULL); EXPECT_CALL(*scheduler_, TimeUntilSend(_)). - WillRepeatedly(testing::Return(QuicTime::Delta())); + WillRepeatedly(testing::Return(QuicTime::Delta::Zero())); helper_ = new QuicConnectionHelper(runner_.get(), &clock_, &random_generator_, socket); connection_ = new TestQuicConnection(guid_, peer_addr_, helper_); @@ -234,10 +234,11 @@ class QuicHttpStreamTest : public ::testing::Test { private: void InitializeHeader(QuicPacketSequenceNumber sequence_number) { - header_.guid = guid_; + header_.public_header.guid = guid_; + header_.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; header_.packet_sequence_number = sequence_number; - header_.flags = PACKET_FLAGS_NONE; header_.fec_group = 0; + header_.private_flags = PACKET_PRIVATE_FLAGS_NONE; } QuicEncryptedPacket* ConstructPacket(const QuicPacketHeader& header, diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc index 769434d..cd79bbb 100644 --- a/net/quic/quic_packet_creator.cc +++ b/net/quic/quic_packet_creator.cc @@ -19,7 +19,7 @@ QuicPacketCreator::QuicPacketCreator(QuicGuid guid, QuicFramer* framer) : guid_(guid), framer_(framer), sequence_number_(0), - fec_group_number_(1) { + fec_group_number_(0) { framer_->set_fec_builder(this); } @@ -27,57 +27,35 @@ QuicPacketCreator::~QuicPacketCreator() { } void QuicPacketCreator::OnBuiltFecProtectedPayload( - const QuicPacketHeader& header, - StringPiece payload) { + const QuicPacketHeader& header, StringPiece payload) { if (fec_group_.get()) { fec_group_->Update(header, payload); } } -PacketPair QuicPacketCreator::SerializeAllFrames(const QuicFrames& frames) { - size_t num_serialized; - PacketPair pair = SerializeFrames(frames, &num_serialized); - DCHECK_EQ(frames.size(), num_serialized); - return pair; +bool QuicPacketCreator::ShouldSendFec(bool force_close) const { + DCHECK(options_.max_packets_per_fec_group == 0 || + (fec_group_.get() != NULL && fec_group_->GroupSize() > 0)); + return options_.max_packets_per_fec_group > 0 && + ((force_close && fec_group_->GroupSize() > 0) || + fec_group_->GroupSize() >= options_.max_packets_per_fec_group); } -PacketPair QuicPacketCreator::SerializeFrames( - const QuicFrames& frames, size_t* num_serialized) { - QuicPacketHeader header; - FillPacketHeader(0, PACKET_FLAGS_NONE, &header); - - QuicPacket* packet = framer_->ConstructMaxFrameDataPacket( - header, frames, num_serialized); - return make_pair(header.packet_sequence_number, packet); +void QuicPacketCreator::MaybeStartFEC() { + if (options_.max_packets_per_fec_group > 0) { + DCHECK(fec_group_.get() == NULL); + fec_group_number_ = sequence_number() + 1; + fec_group_.reset(new QuicFecGroup()); + } } -size_t QuicPacketCreator::DataToStream(QuicStreamId id, - StringPiece data, - QuicStreamOffset offset, - bool fin, - vector<PacketPair>* packets, - QuicFrames* packetized_frames) { +size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id, + StringPiece data, + QuicStreamOffset offset, + bool fin, + QuicFrames* frames) { DCHECK_GT(options_.max_packet_length, QuicUtils::StreamFramePacketOverhead(1)); - DCHECK_LT(0u, options_.max_num_packets); - QuicPacketHeader header; - - QuicPacket* packet = NULL; - QuicFrames frames; - QuicFecGroupNumber current_fec_group = 0; - QuicFecData fec_data; - - size_t num_data_packets = options_.max_num_packets; - - if (options_.use_fec) { - DCHECK_LT(1u, options_.max_num_packets); - --num_data_packets; - DCHECK(!fec_group_.get()); - fec_group_.reset(new QuicFecGroup); - current_fec_group = fec_group_number_; - fec_data.fec_group = current_fec_group; - fec_data.min_protected_packet_sequence_number = sequence_number_ + 1; - } size_t unconsumed_bytes = data.size(); if (data.size() != 0) { @@ -87,30 +65,18 @@ size_t QuicPacketCreator::DataToStream(QuicStreamId id, DCHECK_GT(max_frame_len, 0u); size_t frame_len = min<size_t>(max_frame_len, unconsumed_bytes); - while (unconsumed_bytes > 0 && num_data_packets > 0) { - --num_data_packets; + if (unconsumed_bytes > 0) { bool set_fin = false; - if (unconsumed_bytes <= frame_len) { // last loop + if (unconsumed_bytes <= frame_len) { // last frame. frame_len = min(unconsumed_bytes, frame_len); set_fin = fin; } StringPiece data_frame(data.data() + data.size() - unconsumed_bytes, - frame_len); + frame_len); + frames->push_back(QuicFrame(new QuicStreamFrame( + id, set_fin, offset, data_frame))); - QuicStreamFrame* frame = new QuicStreamFrame( - id, set_fin, offset, data_frame); - frames.push_back(QuicFrame(frame)); - FillPacketHeader(current_fec_group, PACKET_FLAGS_NONE, &header); - offset += frame_len; unconsumed_bytes -= frame_len; - - // Produce the data packet (which might fin the stream). - packet = framer_->ConstructFrameDataPacket(header, frames); - DCHECK(packet); - DCHECK_GE(options_.max_packet_length, packet->length()); - packets->push_back(make_pair(header.packet_sequence_number, packet)); - packetized_frames->push_back(frames[0]); - frames.clear(); } // If we haven't finished serializing all the data, don't set any final fin. if (unconsumed_bytes > 0) { @@ -120,54 +86,51 @@ size_t QuicPacketCreator::DataToStream(QuicStreamId id, // Create a new packet for the fin, if necessary. if (fin && data.size() == 0) { - FillPacketHeader(current_fec_group, PACKET_FLAGS_NONE, &header); QuicStreamFrame* frame = new QuicStreamFrame(id, true, offset, ""); - frames.push_back(QuicFrame(frame)); - packet = framer_->ConstructFrameDataPacket(header, frames); - DCHECK(packet); - DCHECK_GE(options_.max_packet_length, packet->length()); - packets->push_back(make_pair(header.packet_sequence_number, packet)); - packetized_frames->push_back(frames[0]); - frames.clear(); + frames->push_back(QuicFrame(frame)); } - // Create a new FEC packet, if necessary - if (current_fec_group != 0) { - FillPacketHeader(current_fec_group, PACKET_FLAGS_FEC, &header); - fec_data.redundancy = fec_group_->parity(); - QuicPacket* fec_packet = framer_->ConstructFecPacket(header, fec_data); - DCHECK(fec_packet); - DCHECK_GE(options_.max_packet_length, packet->length()); - packets->push_back(make_pair(header.packet_sequence_number, fec_packet)); - ++fec_group_number_; - } - /* - if (options_.random_reorder) { - int32 seed = ACMRandom::HostnamePidTimeSeed(); - ACMRandom random(seed); - DLOG(INFO) << "Seed " << seed; - - vector<PacketPair> tmp_store; - tmp_store.swap(*packets); - - while (tmp_store.size() != 0) { - int idx = random.Uniform(tmp_store.size()); - packets->push_back(tmp_store[idx]); - tmp_store.erase(tmp_store.begin() + idx); - } - } - */ - fec_group_.reset(NULL); - DCHECK(options_.max_num_packets >= packets->size()); - return data.size() - unconsumed_bytes; } +PacketPair QuicPacketCreator::SerializeAllFrames(const QuicFrames& frames) { + size_t num_serialized; + PacketPair pair = SerializeFrames(frames, &num_serialized); + DCHECK_EQ(frames.size(), num_serialized); + return pair; +} + +PacketPair QuicPacketCreator::SerializeFrames(const QuicFrames& frames, + size_t* num_serialized) { + QuicPacketHeader header; + FillPacketHeader(fec_group_number_, PACKET_PRIVATE_FLAGS_NONE, &header); + + QuicPacket* packet = framer_->ConstructMaxFrameDataPacket( + header, frames, num_serialized); + return make_pair(header.packet_sequence_number, packet); +} + +QuicPacketCreator::PacketPair QuicPacketCreator::SerializeFec() { + DCHECK_LT(0u, fec_group_->GroupSize()); + QuicPacketHeader header; + FillPacketHeader(fec_group_number_, PACKET_PRIVATE_FLAGS_FEC, &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_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); +} + QuicPacketCreator::PacketPair QuicPacketCreator::CloseConnection( QuicConnectionCloseFrame* close_frame) { QuicPacketHeader header; - FillPacketHeader(0, PACKET_FLAGS_NONE, &header); + FillPacketHeader(0, PACKET_PRIVATE_FLAGS_NONE, &header); QuicFrames frames; frames.push_back(QuicFrame(close_frame)); @@ -177,10 +140,11 @@ QuicPacketCreator::PacketPair QuicPacketCreator::CloseConnection( } void QuicPacketCreator::FillPacketHeader(QuicFecGroupNumber fec_group, - QuicPacketFlags flags, + QuicPacketPrivateFlags flags, QuicPacketHeader* header) { - header->guid = guid_; - header->flags = flags; + header->public_header.guid = guid_; + header->public_header.flags = PACKET_PUBLIC_FLAGS_NONE; + header->private_flags = flags; header->packet_sequence_number = ++sequence_number_; header->fec_group = fec_group; } diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h index 4f11348..0fc8176 100644 --- a/net/quic/quic_packet_creator.h +++ b/net/quic/quic_packet_creator.h @@ -22,24 +22,17 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { public: // Options for controlling how packets are created. struct Options { - Options() { - Clear(); - } - void Clear() { - memset(this, 0, sizeof(Options)); - max_packet_length = kMaxPacketSize; - max_num_packets = std::numeric_limits<size_t>::max(); + Options() + : max_packet_length(kMaxPacketSize), + random_reorder(false), + max_packets_per_fec_group(0) { } // TODO(alyssar, rch) max frames/packet size_t max_packet_length; - // The maximum number of packets we'd like to serialize. - // If the data can't be fully serialized, DataToStream will only consume as - // much data as fits into this many packets. - size_t max_num_packets; bool random_reorder; // Inefficient: rewrite if used at scale. - // TODO(rch) should probably be max packets per group. - bool use_fec; + // 0 indicates fec is disabled. + size_t max_packets_per_fec_group; }; QuicPacketCreator(QuicGuid guid, QuicFramer* framer); @@ -52,24 +45,33 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { typedef std::pair<QuicPacketSequenceNumber, QuicPacket*> PacketPair; + // Checks if it's time to send an FEC packet. |force_close| forces this to + // return true if an fec group is open. + bool ShouldSendFec(bool force_close) const; + + // Starts a new FEC group with the next serialized packet, if FEC is enabled. + void MaybeStartFEC(); + + // Converts a raw payload to a frame. Returns the number of bytes consumed + // from data. If data is empty and fin is true, the expected behavior is to + // consume the fin but return 0. + size_t CreateStreamFrame(QuicStreamId id, + base::StringPiece data, + QuicStreamOffset offset, + bool fin, + QuicFrames* frames); + // Serializes all frames into a single packet. All frames must fit into a // single packet. PacketPair SerializeAllFrames(const QuicFrames& frames); // Serializes as many non-fec frames as can fit into a single packet. // num_serialized is set to the number of frames serialized into the packet. - PacketPair SerializeFrames(const QuicFrames& frames, size_t* num_serialized); - - // Converts a raw payload to a series of QuicPackets and matching frames in - // those packets. Returns the number of bytes consumed from data. - // If data is empty and fin is true, the expected behavior is to consume the - // fin but return 0. - size_t DataToStream(QuicStreamId id, - base::StringPiece data, - QuicStreamOffset offset, - bool fin, - std::vector<PacketPair>* packets, - QuicFrames* packetized_frames); + PacketPair SerializeFrames(const QuicFrames& frames, + size_t* num_serialized); + + // Packetize FEC data. + PacketPair SerializeFec(); PacketPair CloseConnection(QuicConnectionCloseFrame* close_frame); @@ -87,7 +89,7 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { private: void FillPacketHeader(QuicFecGroupNumber fec_group, - QuicPacketFlags flags, + QuicPacketPrivateFlags flags, QuicPacketHeader* header); Options options_; diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc index d4835b1..d4bdb28 100644 --- a/net/quic/quic_packet_creator_test.cc +++ b/net/quic/quic_packet_creator_test.cc @@ -10,10 +10,11 @@ #include "net/quic/test_tools/quic_test_utils.h" #include "testing/gmock/include/gmock/gmock.h" +using base::StringPiece; +using std::string; +using std::vector; using testing::InSequence; using testing::_; -using std::vector; -using std::string; namespace net { namespace test { @@ -31,21 +32,16 @@ class QuicPacketCreatorTest : public ::testing::Test { framer_.set_visitor(&framer_visitor_); } ~QuicPacketCreatorTest() { - STLDeleteValues(&packets_); for (QuicFrames::iterator it = frames_.begin(); it != frames_.end(); ++it) { QuicConnection::DeleteEnclosedFrame(&(*it)); } } - void ProcessPackets() { - for (size_t i = 0; i < packets_.size(); ++i) { - scoped_ptr<QuicEncryptedPacket> encrypted( - framer_.EncryptPacket(*packets_[i].second)); - framer_.ProcessPacket(IPEndPoint(), IPEndPoint(), *encrypted); - } + void ProcessPacket(QuicPacket* packet) { + scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*packet)); + framer_.ProcessPacket(IPEndPoint(), IPEndPoint(), *encrypted); } - vector<QuicPacketCreator::PacketPair> packets_; QuicFrames frames_; QuicFramer framer_; testing::StrictMock<MockFramerVisitor> framer_visitor_; @@ -56,172 +52,97 @@ class QuicPacketCreatorTest : public ::testing::Test { QuicPacketCreator utils_; }; -TEST_F(QuicPacketCreatorTest, DataToStreamBasic) { - size_t bytes_consumed = utils_.DataToStream( - id_, data_, 0, true, &packets_, &frames_); - - ASSERT_EQ(1u, packets_.size()); - ASSERT_EQ(1u, utils_.sequence_number()); - ASSERT_EQ(data_.size(), bytes_consumed); - - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket(_, _)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - - ProcessPackets(); -} - -TEST_F(QuicPacketCreatorTest, DataToStreamFec) { - utils_.options()->use_fec = true; - size_t bytes_consumed = utils_.DataToStream( - id_, data_, 0, true, &packets_, &frames_); - - ASSERT_EQ(2u, packets_.size()); - ASSERT_EQ(2u, utils_.sequence_number()); - ASSERT_EQ(data_.size(), bytes_consumed); - - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket(_, _)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnFecProtectedPayload(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - - EXPECT_CALL(framer_visitor_, OnPacket(_, _)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnFecData(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - - ProcessPackets(); -} - -TEST_F(QuicPacketCreatorTest, DataToStreamFecHandled) { - utils_.options()->use_fec = true; - size_t bytes_consumed = utils_.DataToStream( - id_, data_, 0, true, &packets_, &frames_); - ASSERT_EQ(data_.size(), bytes_consumed); - - ASSERT_EQ(2u, packets_.size()); - ASSERT_EQ(2u, utils_.sequence_number()); - - QuicFecData fec_data; - fec_data.fec_group = 1; - fec_data.min_protected_packet_sequence_number = 1; - fec_data.redundancy = packets_[0].second->FecProtectedData(); - - InSequence s; - // Data packet - EXPECT_CALL(framer_visitor_, OnPacket(_, _)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnFecProtectedPayload(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - - // FEC packet - EXPECT_CALL(framer_visitor_, OnPacket(_, _)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnFecData(fec_data)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - - ProcessPackets(); - - // Revived data packet - EXPECT_CALL(framer_visitor_, OnRevivedPacket()); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - - QuicPacketHeader header; - framer_.ProcessRevivedPacket(header, fec_data.redundancy); -} - -TEST_F(QuicPacketCreatorTest, DataToStreamSkipFin) { - size_t bytes_consumed = utils_.DataToStream( - id_, data_, 0, false, &packets_, &frames_); - ASSERT_EQ(data_.size(), bytes_consumed); - - ASSERT_EQ(1u, packets_.size()); - ASSERT_EQ(1u, utils_.sequence_number()); - - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket(_, _)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - - ProcessPackets(); +TEST_F(QuicPacketCreatorTest, SerializeFrame) { + frames_.push_back(QuicFrame(new QuicStreamFrame( + 0u, false, 0u, StringPiece("")))); + PacketPair pair = utils_.SerializeAllFrames(frames_); + + { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket(_, _)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); + } + ProcessPacket(pair.second); + delete pair.second; } -TEST_F(QuicPacketCreatorTest, NoData) { - data_ = ""; - - size_t bytes_consumed = utils_.DataToStream( - id_, data_, 0, true, &packets_, &frames_); - ASSERT_EQ(data_.size(), bytes_consumed); - - ASSERT_EQ(1u, packets_.size()); - ASSERT_EQ(1u, utils_.sequence_number()); - - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket(_, _)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - - ProcessPackets(); +TEST_F(QuicPacketCreatorTest, SerializeFrames) { + frames_.push_back(QuicFrame(new QuicAckFrame(0u, 0u))); + frames_.push_back(QuicFrame(new QuicStreamFrame( + 0u, false, 0u, StringPiece("")))); + frames_.push_back(QuicFrame(new QuicStreamFrame( + 0u, true, 0u, StringPiece("")))); + PacketPair pair = utils_.SerializeAllFrames(frames_); + + { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket(_, _)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + EXPECT_CALL(framer_visitor_, OnAckFrame(_)); + EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); + EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); + } + ProcessPacket(pair.second); + delete pair.second; } -TEST_F(QuicPacketCreatorTest, MultiplePackets) { - size_t ciphertext_size = NullEncrypter().GetCiphertextSize(2); - utils_.options()->max_packet_length = - ciphertext_size + QuicUtils::StreamFramePacketOverhead(1); +TEST_F(QuicPacketCreatorTest, SerializeWithFEC) { + utils_.options()->max_packets_per_fec_group = 6; + utils_.MaybeStartFEC(); + + frames_.push_back(QuicFrame(new QuicStreamFrame( + 0u, false, 0u, StringPiece("")))); + PacketPair pair = utils_.SerializeAllFrames(frames_); + + { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket(_, _)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + EXPECT_CALL(framer_visitor_, OnFecProtectedPayload(_)); + EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); + } + ProcessPacket(pair.second); + delete pair.second; - size_t bytes_consumed = utils_.DataToStream( - id_, data_, 0, true, &packets_, &frames_); - ASSERT_EQ(data_.size(), bytes_consumed); + ASSERT_FALSE(utils_.ShouldSendFec(false)); + ASSERT_TRUE(utils_.ShouldSendFec(true)); - ASSERT_EQ(2u, packets_.size()); - ASSERT_EQ(2u, utils_.sequence_number()); + pair = utils_.SerializeFec(); + ASSERT_EQ(2u, pair.first); - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket(_, _)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - - EXPECT_CALL(framer_visitor_, OnPacket(_, _)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - - ProcessPackets(); + { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket(_, _)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); + EXPECT_CALL(framer_visitor_, OnFecData(_)); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); + } + ProcessPacket(pair.second); + delete pair.second; } -TEST_F(QuicPacketCreatorTest, MultiplePacketsWithLimits) { - const size_t kPayloadBytesPerPacket = 2; - - size_t ciphertext_size = NullEncrypter().GetCiphertextSize( - kPayloadBytesPerPacket); - utils_.options()->max_packet_length = - ciphertext_size + QuicUtils::StreamFramePacketOverhead(1); - utils_.options()->max_num_packets = 1; - - size_t bytes_consumed = utils_.DataToStream( - id_, data_, 0, true, &packets_, &frames_); - ASSERT_EQ(kPayloadBytesPerPacket, bytes_consumed); +TEST_F(QuicPacketCreatorTest, CloseConnection) { + QuicConnectionCloseFrame frame; + frame.error_code = QUIC_NO_ERROR; + frame.ack_frame = QuicAckFrame(0u, 0u); - ASSERT_EQ(1u, packets_.size()); + PacketPair pair = utils_.CloseConnection(&frame); + ASSERT_EQ(1u, pair.first); ASSERT_EQ(1u, utils_.sequence_number()); InSequence s; EXPECT_CALL(framer_visitor_, OnPacket(_, _)); EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); + EXPECT_CALL(framer_visitor_, OnAckFrame(_)); + EXPECT_CALL(framer_visitor_, OnConnectionCloseFrame(_)); EXPECT_CALL(framer_visitor_, OnPacketComplete()); - ProcessPackets(); + ProcessPacket(pair.second); + delete pair.second; } } // namespace diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index 3d0b4d9..37ba15e4 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc @@ -157,10 +157,6 @@ bool QuicFecData::operator==(const QuicFecData& other) const { if (fec_group != other.fec_group) { return false; } - if (min_protected_packet_sequence_number != - other.min_protected_packet_sequence_number) { - return false; - } if (redundancy != other.redundancy) { return false; } diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index f2d60a2..a391421 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -32,20 +32,7 @@ typedef uint64 QuicGuid; typedef uint32 QuicStreamId; typedef uint64 QuicStreamOffset; typedef uint64 QuicPacketSequenceNumber; -typedef uint8 QuicFecGroupNumber; - -// 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. -struct QuicConsumedData { - QuicConsumedData(size_t bytes_consumed, bool fin_consumed) - : bytes_consumed(bytes_consumed), - fin_consumed(fin_consumed) { - } - size_t bytes_consumed; - bool fin_consumed; -}; - +typedef QuicPacketSequenceNumber QuicFecGroupNumber; // TODO(rch): Consider Quic specific names for these constants. const size_t kMaxPacketSize = 1200; // Maximum size in bytes of a QUIC packet. @@ -53,20 +40,40 @@ const size_t kMaxPacketSize = 1200; // Maximum size in bytes of a QUIC packet. // Maximum number of open streams per connection. const size_t kDefaultMaxStreamsPerConnection = 100; -// Size in bytes of the packet header common across all packets. -const size_t kPacketHeaderSize = 16; +// Number of bytes reserved for guid in the packet header. +const size_t kQuicGuidSize = 8; +// Number of bytes reserved for public flags in the packet header. +const size_t kPublicFlagsSize = 1; +// Number of bytes reserved for sequence number in the packet header. +const size_t kSequenceNumberSize = 6; +// Number of bytes reserved for private flags in the packet header. +const size_t kPrivateFlagsSize = 1; +// Number of bytes reserved for FEC group in the packet header. +const size_t kFecGroupSize = 1; + +// Size in bytes of the data or fec packet header. +const size_t kPacketHeaderSize = kQuicGuidSize + kPublicFlagsSize + + kPrivateFlagsSize + kSequenceNumberSize + kFecGroupSize; + +// Index into the guid offset in the header. +const size_t kGuidOffset = 0; +// Index into the flags offset in the header. +const size_t kPublicFlagsOffset = kQuicGuidSize; + +// Index into the sequence number offset in the header. +const size_t kSequenceNumberOffset = kPublicFlagsOffset + kPublicFlagsSize; +// Index into the private flags offset in the data packet header. +const size_t kPrivateFlagsOffset = kSequenceNumberOffset + kSequenceNumberSize; +// Index into the fec group offset in the header. +const size_t kFecGroupOffset = kPrivateFlagsOffset + kPrivateFlagsSize; + // Index of the first byte in a QUIC packet of FEC protected data. const size_t kStartOfFecProtectedData = kPacketHeaderSize; // Index of the first byte in a QUIC packet of encrypted data. -const size_t kStartOfEncryptedData = kPacketHeaderSize - 1; +const size_t kStartOfEncryptedData = kPacketHeaderSize - kPrivateFlagsSize - + kFecGroupSize; // Index of the first byte in a QUIC packet which is hashed. const size_t kStartOfHashData = 0; -// Index into the sequence number offset in the header. -const int kSequenceNumberOffset = 8; -// Index into the flags offset in the header. -const int kFlagsOffset = 14; -// Index into the fec group offset in the header. -const int kFecGroupOffset = 15; // Size in bytes of all stream frame fields. const size_t kMinStreamFrameLength = 15; @@ -78,13 +85,16 @@ const QuicStreamId kMaxStreamIdDelta = 100; // TODO(rch): ensure that this is not usable by any other streams. 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 { - STREAM_FRAME = 0, - PDU_FRAME, + PADDING_FRAME = 0, + STREAM_FRAME, ACK_FRAME, CONGESTION_FEEDBACK_FRAME, RST_STREAM_FRAME, @@ -92,11 +102,21 @@ enum QuicFrameType { NUM_FRAME_TYPES }; -enum QuicPacketFlags { - PACKET_FLAGS_NONE = 0, - PACKET_FLAGS_FEC = 1, // Payload is FEC as opposed to frames. +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. +}; + +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_FLAGS_MAX = PACKET_FLAGS_FEC +enum QuicVersion { + QUIC_VERSION_1 = 0 }; enum QuicErrorCode { @@ -161,15 +181,28 @@ enum QuicErrorCode { }; -struct NET_EXPORT_PRIVATE QuicPacketHeader { - // Includes the ConnectionHeader and CongestionMonitoredHeader - // from the design docs, as well as some elements of DecryptedData. +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; +}; + +// Header for Data or FEC packets. +struct QuicPacketHeader { + QuicPacketHeader() {} + explicit QuicPacketHeader(const QuicPacketPublicHeader& header) + : public_header(header) {} + QuicPacketPublicHeader public_header; + QuicPacketPrivateFlags private_flags; QuicPacketSequenceNumber packet_sequence_number; - QuicPacketFlags flags; QuicFecGroupNumber fec_group; }; +// A padding frame contains no payload. +struct NET_EXPORT_PRIVATE QuicPaddingFrame { +}; + struct NET_EXPORT_PRIVATE QuicStreamFrame { QuicStreamFrame(); QuicStreamFrame(QuicStreamId stream_id, @@ -308,6 +341,10 @@ struct NET_EXPORT_PRIVATE QuicConnectionCloseFrame { struct NET_EXPORT_PRIVATE QuicFrame { QuicFrame() {} + explicit QuicFrame(QuicPaddingFrame* padding_frame) + : type(PADDING_FRAME), + padding_frame(padding_frame) { + } explicit QuicFrame(QuicStreamFrame* stream_frame) : type(STREAM_FRAME), stream_frame(stream_frame) { @@ -331,6 +368,7 @@ struct NET_EXPORT_PRIVATE QuicFrame { QuicFrameType type; union { + QuicPaddingFrame* padding_frame; QuicStreamFrame* stream_frame; QuicAckFrame* ack_frame; QuicCongestionFeedbackFrame* congestion_feedback_frame; @@ -346,6 +384,9 @@ struct NET_EXPORT_PRIVATE QuicFecData { bool operator==(const QuicFecData& other) const; + // The FEC group number is also the sequence number of the first + // FEC protected packet. The last protected packet's sequence number will + // be one less than the sequence number of the FEC packet. QuicFecGroupNumber fec_group; QuicPacketSequenceNumber min_protected_packet_sequence_number; // The last protected packet's sequence number will be one @@ -388,11 +429,17 @@ class NET_EXPORT_PRIVATE QuicData { class NET_EXPORT_PRIVATE QuicPacket : public QuicData { public: - QuicPacket( - char* buffer, size_t length, bool owns_buffer, QuicPacketFlags flags) - : QuicData(buffer, length, owns_buffer), - buffer_(buffer), - flags_(flags) { } + static QuicPacket* NewDataPacket(char* buffer, + size_t length, + bool owns_buffer) { + return new QuicPacket(buffer, length, owns_buffer, false); + } + + static QuicPacket* NewFecPacket(char* buffer, + size_t length, + bool owns_buffer) { + return new QuicPacket(buffer, length, owns_buffer, true); + } base::StringPiece FecProtectedData() const { return base::StringPiece(data() + kStartOfFecProtectedData, @@ -408,15 +455,18 @@ class NET_EXPORT_PRIVATE QuicPacket : public QuicData { length() - kStartOfEncryptedData); } - bool IsFecPacket() const { - return flags_ == PACKET_FLAGS_FEC; - } + bool is_fec_packet() const { return is_fec_packet_; } char* mutable_data() { return buffer_; } private: + QuicPacket(char* buffer, size_t length, bool owns_buffer, bool is_fec_packet) + : QuicData(buffer, length, owns_buffer), + buffer_(buffer), + is_fec_packet_(is_fec_packet) { } + char* buffer_; - const QuicPacketFlags flags_; + const bool is_fec_packet_; DISALLOW_COPY_AND_ASSIGN(QuicPacket); }; @@ -437,6 +487,18 @@ class NET_EXPORT_PRIVATE QuicEncryptedPacket : public QuicData { DISALLOW_COPY_AND_ASSIGN(QuicEncryptedPacket); }; +// 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. +struct QuicConsumedData { + QuicConsumedData(size_t bytes_consumed, bool fin_consumed) + : bytes_consumed(bytes_consumed), + fin_consumed(fin_consumed) { + } + size_t bytes_consumed; + bool fin_consumed; +}; + } // namespace net #endif // NET_QUIC_QUIC_PROTOCOL_H_ diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index 49490f6..f1872d2 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc @@ -78,8 +78,9 @@ bool QuicSession::OnPacket(const IPEndPoint& self_address, const IPEndPoint& peer_address, const QuicPacketHeader& header, const vector<QuicStreamFrame>& frames) { - if (header.guid != connection()->guid()) { - DLOG(INFO) << "Got packet header for invalid GUID: " << header.guid; + if (header.public_header.guid != connection()->guid()) { + DLOG(INFO) << "Got packet header for invalid GUID: " + << header.public_header.guid; return false; } for (size_t i = 0; i < frames.size(); ++i) { @@ -151,7 +152,7 @@ QuicConsumedData QuicSession::WriteData(QuicStreamId id, bool fin) { // TODO(wtc): type mismatch -- connection_->SendStreamData() returns a // size_t. - return connection_->SendStreamData(id, data, offset, fin, NULL); + return connection_->SendStreamData(id, data, offset, fin); } void QuicSession::SendRstStream(QuicStreamId id, diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index 9d9f848..c5c8b265 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h @@ -50,8 +50,10 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { // indicating if the fin bit was consumed. This does not indicate the data // has been sent on the wire: it may have been turned into a packet and queued // if the socket was unexpectedly blocked. - virtual QuicConsumedData WriteData(QuicStreamId id, base::StringPiece data, - QuicStreamOffset offset, bool fin); + virtual QuicConsumedData WriteData(QuicStreamId id, + base::StringPiece data, + QuicStreamOffset offset, + bool fin); // Called by streams when they want to close the stream in both directions. void SendRstStream(QuicStreamId id, QuicErrorCode error, diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index e9162b4..fdae38d 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc @@ -50,9 +50,10 @@ class QuicStreamFactoryTest : public ::testing::Test { QuicPacketSequenceNumber num, QuicStreamId stream_id) { QuicPacketHeader header; - header.guid = 0xDEADBEEF; + header.public_header.guid = 0xDEADBEEF; + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; header.packet_sequence_number = num; - header.flags = PACKET_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.fec_group = 0; QuicRstStreamFrame rst(stream_id, 0, QUIC_NO_ERROR); @@ -64,9 +65,10 @@ class QuicStreamFactoryTest : public ::testing::Test { QuicPacketSequenceNumber largest_received, QuicPacketSequenceNumber least_unacked) { QuicPacketHeader header; - header.guid = 0xDEADBEEF; + header.public_header.guid = 0xDEADBEEF; + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; header.packet_sequence_number = 2; - header.flags = PACKET_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.fec_group = 0; QuicAckFrame ack(largest_received, least_unacked); @@ -90,9 +92,10 @@ class QuicStreamFactoryTest : public ::testing::Test { scoped_ptr<QuicEncryptedPacket> ConstructFeedbackPacket( QuicPacketSequenceNumber sequence_number) { QuicPacketHeader header; - header.guid = 0xDEADBEEF; + header.public_header.guid = 0xDEADBEEF; + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; header.packet_sequence_number = sequence_number; - header.flags = PACKET_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.fec_group = 0; QuicCongestionFeedbackFrame frame; diff --git a/net/quic/quic_time.cc b/net/quic/quic_time.cc index b0d6434..7d3ba66 100644 --- a/net/quic/quic_time.cc +++ b/net/quic/quic_time.cc @@ -11,14 +11,14 @@ namespace net { // Highest number of microseconds that DateTimeOffset can hold. const int64 kQuicInfiniteTimeUs = GG_INT64_C(0x7fffffffffffffff) / 10; -QuicTime::Delta::Delta() - : delta_(base::TimeDelta::FromMicroseconds(0)) { -} - QuicTime::Delta::Delta(base::TimeDelta delta) : delta_(delta) { } +QuicTime::Delta QuicTime::Delta::Zero() { + return QuicTime::Delta::FromMicroseconds(0); +} + QuicTime::Delta QuicTime::Delta::Infinite() { return QuicTime::Delta::FromMicroseconds(kQuicInfiniteTimeUs); } @@ -61,8 +61,9 @@ QuicTime::Delta QuicTime::Delta::Subtract(const Delta& delta) const { delta.ToMicroseconds()); } - -QuicTime::QuicTime() { +// static +QuicTime QuicTime::Zero() { + return QuicTime::FromMilliseconds(0); } QuicTime::QuicTime(base::TimeTicks ticks) diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h index e5ca02a..a1fb6a3 100644 --- a/net/quic/quic_time.h +++ b/net/quic/quic_time.h @@ -23,14 +23,14 @@ class NET_EXPORT_PRIVATE QuicTime { // time, stored in microsecond resolution. class NET_EXPORT_PRIVATE Delta { public: - // Default constructor initializes to 0. - Delta(); - explicit Delta(base::TimeDelta delta); // Create a object with infinite offset time. static Delta Infinite(); + // Create a object with infinite offset time. + static Delta Zero(); + // Converts a number of milliseconds to a time offset. static Delta FromMilliseconds(int64 ms); @@ -60,11 +60,12 @@ class NET_EXPORT_PRIVATE QuicTime { friend class QuicTime; }; - // Default constructor initializes to time 0. - QuicTime(); - explicit QuicTime(base::TimeTicks ticks); + // Creates a new QuicTime with an internal value of 0. IsInitialized() + // will return true for these times. + static QuicTime Zero(); + // Create a new QuicTime holding the time_ms. static QuicTime FromMilliseconds(int64 time_ms); diff --git a/net/quic/quic_time_test.cc b/net/quic/quic_time_test.cc index 978bc43..5353289 100644 --- a/net/quic/quic_time_test.cc +++ b/net/quic/quic_time_test.cc @@ -14,13 +14,14 @@ class QuicTimeDeltaTest : public ::testing::Test { }; TEST_F(QuicTimeDeltaTest, Zero) { - EXPECT_TRUE(QuicTime::Delta().IsZero()); + EXPECT_TRUE(QuicTime::Delta::Zero().IsZero()); + EXPECT_FALSE(QuicTime::Delta::Zero().IsInfinite()); EXPECT_FALSE(QuicTime::Delta::FromMilliseconds(1).IsZero()); } TEST_F(QuicTimeDeltaTest, Infinite) { EXPECT_TRUE(QuicTime::Delta::Infinite().IsInfinite()); - EXPECT_FALSE(QuicTime::Delta().IsInfinite()); + EXPECT_FALSE(QuicTime::Delta::Zero().IsInfinite()); EXPECT_FALSE(QuicTime::Delta::FromMilliseconds(1).IsInfinite()); } @@ -34,7 +35,7 @@ TEST_F(QuicTimeDeltaTest, FromTo) { TEST_F(QuicTimeDeltaTest, Add) { EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2000), - QuicTime::Delta().Add(QuicTime::Delta::FromMilliseconds(2))); + QuicTime::Delta::Zero().Add(QuicTime::Delta::FromMilliseconds(2))); } TEST_F(QuicTimeDeltaTest, Subtract) { @@ -49,7 +50,7 @@ class QuicTimeTest : public ::testing::Test { }; TEST_F(QuicTimeTest, Initialized) { - EXPECT_FALSE(QuicTime().IsInitialized()); + EXPECT_FALSE(QuicTime::Zero().IsInitialized()); EXPECT_TRUE(QuicTime::FromMilliseconds(1).IsInitialized()); } diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index 5c38cbd..1de1eb9 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc @@ -111,10 +111,11 @@ QuicConsumedData ReliableQuicStream::WriteOrBuffer(StringPiece data, bool fin) { if (queued_data_.empty()) { consumed_data = WriteDataInternal(string(data.data(), data.length()), fin); + DCHECK_LE(consumed_data.bytes_consumed, data.length()); } - // if there's unconsumed data or an unconsumed fin, queue it. - if (consumed_data.bytes_consumed != data.length() || + // If there's unconsumed data or an unconsumed fin, queue it. + if (consumed_data.bytes_consumed < data.length() || (fin && !consumed_data.fin_consumed)) { queued_data_.push_back( string(data.data() + consumed_data.bytes_consumed, diff --git a/net/quic/test_tools/mock_clock.cc b/net/quic/test_tools/mock_clock.cc index 528865b..b85ae19 100644 --- a/net/quic/test_tools/mock_clock.cc +++ b/net/quic/test_tools/mock_clock.cc @@ -6,7 +6,7 @@ namespace net { -MockClock::MockClock() { +MockClock::MockClock() : now_(QuicTime::Zero()) { } MockClock::~MockClock() { @@ -22,13 +22,13 @@ QuicTime MockClock::Now() const { } QuicTime::Delta MockClock::NowAsDeltaSinceUnixEpoch() const { - return now_.Subtract(QuicTime()); + return now_.Subtract(QuicTime::Zero()); } base::TimeTicks MockClock::NowInTicks() const { base::TimeTicks ticks; return ticks + base::TimeDelta::FromMicroseconds( - now_.Subtract(QuicTime()).ToMicroseconds()); + now_.Subtract(QuicTime::Zero()).ToMicroseconds()); } } // namespace net diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc index 010380e..1411e5b 100644 --- a/net/quic/test_tools/quic_connection_peer.cc +++ b/net/quic/test_tools/quic_connection_peer.cc @@ -4,6 +4,7 @@ #include "net/quic/test_tools/quic_connection_peer.h" +#include "net/quic/congestion_control/quic_congestion_manager.h" #include "net/quic/congestion_control/quic_receipt_metrics_collector.h" #include "net/quic/congestion_control/quic_send_scheduler.h" #include "net/quic/quic_connection.h" @@ -19,13 +20,13 @@ void QuicConnectionPeer::SendAck(QuicConnection* connection) { // static void QuicConnectionPeer::SetCollector(QuicConnection* connection, QuicReceiptMetricsCollector* collector) { - connection->collector_.reset(collector); + connection->congestion_manager_.collector_.reset(collector); } // static void QuicConnectionPeer::SetScheduler(QuicConnection* connection, QuicSendScheduler* scheduler) { - connection->scheduler_.reset(scheduler); + connection->congestion_manager_.scheduler_.reset(scheduler); } // static @@ -39,6 +40,12 @@ QuicConnectionVisitorInterface* QuicConnectionPeer::GetVisitor( return connection->visitor_; } +// static +QuicPacketCreator* QuicConnectionPeer::GetPacketCreator( + QuicConnection* connection) { + return &connection->packet_creator_; +} + bool QuicConnectionPeer::GetReceivedTruncatedAck(QuicConnection* connection) { return connection->received_truncated_ack_; } diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h index 532d1e4..46b20929 100644 --- a/net/quic/test_tools/quic_connection_peer.h +++ b/net/quic/test_tools/quic_connection_peer.h @@ -12,6 +12,7 @@ namespace net { struct QuicAckFrame; class QuicConnection; class QuicConnectionVisitorInterface; +class QuicPacketCreator; class QuicReceiptMetricsCollector; class QuicSendScheduler; @@ -33,6 +34,8 @@ class QuicConnectionPeer { static QuicConnectionVisitorInterface* GetVisitor( QuicConnection* connection); + static QuicPacketCreator* GetPacketCreator(QuicConnection* connection); + static bool GetReceivedTruncatedAck(QuicConnection* connection); private: diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index 052bd95..92793d1 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc @@ -103,9 +103,9 @@ PacketSavingConnection::~PacketSavingConnection() { bool PacketSavingConnection::SendPacket(QuicPacketSequenceNumber number, QuicPacket* packet, - bool should_resend, + bool should_retransmit, bool force, - bool is_retransmit) { + bool is_retransmission) { packets_.push_back(packet); return true; } @@ -210,9 +210,10 @@ QuicPacket* ConstructHandshakePacket(QuicGuid guid, CryptoTag tag) { QuicEncrypter::Create(kNULL)); QuicPacketHeader header; - header.guid = guid; + header.public_header.guid = guid; + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; header.packet_sequence_number = 1; - header.flags = PACKET_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.fec_group = 0; QuicStreamFrame stream_frame(kCryptoStreamId, false, 0, @@ -240,9 +241,10 @@ QuicPacket* ConstructClientHelloPacket(QuicGuid guid, QuicEncrypter::Create(kNULL)); QuicPacketHeader header; - header.guid = guid; + header.public_header.guid = guid; + header.public_header.flags = PACKET_PUBLIC_FLAGS_NONE; header.packet_sequence_number = 1; - header.flags = PACKET_FLAGS_NONE; + header.private_flags = PACKET_PRIVATE_FLAGS_NONE; header.fec_group = 0; QuicStreamFrame stream_frame(kCryptoStreamId, false, 0, diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 0c2207f..c8e26c9 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h @@ -139,8 +139,7 @@ class MockHelper : public QuicConnectionHelperInterface { QuicRandom* GetRandomGenerator(); MOCK_METHOD2(WritePacketToWire, int(const QuicEncryptedPacket& packet, int* error)); - MOCK_METHOD2(SetResendAlarm, void(QuicPacketSequenceNumber sequence_number, - QuicTime::Delta delay)); + MOCK_METHOD1(SetRetransmissionAlarm, void(QuicTime::Delta delay)); MOCK_METHOD1(SetAckAlarm, void(QuicTime::Delta delay)); MOCK_METHOD1(SetSendAlarm, void(QuicTime::Delta delay)); MOCK_METHOD1(SetTimeoutAlarm, void(QuicTime::Delta delay)); @@ -183,9 +182,9 @@ class PacketSavingConnection : public MockConnection { virtual bool SendPacket(QuicPacketSequenceNumber number, QuicPacket* packet, - bool should_resend, + bool should_retransmit, bool force, - bool is_retransmit) OVERRIDE; + bool is_retransmission) OVERRIDE; std::vector<QuicPacket*> packets_; @@ -209,7 +208,8 @@ class MockSession : public QuicSession { MOCK_METHOD0(CreateOutgoingReliableStream, ReliableQuicStream*()); MOCK_METHOD4(WriteData, QuicConsumedData(QuicStreamId id, base::StringPiece data, - QuicStreamOffset offset, bool fin)); + QuicStreamOffset offset, + bool fin)); MOCK_METHOD0(IsHandshakeComplete, bool()); private: |