summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-03 07:47:41 +0000
committerrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-03 07:47:41 +0000
commitfee17f78c16789e740b050327e67abe76b500884 (patch)
treee6697c04381916b358fbc6759043ab28b9be56c5
parent7016f66d683e581d805c25cbde4db1fea933b255 (diff)
downloadchromium_src-fee17f78c16789e740b050327e67abe76b500884.zip
chromium_src-fee17f78c16789e740b050327e67abe76b500884.tar.gz
chromium_src-fee17f78c16789e740b050327e67abe76b500884.tar.bz2
Land recent QUIC changes.
Count the number of retransmissions for a packet due to RTO and explicit nacks and implement exponential backoff based on number of retransmissions. Merge internal change: 41823946 QuicConnection now packetizes acks and congestion control frames even more lazily and packs control frames with up to 1 stream frame. Merge internal change: 41805161 Remove nitty-gritties of QuicFramer from QuicTimeWaitListManager and remove some static methods from QuicFramer. Merge internal change: 41795314 Store socket addresses in QuicConnection.h instead of pushing it down to QuicFramer.h and getting it back from there. Merge internal change: 41768211 Retransmit largest_observed_ packet if its missing. Merge internal change: 41743584 Split framer packet creation into size determination and packet creation methods in order to ensure the maximum number of frames are fit into a single packet. Merge internal change: 41702016 Handle packet reordering for queued packets. Merge internal change: 41701179 Bug fix for retransmission order. Merge internal change: 41638847 Adding basic dispatcher stats for QUIC Merge internal change: 41630921 Minor fixes in quic_connection.cc Merge internal change: 41610652 Use priority queue to maintain the list of sequence numbers to be retransmitted. This will enable us to do an exponential backoff for lost packets. Merge internal change: 41582526 Adding DISALLOW_COPY_AND_ASSIGN to all congestion control classes that were missing it. And a few nits. Merge internal change: 41580553 Break circular dependency between quic_protocol.h and quic_bandwidth.h Merge internal change: 41578776 Fix uninitialized memory access in quic_framer_test. Merge internal change: 41558816 Cleanup, consolidated quic_send_scheduler with quic_congestion_manager Merge internal change: 41549823 Set the retransmit alarm only when we successfully write the packet to the socket instead of setting it when we attempt to write. Merge internal change: 41547192 Introduced QuicByteCount and moved TCP receive_bytes packing to QuicFramer where it belongs. Merge internal change: 41546840 Fix a bug with how FEC groups were being created in QUIC. Now opening multiple and always closing the group. Merge internal change: 41538221 Removing QUIC logspam Merge internal change: 41537896 Exposing ReadPublicHeader and ReadPublicResetPacket static methods which don't take a dependency on reader_(unlike Process..() methods). Merge internal change: 41535886 Use "test" not "testing" for test namespaces to be consistent with other QUIC code. Merge internal change: 41534488 Fix a number of minor issues that came up in landing recent chrome changes. Merge internal change: 41531793 Removed the QuicReceiptMetricsCollector and started using the ReceiveAlgorithmInterface directly in the CongestionManager. The QuicReceiptMetricsCollector did not provide any functionality. Merge internal change: 41486246 Integrating new quic bandwidth class Merge internal change: 41473682 R=jar@chromium.org BUG= Review URL: https://chromiumcodereview.appspot.com/12145002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@180299 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/net.gyp8
-rw-r--r--net/quic/congestion_control/cubic.h2
-rw-r--r--net/quic/congestion_control/fix_rate_receiver.cc11
-rw-r--r--net/quic/congestion_control/fix_rate_receiver.h15
-rw-r--r--net/quic/congestion_control/fix_rate_sender.cc50
-rw-r--r--net/quic/congestion_control/fix_rate_sender.h22
-rw-r--r--net/quic/congestion_control/fix_rate_test.cc59
-rw-r--r--net/quic/congestion_control/hybrid_slow_start.h2
-rw-r--r--net/quic/congestion_control/leaky_bucket.cc23
-rw-r--r--net/quic/congestion_control/leaky_bucket.h16
-rw-r--r--net/quic/congestion_control/leaky_bucket_test.cc14
-rw-r--r--net/quic/congestion_control/paced_sender.cc34
-rw-r--r--net/quic/congestion_control/paced_sender.h13
-rw-r--r--net/quic/congestion_control/paced_sender_test.cc20
-rw-r--r--net/quic/congestion_control/quic_congestion_manager.cc148
-rw-r--r--net/quic/congestion_control/quic_congestion_manager.h38
-rw-r--r--net/quic/congestion_control/quic_receipt_metrics_collector.cc34
-rw-r--r--net/quic/congestion_control/quic_receipt_metrics_collector.h57
-rw-r--r--net/quic/congestion_control/quic_receipt_metrics_collector_test.cc34
-rw-r--r--net/quic/congestion_control/quic_send_scheduler.cc176
-rw-r--r--net/quic/congestion_control/quic_send_scheduler.h85
-rw-r--r--net/quic/congestion_control/quic_send_scheduler_test.cc197
-rw-r--r--net/quic/congestion_control/receive_algorithm_interface.h2
-rw-r--r--net/quic/congestion_control/send_algorithm_interface.h20
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.cc40
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.h28
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender_test.cc50
-rw-r--r--net/quic/congestion_control/tcp_receiver.cc8
-rw-r--r--net/quic/congestion_control/tcp_receiver.h7
-rw-r--r--net/quic/congestion_control/tcp_receiver_test.cc4
-rw-r--r--net/quic/quic_bandwidth.cc20
-rw-r--r--net/quic/quic_bandwidth.h11
-rw-r--r--net/quic/quic_bandwidth_test.cc25
-rw-r--r--net/quic/quic_connection.cc490
-rw-r--r--net/quic/quic_connection.h123
-rw-r--r--net/quic/quic_connection_helper.cc2
-rw-r--r--net/quic/quic_connection_helper_test.cc34
-rw-r--r--net/quic/quic_connection_test.cc348
-rw-r--r--net/quic/quic_crypto_client_stream_test.cc3
-rw-r--r--net/quic/quic_data_writer.cc4
-rw-r--r--net/quic/quic_fec_group.cc4
-rw-r--r--net/quic/quic_fec_group.h14
-rw-r--r--net/quic/quic_framer.cc145
-rw-r--r--net/quic/quic_framer.h29
-rw-r--r--net/quic/quic_framer_test.cc77
-rw-r--r--net/quic/quic_http_stream_test.cc35
-rw-r--r--net/quic/quic_packet_creator.cc126
-rw-r--r--net/quic/quic_packet_creator.h43
-rw-r--r--net/quic/quic_packet_creator_test.cc127
-rw-r--r--net/quic/quic_protocol.cc10
-rw-r--r--net/quic/quic_protocol.h12
-rw-r--r--net/quic/quic_protocol_test.cc53
-rw-r--r--net/quic/quic_session.cc2
-rw-r--r--net/quic/quic_session.h2
-rw-r--r--net/quic/quic_time.h2
-rw-r--r--net/quic/quic_time_test.cc4
-rw-r--r--net/quic/quic_utils.cc4
-rw-r--r--net/quic/reliable_quic_stream_test.cc91
-rw-r--r--net/quic/test_tools/quic_connection_peer.cc41
-rw-r--r--net/quic/test_tools/quic_connection_peer.h23
-rw-r--r--net/quic/test_tools/quic_test_utils.cc25
-rw-r--r--net/quic/test_tools/quic_test_utils.h51
62 files changed, 1694 insertions, 1503 deletions
diff --git a/net/net.gyp b/net/net.gyp
index 035ec22..c7bf23b 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -667,10 +667,6 @@
'quic/congestion_control/paced_sender.h',
'quic/congestion_control/quic_congestion_manager.cc',
'quic/congestion_control/quic_congestion_manager.h',
- 'quic/congestion_control/quic_receipt_metrics_collector.cc',
- 'quic/congestion_control/quic_receipt_metrics_collector.h',
- 'quic/congestion_control/quic_send_scheduler.cc',
- 'quic/congestion_control/quic_send_scheduler.h',
'quic/congestion_control/receive_algorithm_interface.cc',
'quic/congestion_control/receive_algorithm_interface.h',
'quic/congestion_control/send_algorithm_interface.cc',
@@ -1482,8 +1478,6 @@
'quic/congestion_control/hybrid_slow_start_test.cc',
'quic/congestion_control/leaky_bucket_test.cc',
'quic/congestion_control/paced_sender_test.cc',
- 'quic/congestion_control/quic_receipt_metrics_collector_test.cc',
- 'quic/congestion_control/quic_send_scheduler_test.cc',
'quic/congestion_control/tcp_cubic_sender_test.cc',
'quic/congestion_control/tcp_receiver_test.cc',
'quic/crypto/crypto_framer_test.cc',
@@ -1516,11 +1510,13 @@
'quic/quic_framer_test.cc',
'quic/quic_http_stream_test.cc',
'quic/quic_packet_creator_test.cc',
+ 'quic/quic_protocol_test.cc',
'quic/quic_reliable_client_stream_test.cc',
'quic/quic_session_test.cc',
'quic/quic_stream_factory_test.cc',
'quic/quic_stream_sequencer_test.cc',
'quic/quic_time_test.cc',
+ 'quic/reliable_quic_stream_test.cc',
'socket/buffered_write_stream_socket_unittest.cc',
'socket/client_socket_pool_base_unittest.cc',
'socket/deterministic_socket_data_unittest.cc',
diff --git a/net/quic/congestion_control/cubic.h b/net/quic/congestion_control/cubic.h
index 4c013a9..e365bbe 100644
--- a/net/quic/congestion_control/cubic.h
+++ b/net/quic/congestion_control/cubic.h
@@ -79,6 +79,8 @@ class NET_EXPORT_PRIVATE Cubic {
// Last congestion window in packets computed by cubic function.
QuicTcpCongestionWindow last_target_congestion_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(Cubic);
};
} // namespace net
diff --git a/net/quic/congestion_control/fix_rate_receiver.cc b/net/quic/congestion_control/fix_rate_receiver.cc
index b2b5f8e..950b49c 100644
--- a/net/quic/congestion_control/fix_rate_receiver.cc
+++ b/net/quic/congestion_control/fix_rate_receiver.cc
@@ -14,27 +14,22 @@ namespace {
namespace net {
FixRateReceiver::FixRateReceiver()
- : bitrate_in_bytes_per_second_(kInitialBitrate) {
+ : configured_rate_(QuicBandwidth::FromBytesPerSecond(kInitialBitrate)) {
}
bool FixRateReceiver::GenerateCongestionFeedback(
QuicCongestionFeedbackFrame* feedback) {
feedback->type = kFixRate;
- feedback->fix_rate.bitrate_in_bytes_per_second =
- bitrate_in_bytes_per_second_;
+ feedback->fix_rate.bitrate = configured_rate_;
return true;
}
void FixRateReceiver::RecordIncomingPacket(
- size_t /*bytes*/,
+ QuicByteCount /*bytes*/,
QuicPacketSequenceNumber /*sequence_number*/,
QuicTime /*timestamp*/,
bool /*recovered*/) {
// Nothing to do for this simple implementation.
}
-void FixRateReceiver::SetBitrate(int bytes_per_second) {
- bitrate_in_bytes_per_second_ = bytes_per_second;
-}
-
} // namespace net
diff --git a/net/quic/congestion_control/fix_rate_receiver.h b/net/quic/congestion_control/fix_rate_receiver.h
index d550f13..690f138 100644
--- a/net/quic/congestion_control/fix_rate_receiver.h
+++ b/net/quic/congestion_control/fix_rate_receiver.h
@@ -11,9 +11,14 @@
#include "base/compiler_specific.h"
#include "net/base/net_export.h"
#include "net/quic/congestion_control/receive_algorithm_interface.h"
+#include "net/quic/quic_bandwidth.h"
namespace net {
+namespace test {
+class FixRateReceiverPeer;
+} // namespace test
+
class NET_EXPORT_PRIVATE FixRateReceiver : public ReceiveAlgorithmInterface {
public:
FixRateReceiver();
@@ -23,17 +28,17 @@ class NET_EXPORT_PRIVATE FixRateReceiver : public ReceiveAlgorithmInterface {
QuicCongestionFeedbackFrame* feedback) OVERRIDE;
// Implements ReceiveAlgorithmInterface.
- virtual void RecordIncomingPacket(size_t bytes,
+ virtual void RecordIncomingPacket(QuicByteCount bytes,
QuicPacketSequenceNumber sequence_number,
QuicTime timestamp,
bool recovered) OVERRIDE;
+ private:
+ friend class test::FixRateReceiverPeer;
- void SetBitrate(int bytes_per_second); // Used for testing only.
+ QuicBandwidth configured_rate_;
- private:
- int bitrate_in_bytes_per_second_;
+ DISALLOW_COPY_AND_ASSIGN(FixRateReceiver);
};
} // namespace net
-
#endif // NET_QUIC_CONGESTION_CONTROL_FIX_RATE_RECEIVER_H_
diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc
index 758a6c1..2738526 100644
--- a/net/quic/congestion_control/fix_rate_sender.cc
+++ b/net/quic/congestion_control/fix_rate_sender.cc
@@ -7,7 +7,6 @@
#include <math.h>
#include "base/logging.h"
-#include "base/time.h"
#include "net/quic/quic_protocol.h"
namespace {
@@ -18,10 +17,10 @@ namespace {
namespace net {
FixRateSender::FixRateSender(const QuicClock* clock)
- : bitrate_in_bytes_per_s_(kInitialBitrate),
- fix_rate_leaky_bucket_(clock, kInitialBitrate),
- paced_sender_(clock, kInitialBitrate),
- bytes_in_flight_(0) {
+ : bitrate_(QuicBandwidth::FromBytesPerSecond(kInitialBitrate)),
+ fix_rate_leaky_bucket_(clock, bitrate_),
+ paced_sender_(clock, bitrate_),
+ data_in_flight_(0) {
DLOG(INFO) << "FixRateSender";
}
@@ -31,19 +30,18 @@ void FixRateSender::OnIncomingQuicCongestionFeedbackFrame(
DCHECK(feedback.type == kFixRate) <<
"Invalid incoming CongestionFeedbackType:" << feedback.type;
if (feedback.type == kFixRate) {
- bitrate_in_bytes_per_s_ =
- feedback.fix_rate.bitrate_in_bytes_per_second;
- fix_rate_leaky_bucket_.SetDrainingRate(bitrate_in_bytes_per_s_);
- paced_sender_.UpdateBandwidthEstimate(bitrate_in_bytes_per_s_);
+ bitrate_ = feedback.fix_rate.bitrate;
+ fix_rate_leaky_bucket_.SetDrainingRate(bitrate_);
+ paced_sender_.UpdateBandwidthEstimate(bitrate_);
}
// Silently ignore invalid messages in release mode.
}
void FixRateSender::OnIncomingAck(
QuicPacketSequenceNumber /*acked_sequence_number*/,
- size_t bytes_acked,
+ QuicByteCount bytes_acked,
QuicTime::Delta /*rtt*/) {
- bytes_in_flight_ -= bytes_acked;
+ data_in_flight_ -= bytes_acked;
}
void FixRateSender::OnIncomingLoss(int /*number_of_lost_packets*/) {
@@ -51,23 +49,22 @@ void FixRateSender::OnIncomingLoss(int /*number_of_lost_packets*/) {
}
void FixRateSender::SentPacket(QuicPacketSequenceNumber /*sequence_number*/,
- size_t bytes,
+ QuicByteCount bytes,
bool is_retransmission) {
fix_rate_leaky_bucket_.Add(bytes);
paced_sender_.SentPacket(bytes);
if (!is_retransmission) {
- bytes_in_flight_ += bytes;
+ data_in_flight_ += bytes;
}
}
QuicTime::Delta FixRateSender::TimeUntilSend(bool /*is_retransmission*/) {
if (CongestionWindow() > fix_rate_leaky_bucket_.BytesPending()) {
- if (CongestionWindow() <= bytes_in_flight_) {
+ if (CongestionWindow() <= data_in_flight_) {
// We need an ack before we send more.
return QuicTime::Delta::Infinite();
}
- QuicTime::Delta zero_time(QuicTime::Delta::Zero());
- return paced_sender_.TimeUntilSend(zero_time);
+ return paced_sender_.TimeUntilSend(QuicTime::Delta::Zero());
}
QuicTime::Delta time_remaining = fix_rate_leaky_bucket_.TimeRemaining();
if (time_remaining.IsZero()) {
@@ -77,24 +74,25 @@ QuicTime::Delta FixRateSender::TimeUntilSend(bool /*is_retransmission*/) {
return paced_sender_.TimeUntilSend(time_remaining);
}
-size_t FixRateSender::CongestionWindow() {
- size_t window_size = bitrate_in_bytes_per_s_ * kWindowSizeUs /
- base::Time::kMicrosecondsPerSecond;
+QuicByteCount FixRateSender::CongestionWindow() {
+ QuicByteCount window_size_bytes = bitrate_.ToBytesPerPeriod(
+ QuicTime::Delta::FromMicroseconds(kWindowSizeUs));
// Make sure window size is not less than a packet.
- return std::max(kMaxPacketSize, window_size);
+ return std::max(kMaxPacketSize, window_size_bytes);
}
-size_t FixRateSender::AvailableCongestionWindow() {
- size_t congestion_window = CongestionWindow();
- if (bytes_in_flight_ >= congestion_window) {
+QuicByteCount FixRateSender::AvailableCongestionWindow() {
+ QuicByteCount congestion_window = CongestionWindow();
+ if (data_in_flight_ >= congestion_window) {
return 0;
}
- size_t available_congestion_window = congestion_window - bytes_in_flight_;
+ QuicByteCount available_congestion_window = congestion_window -
+ data_in_flight_;
return paced_sender_.AvailableWindow(available_congestion_window);
}
-int FixRateSender::BandwidthEstimate() {
- return bitrate_in_bytes_per_s_;
+QuicBandwidth FixRateSender::BandwidthEstimate() {
+ return bitrate_;
}
} // namespace net
diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h
index 1c91fd0..4e864b7 100644
--- a/net/quic/congestion_control/fix_rate_sender.h
+++ b/net/quic/congestion_control/fix_rate_sender.h
@@ -18,6 +18,10 @@
namespace net {
+namespace test {
+class FixRateSenderPeer;
+} // namespace test
+
class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface {
public:
explicit FixRateSender(const QuicClock* clock);
@@ -27,24 +31,28 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface {
const QuicCongestionFeedbackFrame& feedback,
const SentPacketsMap& sent_packets) OVERRIDE;
virtual void OnIncomingAck(QuicPacketSequenceNumber acked_sequence_number,
- size_t acked_bytes,
+ QuicByteCount acked_bytes,
QuicTime::Delta rtt) OVERRIDE;
virtual void OnIncomingLoss(int number_of_lost_packets) OVERRIDE;
virtual void SentPacket(QuicPacketSequenceNumber equence_number,
- size_t bytes,
+ QuicByteCount bytes,
bool is_retransmission) OVERRIDE;
virtual QuicTime::Delta TimeUntilSend(bool is_retransmission) OVERRIDE;
- virtual size_t AvailableCongestionWindow() OVERRIDE;
- virtual int BandwidthEstimate() OVERRIDE;
+ virtual QuicBandwidth BandwidthEstimate() OVERRIDE;
// End implementation of SendAlgorithmInterface.
private:
- size_t CongestionWindow();
+ friend class test::FixRateSenderPeer;
+
+ QuicByteCount AvailableCongestionWindow();
+ QuicByteCount CongestionWindow();
- uint32 bitrate_in_bytes_per_s_;
+ QuicBandwidth bitrate_;
LeakyBucket fix_rate_leaky_bucket_;
PacedSender paced_sender_;
- size_t bytes_in_flight_;
+ QuicByteCount data_in_flight_;
+
+ DISALLOW_COPY_AND_ASSIGN(FixRateSender);
};
} // namespace net
diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc
index 33a739f..2c0770a 100644
--- a/net/quic/congestion_control/fix_rate_test.cc
+++ b/net/quic/congestion_control/fix_rate_test.cc
@@ -15,44 +15,62 @@
namespace net {
namespace test {
+class FixRateSenderPeer : public FixRateSender {
+ public:
+ explicit FixRateSenderPeer(const QuicClock* clock)
+ : FixRateSender(clock) {
+ }
+ using FixRateSender::AvailableCongestionWindow;
+};
+
+class FixRateReceiverPeer : public FixRateReceiver {
+ public:
+ FixRateReceiverPeer()
+ : FixRateReceiver() {
+ }
+ void SetBitrate(QuicBandwidth fix_rate) {
+ FixRateReceiver::configured_rate_ = fix_rate;
+ }
+};
+
class FixRateTest : public ::testing::Test {
protected:
FixRateTest()
- : rtt_(QuicTime::Delta::FromMilliseconds(30)) {
- }
- void SetUp() {
- sender_.reset(new FixRateSender(&clock_));
- receiver_.reset(new FixRateReceiver());
+ : rtt_(QuicTime::Delta::FromMilliseconds(30)),
+ sender_(new FixRateSenderPeer(&clock_)),
+ receiver_(new FixRateReceiverPeer()) {
// Make sure clock does not start at 0.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2));
}
const QuicTime::Delta rtt_;
MockClock clock_;
SendAlgorithmInterface::SentPacketsMap not_used_;
- scoped_ptr<FixRateSender> sender_;
- scoped_ptr<FixRateReceiver> receiver_;
+ scoped_ptr<FixRateSenderPeer> sender_;
+ scoped_ptr<FixRateReceiverPeer> receiver_;
};
TEST_F(FixRateTest, ReceiverAPI) {
QuicCongestionFeedbackFrame feedback;
QuicTime timestamp(QuicTime::Zero());
- receiver_->SetBitrate(300000); // Bytes per second.
+ receiver_->SetBitrate(QuicBandwidth::FromKBytesPerSecond(300));
receiver_->RecordIncomingPacket(1, 1, timestamp, false);
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
EXPECT_EQ(kFixRate, feedback.type);
- EXPECT_EQ(300000u, feedback.fix_rate.bitrate_in_bytes_per_second);
+ EXPECT_EQ(300000u, feedback.fix_rate.bitrate.ToBytesPerSecond());
}
TEST_F(FixRateTest, SenderAPI) {
QuicCongestionFeedbackFrame feedback;
feedback.type = kFixRate;
- feedback.fix_rate.bitrate_in_bytes_per_second = 300000;
+ feedback.fix_rate.bitrate = QuicBandwidth::FromKBytesPerSecond(300);
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_);
- EXPECT_EQ(300000, sender_->BandwidthEstimate());
+ EXPECT_EQ(300000, sender_->BandwidthEstimate().ToBytesPerSecond());
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
- EXPECT_EQ(kMaxPacketSize * 2, sender_->AvailableCongestionWindow());
+ EXPECT_EQ(kMaxPacketSize * 2,
+ sender_->AvailableCongestionWindow());
sender_->SentPacket(1, kMaxPacketSize, false);
- EXPECT_EQ(3000u - kMaxPacketSize, sender_->AvailableCongestionWindow());
+ EXPECT_EQ(3000u - kMaxPacketSize,
+ sender_->AvailableCongestionWindow());
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
sender_->SentPacket(2, kMaxPacketSize, false);
sender_->SentPacket(3, 600, false);
@@ -69,18 +87,19 @@ TEST_F(FixRateTest, SenderAPI) {
}
TEST_F(FixRateTest, FixRatePacing) {
- const int64 packet_size = 1200;
- const int64 bit_rate = 240000;
+ const QuicByteCount packet_size = 1200;
+ const QuicBandwidth bitrate = QuicBandwidth::FromKBytesPerSecond(240);
const int64 num_packets = 200;
QuicCongestionFeedbackFrame feedback;
- receiver_->SetBitrate(240000); // Bytes per second.
+ receiver_->SetBitrate(QuicBandwidth::FromKBytesPerSecond(240));
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, not_used_);
QuicTime acc_advance_time(QuicTime::Zero());
QuicPacketSequenceNumber sequence_number = 0;
- for (int i = 0; i < num_packets; i += 2) {
+ for (int64 i = 0; i < num_packets; i += 2) {
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
- EXPECT_EQ(kMaxPacketSize * 2, sender_->AvailableCongestionWindow());
+ EXPECT_EQ(kMaxPacketSize * 2,
+ sender_->AvailableCongestionWindow());
sender_->SentPacket(sequence_number++, packet_size, false);
EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
sender_->SentPacket(sequence_number++, packet_size, false);
@@ -90,8 +109,8 @@ TEST_F(FixRateTest, FixRatePacing) {
sender_->OnIncomingAck(sequence_number - 2, packet_size, rtt_);
acc_advance_time = acc_advance_time.Add(advance_time);
}
- EXPECT_EQ(num_packets * packet_size * 1000000 / bit_rate,
- acc_advance_time.ToMicroseconds());
+ EXPECT_EQ(num_packets * packet_size * 1000000 / bitrate.ToBytesPerSecond(),
+ static_cast<uint64>(acc_advance_time.ToMicroseconds()));
}
} // namespace test
diff --git a/net/quic/congestion_control/hybrid_slow_start.h b/net/quic/congestion_control/hybrid_slow_start.h
index cb3345c..cee9c73 100644
--- a/net/quic/congestion_control/hybrid_slow_start.h
+++ b/net/quic/congestion_control/hybrid_slow_start.h
@@ -56,6 +56,8 @@ class NET_EXPORT_PRIVATE HybridSlowStart {
QuicTime last_time_; // Last time when the ACK spacing was close.
uint8 sample_count_; // Number of samples to decide current RTT.
QuicTime::Delta current_rtt_; // The minimum rtt of current round.
+
+ DISALLOW_COPY_AND_ASSIGN(HybridSlowStart);
};
} // namespace net
diff --git a/net/quic/congestion_control/leaky_bucket.cc b/net/quic/congestion_control/leaky_bucket.cc
index 60ec7a6..0012ae8 100644
--- a/net/quic/congestion_control/leaky_bucket.cc
+++ b/net/quic/congestion_control/leaky_bucket.cc
@@ -8,19 +8,19 @@
namespace net {
-LeakyBucket::LeakyBucket(const QuicClock* clock, int bytes_per_second)
+LeakyBucket::LeakyBucket(const QuicClock* clock, QuicBandwidth draining_rate)
: clock_(clock),
bytes_(0),
time_last_updated_(QuicTime::Zero()),
- draining_rate_bytes_per_s_(bytes_per_second) {
+ draining_rate_(draining_rate) {
}
-void LeakyBucket::SetDrainingRate(int bytes_per_second) {
+void LeakyBucket::SetDrainingRate(QuicBandwidth draining_rate) {
Update();
- draining_rate_bytes_per_s_ = bytes_per_second;
+ draining_rate_ = draining_rate;
}
-void LeakyBucket::Add(size_t bytes) {
+void LeakyBucket::Add(QuicByteCount bytes) {
Update();
bytes_ += bytes;
}
@@ -29,25 +29,24 @@ QuicTime::Delta LeakyBucket::TimeRemaining() {
Update();
return QuicTime::Delta::FromMicroseconds(
(bytes_ * base::Time::kMicrosecondsPerSecond) /
- draining_rate_bytes_per_s_);
+ draining_rate_.ToBytesPerSecond());
}
-size_t LeakyBucket::BytesPending() {
+QuicByteCount LeakyBucket::BytesPending() {
Update();
return bytes_;
}
void LeakyBucket::Update() {
- QuicTime::Delta elapsed_time = clock_->Now().Subtract(time_last_updated_);
- size_t bytes_cleared =
- (elapsed_time.ToMicroseconds() * draining_rate_bytes_per_s_) /
- base::Time::kMicrosecondsPerSecond;
+ QuicTime now = clock_->Now();
+ QuicTime::Delta elapsed_time = now.Subtract(time_last_updated_);
+ QuicByteCount bytes_cleared = draining_rate_.ToBytesPerPeriod(elapsed_time);
if (bytes_cleared >= bytes_) {
bytes_ = 0;
} else {
bytes_ -= bytes_cleared;
}
- time_last_updated_ = clock_->Now();
+ time_last_updated_ = now;
}
} // namespace net
diff --git a/net/quic/congestion_control/leaky_bucket.h b/net/quic/congestion_control/leaky_bucket.h
index 0ea8bc7..be138982 100644
--- a/net/quic/congestion_control/leaky_bucket.h
+++ b/net/quic/congestion_control/leaky_bucket.h
@@ -12,7 +12,9 @@
#include "base/basictypes.h"
#include "net/base/net_export.h"
+#include "net/quic/quic_bandwidth.h"
#include "net/quic/quic_clock.h"
+#include "net/quic/quic_protocol.h"
#include "net/quic/quic_time.h"
namespace net {
@@ -20,27 +22,29 @@ namespace net {
class NET_EXPORT_PRIVATE LeakyBucket {
public:
// clock is not owned by this class.
- LeakyBucket(const QuicClock* clock, int bytes_per_second);
+ LeakyBucket(const QuicClock* clock, QuicBandwidth draining_rate);
// Set the rate at which the bytes leave the buffer.
- void SetDrainingRate(int bytes_per_second);
+ void SetDrainingRate(QuicBandwidth draining_rate);
// Add data to the buffer.
- void Add(size_t bytes);
+ void Add(QuicByteCount bytes);
// Time until the buffer is empty in us.
QuicTime::Delta TimeRemaining();
// Number of bytes in the buffer.
- size_t BytesPending();
+ QuicByteCount BytesPending();
private:
void Update();
const QuicClock* clock_;
- size_t bytes_;
+ QuicByteCount bytes_;
QuicTime time_last_updated_;
- int draining_rate_bytes_per_s_;
+ QuicBandwidth draining_rate_;
+
+ DISALLOW_COPY_AND_ASSIGN(LeakyBucket);
};
} // namespace net
diff --git a/net/quic/congestion_control/leaky_bucket_test.cc b/net/quic/congestion_control/leaky_bucket_test.cc
index f0e6ec0..a510200 100644
--- a/net/quic/congestion_control/leaky_bucket_test.cc
+++ b/net/quic/congestion_control/leaky_bucket_test.cc
@@ -14,15 +14,15 @@ namespace test {
class LeakyBucketTest : public ::testing::Test {
protected:
void SetUp() {
- leaky_bucket_.reset(new LeakyBucket(&clock_, 0));
+ leaky_bucket_.reset(new LeakyBucket(&clock_, QuicBandwidth::Zero()));
}
MockClock clock_;
scoped_ptr<LeakyBucket> leaky_bucket_;
};
TEST_F(LeakyBucketTest, Basic) {
- int bytes_per_second = 200000;
- leaky_bucket_->SetDrainingRate(bytes_per_second);
+ QuicBandwidth draining_rate = QuicBandwidth::FromBytesPerSecond(200000);
+ leaky_bucket_->SetDrainingRate(draining_rate);
leaky_bucket_->Add(2000);
EXPECT_EQ(2000u, leaky_bucket_->BytesPending());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
@@ -54,8 +54,8 @@ TEST_F(LeakyBucketTest, Basic) {
}
TEST_F(LeakyBucketTest, ChangeDrainRate) {
- int bytes_per_second = 200000;
- leaky_bucket_->SetDrainingRate(bytes_per_second);
+ QuicBandwidth draining_rate = QuicBandwidth::FromBytesPerSecond(200000);
+ leaky_bucket_->SetDrainingRate(draining_rate);
leaky_bucket_->Add(2000);
EXPECT_EQ(2000u, leaky_bucket_->BytesPending());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
@@ -64,8 +64,8 @@ TEST_F(LeakyBucketTest, ChangeDrainRate) {
EXPECT_EQ(1000u, leaky_bucket_->BytesPending());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(5),
leaky_bucket_->TimeRemaining());
- bytes_per_second = 100000; // Cut drain rate in half.
- leaky_bucket_->SetDrainingRate(bytes_per_second);
+ draining_rate = draining_rate.Scale(0.5f); // Cut drain rate in half.
+ leaky_bucket_->SetDrainingRate(draining_rate);
EXPECT_EQ(1000u, leaky_bucket_->BytesPending());
EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
leaky_bucket_->TimeRemaining());
diff --git a/net/quic/congestion_control/paced_sender.cc b/net/quic/congestion_control/paced_sender.cc
index 38419d0..f44aa33 100644
--- a/net/quic/congestion_control/paced_sender.cc
+++ b/net/quic/congestion_control/paced_sender.cc
@@ -4,28 +4,27 @@
#include "net/quic/congestion_control/paced_sender.h"
-#include "base/time.h"
#include "net/quic/quic_protocol.h"
namespace net {
// To prevent too aggressive pacing we allow the following packet burst size.
-const size_t kMinPacketBurstSize = 2;
+const int64 kMinPacketBurstSize = 2;
// Max estimated time between calls to TimeUntilSend and
// AvailableCongestionWindow.
const int64 kMaxSchedulingDelayUs = 2000;
-PacedSender::PacedSender(const QuicClock* clock, int bytes_per_s)
- : leaky_bucket_(clock, bytes_per_s),
- pace_in_bytes_per_s_(bytes_per_s) {
+PacedSender::PacedSender(const QuicClock* clock, QuicBandwidth estimate)
+ : leaky_bucket_(clock, estimate),
+ pace_(estimate) {
}
-void PacedSender::UpdateBandwidthEstimate(int bytes_per_s) {
- leaky_bucket_.SetDrainingRate(bytes_per_s);
- pace_in_bytes_per_s_ = bytes_per_s;
+void PacedSender::UpdateBandwidthEstimate(QuicBandwidth estimate) {
+ leaky_bucket_.SetDrainingRate(estimate);
+ pace_ = estimate;
}
-void PacedSender::SentPacket(size_t bytes) {
+void PacedSender::SentPacket(QuicByteCount bytes) {
leaky_bucket_.Add(bytes);
}
@@ -34,9 +33,9 @@ QuicTime::Delta PacedSender::TimeUntilSend(QuicTime::Delta time_until_send) {
return time_until_send;
}
// Pace the data.
- size_t pacing_window = kMaxSchedulingDelayUs * pace_in_bytes_per_s_ /
- base::Time::kMicrosecondsPerSecond;
- size_t min_window_size = kMinPacketBurstSize * kMaxPacketSize;
+ QuicByteCount pacing_window = pace_.ToBytesPerPeriod(
+ QuicTime::Delta::FromMicroseconds(kMaxSchedulingDelayUs));
+ QuicByteCount min_window_size = kMinPacketBurstSize * kMaxPacketSize;
pacing_window = std::max(pacing_window, min_window_size);
if (pacing_window > leaky_bucket_.BytesPending()) {
@@ -46,10 +45,11 @@ QuicTime::Delta PacedSender::TimeUntilSend(QuicTime::Delta time_until_send) {
return leaky_bucket_.TimeRemaining();
}
-size_t PacedSender::AvailableWindow(size_t available_congestion_window) {
- size_t accuracy_window = (kMaxSchedulingDelayUs * pace_in_bytes_per_s_) /
- base::Time::kMicrosecondsPerSecond;
- size_t min_burst_window = kMinPacketBurstSize * kMaxPacketSize;
+QuicByteCount PacedSender::AvailableWindow(
+ QuicByteCount available_congestion_window) {
+ QuicByteCount accuracy_window = pace_.ToBytesPerPeriod(
+ QuicTime::Delta::FromMicroseconds(kMaxSchedulingDelayUs));
+ QuicByteCount min_burst_window = kMinPacketBurstSize * kMaxPacketSize;
DLOG(INFO) << "Available congestion window:" << available_congestion_window
<< " accuracy window:" << accuracy_window
<< " min burst window:" << min_burst_window;
@@ -61,7 +61,7 @@ size_t PacedSender::AvailableWindow(size_t available_congestion_window) {
// burst we also consider our timing accuracy. An accuracy of 1 ms will
// allow us to send up to 19.2Mbit/s with 2 packets per burst.
available_congestion_window = std::max(min_burst_window, accuracy_window);
- size_t bytes_pending = leaky_bucket_.BytesPending();
+ QuicByteCount bytes_pending = leaky_bucket_.BytesPending();
if (bytes_pending > available_congestion_window) {
return 0;
}
diff --git a/net/quic/congestion_control/paced_sender.h b/net/quic/congestion_control/paced_sender.h
index 1b6f81d..af3adaf 100644
--- a/net/quic/congestion_control/paced_sender.h
+++ b/net/quic/congestion_control/paced_sender.h
@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "net/base/net_export.h"
#include "net/quic/congestion_control/leaky_bucket.h"
+#include "net/quic/quic_bandwidth.h"
#include "net/quic/quic_clock.h"
#include "net/quic/quic_time.h"
@@ -17,13 +18,13 @@ namespace net {
class NET_EXPORT_PRIVATE PacedSender {
public:
- PacedSender(const QuicClock* clock, int bandwidth_estimate_bytes_per_s);
+ PacedSender(const QuicClock* clock, QuicBandwidth bandwidth_estimate);
// The estimated bandidth from the congestion algorithm changed.
- void UpdateBandwidthEstimate(int bytes_per_s);
+ void UpdateBandwidthEstimate(QuicBandwidth bandwidth_estimate);
// A packet of size bytes was sent.
- void SentPacket(size_t bytes);
+ void SentPacket(QuicByteCount bytes);
// Return time until we can send based on the pacing.
QuicTime::Delta TimeUntilSend(QuicTime::Delta time_until_send);
@@ -31,12 +32,14 @@ class NET_EXPORT_PRIVATE PacedSender {
// Return the amount of data in bytes we can send based on the pacing.
// available_congestion_window is the congestion algorithms available
// congestion window in bytes.
- size_t AvailableWindow(size_t available_congestion_window);
+ QuicByteCount AvailableWindow(QuicByteCount available_congestion_window);
private:
// Helper object to track the rate data can leave the buffer for pacing.
LeakyBucket leaky_bucket_;
- int pace_in_bytes_per_s_;
+ QuicBandwidth pace_;
+
+ DISALLOW_COPY_AND_ASSIGN(PacedSender);
};
} // namespace net
diff --git a/net/quic/congestion_control/paced_sender_test.cc b/net/quic/congestion_control/paced_sender_test.cc
index e93261b..d2432aa 100644
--- a/net/quic/congestion_control/paced_sender_test.cc
+++ b/net/quic/congestion_control/paced_sender_test.cc
@@ -13,13 +13,14 @@
namespace net {
namespace test {
-const int kHundredKBytesPerS = 100000;
+const int kHundredKBytesPerS = 100;
class PacedSenderTest : public ::testing::Test {
protected:
PacedSenderTest()
: zero_time_(QuicTime::Delta::Zero()),
- paced_sender_(new PacedSender(&clock_, kHundredKBytesPerS)) {
+ paced_sender_(new PacedSender(&clock_,
+ QuicBandwidth::FromKBytesPerSecond(kHundredKBytesPerS))) {
}
const QuicTime::Delta zero_time_;
@@ -28,7 +29,8 @@ class PacedSenderTest : public ::testing::Test {
};
TEST_F(PacedSenderTest, Basic) {
- paced_sender_->UpdateBandwidthEstimate(kHundredKBytesPerS * 10);
+ paced_sender_->UpdateBandwidthEstimate(
+ QuicBandwidth::FromKBytesPerSecond(kHundredKBytesPerS * 10));
EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero());
EXPECT_EQ(kMaxPacketSize * 2,
paced_sender_->AvailableWindow(kMaxPacketSize * 4));
@@ -40,12 +42,13 @@ TEST_F(PacedSenderTest, Basic) {
EXPECT_EQ(0u, paced_sender_->AvailableWindow(kMaxPacketSize * 4));
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(24));
EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero());
- EXPECT_EQ(kMaxPacketSize * 2,
+ EXPECT_EQ(kMaxPacketSize * 2u,
paced_sender_->AvailableWindow(kMaxPacketSize * 4));
}
TEST_F(PacedSenderTest, LowRate) {
- paced_sender_->UpdateBandwidthEstimate(kHundredKBytesPerS);
+ paced_sender_->UpdateBandwidthEstimate(
+ QuicBandwidth::FromKBytesPerSecond(kHundredKBytesPerS));
EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero());
size_t window = paced_sender_->AvailableWindow(kMaxPacketSize * 4);
EXPECT_EQ(kMaxPacketSize * 2, window);
@@ -62,10 +65,11 @@ TEST_F(PacedSenderTest, LowRate) {
}
TEST_F(PacedSenderTest, HighRate) {
- int bandwidth_estimate = kHundredKBytesPerS * 100;
+ QuicBandwidth bandwidth_estimate = QuicBandwidth::FromKBytesPerSecond(
+ kHundredKBytesPerS * 100);
paced_sender_->UpdateBandwidthEstimate(bandwidth_estimate);
EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero());
- EXPECT_EQ(bandwidth_estimate / 500u,
+ EXPECT_EQ(static_cast<uint64>(bandwidth_estimate.ToBytesPerSecond() / 500u),
paced_sender_->AvailableWindow(kMaxPacketSize * 100));
for (int i = 0; i < 16; ++i) {
paced_sender_->SentPacket(kMaxPacketSize);
@@ -76,7 +80,7 @@ TEST_F(PacedSenderTest, HighRate) {
EXPECT_EQ(2040, paced_sender_->TimeUntilSend(zero_time_).ToMicroseconds());
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(20400));
EXPECT_TRUE(paced_sender_->TimeUntilSend(zero_time_).IsZero());
- EXPECT_EQ(bandwidth_estimate / 500u,
+ EXPECT_EQ(static_cast<uint64>(bandwidth_estimate.ToBytesPerSecond() / 500u),
paced_sender_->AvailableWindow(kMaxPacketSize * 100));
}
diff --git a/net/quic/congestion_control/quic_congestion_manager.cc b/net/quic/congestion_control/quic_congestion_manager.cc
index 8e300bb..238b5c7 100644
--- a/net/quic/congestion_control/quic_congestion_manager.cc
+++ b/net/quic/congestion_control/quic_congestion_manager.cc
@@ -4,51 +4,175 @@
#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 <algorithm>
+#include <map>
+
+#include "base/stl_util.h"
+#include "net/quic/congestion_control/receive_algorithm_interface.h"
+#include "net/quic/congestion_control/send_algorithm_interface.h"
+
+namespace {
+const int kBitrateSmoothingPeriodMs = 3000;
+const int kMinBitrateSmoothingPeriodMs = 500;
+const int kHistoryPeriodMs = 5000;
+
+const int kDefaultRetransmissionTimeMs = 500;
+const size_t kMaxRetransmissions = 15;
+
+COMPILE_ASSERT(kHistoryPeriodMs >= kBitrateSmoothingPeriodMs,
+ history_must_be_longer_or_equal_to_the_smoothing_period);
+} // namespace
+
+using std::map;
+using std::min;
namespace net {
QuicCongestionManager::QuicCongestionManager(
const QuicClock* clock,
CongestionFeedbackType type)
- : collector_(new QuicReceiptMetricsCollector(clock, type)),
- scheduler_(new QuicSendScheduler(clock, type)) {
+ : clock_(clock),
+ receive_algorithm_(ReceiveAlgorithmInterface::Create(clock, type)),
+ send_algorithm_(SendAlgorithmInterface::Create(clock, type)) {
}
QuicCongestionManager::~QuicCongestionManager() {
+ STLDeleteValues(&packet_history_map_);
}
void QuicCongestionManager::SentPacket(QuicPacketSequenceNumber sequence_number,
- size_t bytes,
+ QuicByteCount bytes,
bool is_retransmission) {
- scheduler_->SentPacket(sequence_number, bytes, is_retransmission);
+ DCHECK(!ContainsKey(pending_packets_, sequence_number));
+ send_algorithm_->SentPacket(sequence_number, bytes, is_retransmission);
+
+ packet_history_map_[sequence_number] =
+ new class SendAlgorithmInterface::SentPacket(bytes, clock_->Now());
+ pending_packets_[sequence_number] = bytes;
+ CleanupPacketHistory();
+ DLOG(INFO) << "Sent sequence number:" << sequence_number;
}
void QuicCongestionManager::OnIncomingQuicCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame) {
- scheduler_->OnIncomingQuicCongestionFeedbackFrame(frame);
+ send_algorithm_->OnIncomingQuicCongestionFeedbackFrame(frame,
+ packet_history_map_);
}
void QuicCongestionManager::OnIncomingAckFrame(const QuicAckFrame& frame) {
- scheduler_->OnIncomingAckFrame(frame);
+ // We calculate the RTT based on the highest ACKed sequence number, the lower
+ // sequence numbers will include the ACK aggregation delay.
+ QuicTime::Delta rtt = QuicTime::Delta::Zero();
+ SendAlgorithmInterface::SentPacketsMap::iterator history_it =
+ packet_history_map_.find(frame.received_info.largest_observed);
+ if (history_it != packet_history_map_.end()) {
+ rtt = clock_->Now().Subtract(history_it->second->SendTimestamp());
+ }
+ // We want to.
+ // * Get all packets lower(including) than largest_observed
+ // from pending_packets_.
+ // * Remove all missing packets.
+ // * Send each ACK in the list to send_algorithm_.
+ PendingPacketsMap::iterator it, it_upper;
+ it = pending_packets_.begin();
+ it_upper = pending_packets_.upper_bound(frame.received_info.largest_observed);
+
+ while (it != it_upper) {
+ QuicPacketSequenceNumber sequence_number = it->first;
+ if (!frame.received_info.IsAwaitingPacket(sequence_number)) {
+ // Not missing, hence implicitly acked.
+ send_algorithm_->OnIncomingAck(sequence_number,
+ it->second,
+ rtt);
+ DLOG(INFO) << "ACKed sequence number:" << sequence_number;
+ pending_packets_.erase(it++); // Must be incremented post to work.
+ } else {
+ ++it;
+ }
+ }
}
QuicTime::Delta QuicCongestionManager::TimeUntilSend(bool is_retransmission) {
- return scheduler_->TimeUntilSend(is_retransmission);
+ return send_algorithm_->TimeUntilSend(is_retransmission);
}
bool QuicCongestionManager::GenerateCongestionFeedback(
QuicCongestionFeedbackFrame* feedback) {
- return collector_->GenerateCongestionFeedback(feedback);
+ return receive_algorithm_->GenerateCongestionFeedback(feedback);
}
void QuicCongestionManager::RecordIncomingPacket(
- size_t bytes,
+ QuicByteCount bytes,
QuicPacketSequenceNumber sequence_number,
QuicTime timestamp,
bool revived) {
- collector_->RecordIncomingPacket(bytes, sequence_number, timestamp, revived);
+ receive_algorithm_->RecordIncomingPacket(bytes, sequence_number, timestamp,
+ revived);
+}
+
+// static
+const QuicTime::Delta QuicCongestionManager::DefaultRetransmissionTime() {
+ return QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs);
+}
+
+// static
+const QuicTime::Delta QuicCongestionManager::GetRetransmissionDelay(
+ size_t number_retransmissions) {
+ return QuicTime::Delta::FromMilliseconds(
+ kDefaultRetransmissionTimeMs *
+ (1 << min<size_t>(number_retransmissions, kMaxRetransmissions)));
+}
+
+QuicBandwidth QuicCongestionManager::SentBandwidth() const {
+ const QuicTime::Delta kBitrateSmoothingPeriod =
+ QuicTime::Delta::FromMilliseconds(kBitrateSmoothingPeriodMs);
+ const QuicTime::Delta kMinBitrateSmoothingPeriod =
+ QuicTime::Delta::FromMilliseconds(kMinBitrateSmoothingPeriodMs);
+
+ QuicTime now = clock_->Now();
+ QuicByteCount sum_bytes_sent = 0;
+
+ // Sum packet from new until they are kBitrateSmoothingPeriod old.
+ SendAlgorithmInterface::SentPacketsMap::const_reverse_iterator history_rit =
+ packet_history_map_.rbegin();
+
+ QuicTime::Delta max_diff = QuicTime::Delta::Zero();
+ for (; history_rit != packet_history_map_.rend(); ++history_rit) {
+ QuicTime::Delta diff = now.Subtract(history_rit->second->SendTimestamp());
+ if (diff > kBitrateSmoothingPeriod) {
+ break;
+ }
+ sum_bytes_sent += history_rit->second->BytesSent();
+ max_diff = diff;
+ }
+ if (max_diff < kMinBitrateSmoothingPeriod) {
+ // No estimate.
+ return QuicBandwidth::Zero();
+ }
+ return QuicBandwidth::FromBytesAndTimeDelta(sum_bytes_sent, max_diff);
+}
+
+QuicBandwidth QuicCongestionManager::BandwidthEstimate() {
+ return send_algorithm_->BandwidthEstimate();
+}
+
+void QuicCongestionManager::CleanupPacketHistory() {
+ const QuicTime::Delta kHistoryPeriod =
+ QuicTime::Delta::FromMilliseconds(kHistoryPeriodMs);
+ QuicTime Now = clock_->Now();
+
+ SendAlgorithmInterface::SentPacketsMap::iterator history_it =
+ packet_history_map_.begin();
+ for (; history_it != packet_history_map_.end(); ++history_it) {
+ if (Now.Subtract(history_it->second->SendTimestamp()) <= kHistoryPeriod) {
+ return;
+ }
+ DLOG(INFO) << "Clear sequence number:" << history_it->first
+ << "from history";
+ delete history_it->second;
+ packet_history_map_.erase(history_it);
+ history_it = packet_history_map_.begin();
+ }
}
} // namespace net
diff --git a/net/quic/congestion_control/quic_congestion_manager.h b/net/quic/congestion_control/quic_congestion_manager.h
index 9402213..09a9c9c 100644
--- a/net/quic/congestion_control/quic_congestion_manager.h
+++ b/net/quic/congestion_control/quic_congestion_manager.h
@@ -3,8 +3,8 @@
// 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
+// congestion control code. It wraps the SendAlgorithmInterface and
+// ReceiveAlgorithmInterface and provides a single interface
// for consumers.
#ifndef NET_QUIC_CONGESTION_CONTROL_QUIC_CONGESTION_MANAGER_H_
@@ -12,17 +12,19 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+#include "net/quic/congestion_control/send_algorithm_interface.h"
+#include "net/quic/quic_bandwidth.h"
#include "net/quic/quic_protocol.h"
namespace net {
namespace test {
class QuicConnectionPeer;
+class QuicCongestionManagerPeer;
} // namespace test
class QuicClock;
-class QuicReceiptMetricsCollector;
-class QuicSendScheduler;
+class ReceiveAlgorithmInterface;
class QuicCongestionManager {
public:
@@ -40,7 +42,7 @@ class QuicCongestionManager {
// 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,
+ QuicByteCount bytes,
bool is_retransmission);
// Calculate the time until we can send the next packet to the wire.
@@ -63,16 +65,34 @@ class QuicCongestionManager {
// 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,
+ virtual void RecordIncomingPacket(QuicByteCount bytes,
QuicPacketSequenceNumber sequence_number,
QuicTime timestamp,
bool revived);
+ const QuicTime::Delta DefaultRetransmissionTime();
+
+ const QuicTime::Delta GetRetransmissionDelay(
+ size_t number_retransmissions);
+
private:
friend class test::QuicConnectionPeer;
-
- scoped_ptr<QuicReceiptMetricsCollector> collector_;
- scoped_ptr<QuicSendScheduler> scheduler_;
+ friend class test::QuicCongestionManagerPeer;
+ typedef std::map<QuicPacketSequenceNumber, size_t> PendingPacketsMap;
+
+ // TODO(pwestin): Currently only used for testing. How do we surface this?
+ QuicBandwidth SentBandwidth() const;
+ // TODO(pwestin): Currently only used for testing. How do we surface this?
+ QuicBandwidth BandwidthEstimate();
+ void CleanupPacketHistory();
+
+ const QuicClock* clock_;
+ scoped_ptr<ReceiveAlgorithmInterface> receive_algorithm_;
+ scoped_ptr<SendAlgorithmInterface> send_algorithm_;
+ SendAlgorithmInterface::SentPacketsMap packet_history_map_;
+ PendingPacketsMap pending_packets_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicCongestionManager);
};
} // namespace net
diff --git a/net/quic/congestion_control/quic_receipt_metrics_collector.cc b/net/quic/congestion_control/quic_receipt_metrics_collector.cc
deleted file mode 100644
index 7f3c076..0000000
--- a/net/quic/congestion_control/quic_receipt_metrics_collector.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/congestion_control/quic_receipt_metrics_collector.h"
-
-#include "net/quic/congestion_control/receive_algorithm_interface.h"
-
-namespace net {
-
-QuicReceiptMetricsCollector::QuicReceiptMetricsCollector(
- const QuicClock* clock,
- CongestionFeedbackType type)
- : receive_algorithm_(ReceiveAlgorithmInterface::Create(clock, type)) {
-}
-
-QuicReceiptMetricsCollector::~QuicReceiptMetricsCollector() {
-}
-
-bool QuicReceiptMetricsCollector::GenerateCongestionFeedback(
- QuicCongestionFeedbackFrame* feedback) {
- return receive_algorithm_->GenerateCongestionFeedback(feedback);
-}
-
-void QuicReceiptMetricsCollector::RecordIncomingPacket(
- size_t bytes,
- QuicPacketSequenceNumber sequence_number,
- QuicTime timestamp,
- bool revived) {
- receive_algorithm_->RecordIncomingPacket(bytes, sequence_number, timestamp,
- revived);
-}
-
-} // namespace net
diff --git a/net/quic/congestion_control/quic_receipt_metrics_collector.h b/net/quic/congestion_control/quic_receipt_metrics_collector.h
deleted file mode 100644
index d985cff..0000000
--- a/net/quic/congestion_control/quic_receipt_metrics_collector.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// This is the base class for QUIC receive side congestion control.
-// This class will provide the QuicCongestionFeedbackFrame objects for outgoing
-// packets if needed.
-// The acctual receive side algorithm is implemented via the
-// ReceiveAlgorithmInterface.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_QUIC_RECEIPT_METRICS_COLLECTOR_H_
-#define NET_QUIC_CONGESTION_CONTROL_QUIC_RECEIPT_METRICS_COLLECTOR_H_
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "net/base/net_export.h"
-#include "net/quic/congestion_control/receive_algorithm_interface.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE QuicReceiptMetricsCollector {
- public:
- QuicReceiptMetricsCollector(const QuicClock* clock,
- CongestionFeedbackType congestion_type);
-
- virtual ~QuicReceiptMetricsCollector();
-
- // 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);
-
- // TODO(pwestin) Keep track of the number of FEC recovered packets.
- // Needed by all congestion control algorithms.
-
- private:
- scoped_ptr<ReceiveAlgorithmInterface> receive_algorithm_;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_QUIC_RECEIPT_METRICS_COLLECTOR_H_
diff --git a/net/quic/congestion_control/quic_receipt_metrics_collector_test.cc b/net/quic/congestion_control/quic_receipt_metrics_collector_test.cc
deleted file mode 100644
index 891fcba..0000000
--- a/net/quic/congestion_control/quic_receipt_metrics_collector_test.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "net/quic/congestion_control/quic_receipt_metrics_collector.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-class QuicReceiptMetricsCollectorTest : public ::testing::Test {
- protected:
- void SetUpCongestionType(CongestionFeedbackType congestion_type) {
- receiver_.reset(new QuicReceiptMetricsCollector(&clock_, congestion_type));
- }
-
- MockClock clock_;
- scoped_ptr<QuicReceiptMetricsCollector> receiver_;
-};
-
-TEST_F(QuicReceiptMetricsCollectorTest, FixedRateReceiverAPI) {
- SetUpCongestionType(kFixRate);
- QuicCongestionFeedbackFrame feedback;
- QuicTime timestamp(QuicTime::Zero());
- receiver_->RecordIncomingPacket(1, 1, timestamp, false);
- ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
- EXPECT_EQ(kFixRate, feedback.type);
-}
-
-} // namespace test
-} // namespace net
diff --git a/net/quic/congestion_control/quic_send_scheduler.cc b/net/quic/congestion_control/quic_send_scheduler.cc
deleted file mode 100644
index 8b9acf5..0000000
--- a/net/quic/congestion_control/quic_send_scheduler.cc
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-#include "net/quic/congestion_control/quic_send_scheduler.h"
-
-#include <algorithm>
-#include <cmath>
-#include <map>
-
-#include "base/stl_util.h"
-#include "base/time.h"
-#include "net/quic/congestion_control/send_algorithm_interface.h"
-//#include "util/gtl/map-util.h"
-
-namespace {
-const int kBitrateSmoothingPeriodMs = 3000;
-const int kMinBitrateSmoothingPeriodMs = 500;
-const int kHistoryPeriodMs = 5000;
-
-COMPILE_ASSERT(kHistoryPeriodMs >= kBitrateSmoothingPeriodMs,
- history_must_be_longer_or_equal_to_the_smoothing_period);
-}
-
-using std::map;
-using std::max;
-
-namespace net {
-
-const int64 kNumMicrosPerSecond = base::Time::kMicrosecondsPerSecond;
-
-QuicSendScheduler::QuicSendScheduler(
- const QuicClock* clock,
- CongestionFeedbackType type)
- : clock_(clock),
- current_estimated_bandwidth_(0),
- max_estimated_bandwidth_(-1),
- last_sent_packet_(QuicTime::FromMicroseconds(0)),
- send_algorithm_(SendAlgorithmInterface::Create(clock, type)) {
-}
-
-QuicSendScheduler::~QuicSendScheduler() {
- STLDeleteValues(&packet_history_map_);
-}
-
-void QuicSendScheduler::SentPacket(QuicPacketSequenceNumber sequence_number,
- size_t bytes,
- bool is_retransmission) {
- DCHECK(!ContainsKey(pending_packets_, sequence_number));
- send_algorithm_->SentPacket(sequence_number, bytes, is_retransmission);
-
- packet_history_map_[sequence_number] =
- new class SendAlgorithmInterface::SentPacket(bytes, clock_->Now());
- pending_packets_[sequence_number] = bytes;
- CleanupPacketHistory();
- DLOG(INFO) << "Sent sequence number:" << sequence_number;
-}
-
-void QuicSendScheduler::OnIncomingQuicCongestionFeedbackFrame(
- const QuicCongestionFeedbackFrame& congestion_feedback_frame) {
- send_algorithm_->OnIncomingQuicCongestionFeedbackFrame(
- congestion_feedback_frame, packet_history_map_);
-}
-
-void QuicSendScheduler::CleanupPacketHistory() {
- const QuicTime::Delta kHistoryPeriod =
- QuicTime::Delta::FromMilliseconds(kHistoryPeriodMs);
- QuicTime Now = clock_->Now();
-
- SendAlgorithmInterface::SentPacketsMap::iterator history_it =
- packet_history_map_.begin();
- for (; history_it != packet_history_map_.end(); ++history_it) {
- if (Now.Subtract(history_it->second->SendTimestamp()) <= kHistoryPeriod) {
- return;
- }
- DLOG(INFO) << "Clear sequence number:" << history_it->first
- << "from history";
- delete history_it->second;
- packet_history_map_.erase(history_it);
- history_it = packet_history_map_.begin();
- }
-}
-
-void QuicSendScheduler::OnIncomingAckFrame(const QuicAckFrame& ack_frame) {
- // We calculate the RTT based on the highest ACKed sequence number, the lower
- // sequence numbers will include the ACK aggregation delay.
- QuicTime::Delta rtt = QuicTime::Delta::Zero();
- SendAlgorithmInterface::SentPacketsMap::iterator history_it =
- packet_history_map_.find(ack_frame.received_info.largest_observed);
- if (history_it != packet_history_map_.end()) {
- rtt = clock_->Now().Subtract(history_it->second->SendTimestamp());
- }
- // We want to.
- // * Get all packets lower(including) than largest_observed
- // from pending_packets_.
- // * Remove all missing packets.
- // * Send each ACK in the list to send_algorithm_.
- PendingPacketsMap::iterator it, it_upper;
- it = pending_packets_.begin();
- it_upper = pending_packets_.upper_bound(
- ack_frame.received_info.largest_observed);
-
- while (it != it_upper) {
- QuicPacketSequenceNumber sequence_number = it->first;
- if (!ack_frame.received_info.IsAwaitingPacket(sequence_number)) {
- // Not missing, hence implicitly acked.
- send_algorithm_->OnIncomingAck(sequence_number,
- it->second,
- rtt);
- DLOG(INFO) << "ACKed sequence number:" << sequence_number;
- pending_packets_.erase(it++); // Must be incremented post to work.
- } else {
- ++it;
- }
- }
-}
-
-QuicTime::Delta QuicSendScheduler::TimeUntilSend(bool is_retransmission) {
- return send_algorithm_->TimeUntilSend(is_retransmission);
-}
-
-size_t QuicSendScheduler::AvailableCongestionWindow() {
- return send_algorithm_->AvailableCongestionWindow();
-}
-
-int QuicSendScheduler::BandwidthEstimate() {
- int bandwidth_estimate = send_algorithm_->BandwidthEstimate();
- if (bandwidth_estimate == kNoValidEstimate) {
- // If we don't have a valid estimate use the send rate.
- return SentBandwidth();
- }
- return bandwidth_estimate;
-}
-
-// TODO(pwestin): add a timer to make max_estimated_bandwidth_ accurate.
-int QuicSendScheduler::SentBandwidth() {
- const QuicTime::Delta kBitrateSmoothingPeriod =
- QuicTime::Delta::FromMilliseconds(kBitrateSmoothingPeriodMs);
- const QuicTime::Delta kMinBitrateSmoothingPeriod =
- QuicTime::Delta::FromMilliseconds(kMinBitrateSmoothingPeriodMs);
-
- QuicTime Now = clock_->Now();
- size_t sum_bytes_sent = 0;
-
- // Sum packet from new until they are kBitrateSmoothingPeriod old.
- SendAlgorithmInterface::SentPacketsMap::reverse_iterator history_rit =
- packet_history_map_.rbegin();
-
- QuicTime::Delta max_diff = QuicTime::Delta::Zero();
- for (; history_rit != packet_history_map_.rend(); ++history_rit) {
- QuicTime::Delta diff = Now.Subtract(history_rit->second->SendTimestamp());
- if (diff > kBitrateSmoothingPeriod) {
- break;
- }
- sum_bytes_sent += history_rit->second->BytesSent();
- max_diff = diff;
- }
- if (max_diff < kMinBitrateSmoothingPeriod) {
- // No estimate.
- return 0;
- }
- current_estimated_bandwidth_ = sum_bytes_sent * kNumMicrosPerSecond /
- max_diff.ToMicroseconds();
- max_estimated_bandwidth_ = max(max_estimated_bandwidth_,
- current_estimated_bandwidth_);
- return current_estimated_bandwidth_;
-}
-
-int QuicSendScheduler::PeakSustainedBandwidth() {
- // To make sure that we get the latest estimate we call SentBandwidth.
- SentBandwidth();
- return max_estimated_bandwidth_;
-}
-
-} // namespace net
diff --git a/net/quic/congestion_control/quic_send_scheduler.h b/net/quic/congestion_control/quic_send_scheduler.h
deleted file mode 100644
index 53793bd..0000000
--- a/net/quic/congestion_control/quic_send_scheduler.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// The is the base class for QUIC send side congestion control.
-// It decides when we can send a QUIC packet to the wire.
-// This class handles the basic bookkeeping of sent bitrate and packet loss.
-// The actual send side algorithm is implemented via the
-// SendAlgorithmInterface.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_QUIC_SEND_SCHEDULER_H_
-#define NET_QUIC_CONGESTION_CONTROL_QUIC_SEND_SCHEDULER_H_
-
-#include <map>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "net/base/net_export.h"
-#include "net/quic/congestion_control/quic_receipt_metrics_collector.h"
-#include "net/quic/congestion_control/send_algorithm_interface.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE QuicSendScheduler {
- public:
- // Enable pacing to prevent a large congestion window to be sent all at once,
- // when pacing is enabled a large congestion window will be sent in multiple
- // bursts of packet(s) instead of one big burst that might introduce packet
- // loss.
- QuicSendScheduler(const QuicClock* clock,
- CongestionFeedbackType congestion_type);
- virtual ~QuicSendScheduler();
-
- // 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);
-
- // Returns the current available congestion window in bytes, the number of
- // bytes that can be sent now.
- // Note: due to pacing this function might return a smaller value than the
- // real available congestion window. This way we hold off the sender to avoid
- // queuing in the lower layers in the stack.
- size_t AvailableCongestionWindow();
-
- int BandwidthEstimate(); // Current estimate, in bytes per second.
-
- int SentBandwidth(); // Current smooth acctually sent, in bytes per second.
-
- int PeakSustainedBandwidth(); // In bytes per second.
-
- private:
- typedef std::map<QuicPacketSequenceNumber, size_t> PendingPacketsMap;
-
- void CleanupPacketHistory();
-
- const QuicClock* clock_;
- int64 current_estimated_bandwidth_;
- int64 max_estimated_bandwidth_;
- QuicTime last_sent_packet_;
- scoped_ptr<SendAlgorithmInterface> send_algorithm_;
- SendAlgorithmInterface::SentPacketsMap packet_history_map_;
- PendingPacketsMap pending_packets_;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_QUIC_SEND_SCHEDULER_H_
diff --git a/net/quic/congestion_control/quic_send_scheduler_test.cc b/net/quic/congestion_control/quic_send_scheduler_test.cc
deleted file mode 100644
index 9347b2c..0000000
--- a/net/quic/congestion_control/quic_send_scheduler_test.cc
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "net/quic/congestion_control/quic_receipt_metrics_collector.h"
-#include "net/quic/congestion_control/quic_send_scheduler.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/quic_protocol.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-class QuicSendSchedulerTest : public ::testing::Test {
- protected:
- void SetUpCongestionType(CongestionFeedbackType congestion_type) {
- sender_.reset(new QuicSendScheduler(&clock_, congestion_type));
- }
- MockClock clock_;
- scoped_ptr<QuicSendScheduler> sender_;
-};
-
-TEST_F(QuicSendSchedulerTest, FixedRateSenderAPI) {
- SetUpCongestionType(kFixRate);
- QuicCongestionFeedbackFrame congestion_feedback;
- congestion_feedback.type = kFixRate;
- congestion_feedback.fix_rate.bitrate_in_bytes_per_second = 30000;
- sender_->OnIncomingQuicCongestionFeedbackFrame(congestion_feedback);
- EXPECT_EQ(-1, sender_->PeakSustainedBandwidth());
- EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
- EXPECT_EQ(kMaxPacketSize, sender_->AvailableCongestionWindow());
- sender_->SentPacket(1, kMaxPacketSize, false);
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40),
- sender_->TimeUntilSend(false));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(35));
- EXPECT_EQ(QuicTime::Delta::Infinite(),
- sender_->TimeUntilSend(false));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_EQ(QuicTime::Delta::Infinite(),
- sender_->TimeUntilSend(false));
-}
-
-TEST_F(QuicSendSchedulerTest, FixedRatePacing) {
- SetUpCongestionType(kFixRate);
- QuicAckFrame ack;
- ack.received_info.largest_observed = 0;
- sender_->OnIncomingAckFrame(ack);
-
- QuicCongestionFeedbackFrame feedback;
- feedback.type = kFixRate;
- feedback.fix_rate.bitrate_in_bytes_per_second = 100000;
- sender_->OnIncomingQuicCongestionFeedbackFrame(feedback);
-
- QuicTime acc_advance_time(QuicTime::Zero());
- for (int i = 1; i <= 100; ++i) {
- EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
- EXPECT_EQ(kMaxPacketSize, sender_->AvailableCongestionWindow());
- sender_->SentPacket(i, kMaxPacketSize, false);
- QuicTime::Delta advance_time = sender_->TimeUntilSend(false);
- clock_.AdvanceTime(advance_time);
- acc_advance_time = acc_advance_time.Add(advance_time);
- // Ack the packet we sent.
- ack.received_info.RecordReceived(i);
- sender_->OnIncomingAckFrame(ack);
- }
- EXPECT_EQ(QuicTime::FromMilliseconds(1200), acc_advance_time);
-}
-
-TEST_F(QuicSendSchedulerTest, AvailableCongestionWindow) {
- SetUpCongestionType(kFixRate);
- QuicAckFrame ack;
- sender_->OnIncomingAckFrame(ack);
-
- QuicCongestionFeedbackFrame feedback;
- feedback.type = kFixRate;
- feedback.fix_rate.bitrate_in_bytes_per_second = 100000;
- sender_->OnIncomingQuicCongestionFeedbackFrame(feedback);
-
- EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
- EXPECT_EQ(kMaxPacketSize, sender_->AvailableCongestionWindow());
- const int32 num_packets = 12;
- for (int i = 1; i <= num_packets; i++) {
- EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
- sender_->SentPacket(i, 100, false);
- EXPECT_EQ(kMaxPacketSize - (i * 100), sender_->AvailableCongestionWindow());
- }
- // Ack the packets we sent.
- for (int i = 1; i <= num_packets; i++) {
- ack.received_info.RecordReceived(i);
- }
- sender_->OnIncomingAckFrame(ack);
- EXPECT_EQ(kMaxPacketSize, sender_->AvailableCongestionWindow());
-}
-
-TEST_F(QuicSendSchedulerTest, FixedRateBandwidth) {
- SetUpCongestionType(kFixRate);
- QuicAckFrame ack;
- sender_->OnIncomingAckFrame(ack);
-
- QuicCongestionFeedbackFrame feedback;
- feedback.type = kFixRate;
- feedback.fix_rate.bitrate_in_bytes_per_second = 100000;
- sender_->OnIncomingQuicCongestionFeedbackFrame(feedback);
-
- for (int i = 1; i <= 100; ++i) {
- QuicTime::Delta advance_time = sender_->TimeUntilSend(false);
- clock_.AdvanceTime(advance_time);
- EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
- EXPECT_EQ(kMaxPacketSize, sender_->AvailableCongestionWindow());
- sender_->SentPacket(i, 1000, false);
- // Ack the packet we sent.
- ack.received_info.RecordReceived(i);
- sender_->OnIncomingAckFrame(ack);
- }
- EXPECT_EQ(100000, sender_->BandwidthEstimate());
- EXPECT_NEAR(100000, sender_->PeakSustainedBandwidth(), 4000);
- EXPECT_NEAR(100000, sender_->SentBandwidth(), 4000);
-}
-
-TEST_F(QuicSendSchedulerTest, BandwidthWith3SecondGap) {
- SetUpCongestionType(kFixRate);
- QuicAckFrame ack;
- sender_->OnIncomingAckFrame(ack);
-
- QuicCongestionFeedbackFrame feedback;
- feedback.type = kFixRate;
- feedback.fix_rate.bitrate_in_bytes_per_second = 100000;
- sender_->OnIncomingQuicCongestionFeedbackFrame(feedback);
-
- for (int i = 1; i <= 100; ++i) {
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
- EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
- EXPECT_EQ(kMaxPacketSize, sender_->AvailableCongestionWindow());
- sender_->SentPacket(i, 1000, false);
- // Ack the packet we sent.
- ack.received_info.RecordReceived(i);
- sender_->OnIncomingAckFrame(ack);
- }
- EXPECT_EQ(100000, sender_->BandwidthEstimate());
- EXPECT_NEAR(100000, sender_->PeakSustainedBandwidth(), 2000);
- EXPECT_NEAR(100000, sender_->SentBandwidth(), 2000);
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000));
- EXPECT_NEAR(50000, sender_->SentBandwidth(), 1000);
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2100));
- EXPECT_NEAR(100000, sender_->BandwidthEstimate(), 2000);
- EXPECT_NEAR(100000, sender_->PeakSustainedBandwidth(), 2000);
- EXPECT_EQ(0, sender_->SentBandwidth());
- for (int i = 1; i <= 150; ++i) {
- EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
- EXPECT_EQ(kMaxPacketSize, sender_->AvailableCongestionWindow());
- sender_->SentPacket(i + 100, 1000, false);
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
- // Ack the packet we sent.
- ack.received_info.RecordReceived(i + 100);
- sender_->OnIncomingAckFrame(ack);
- }
- EXPECT_EQ(100000, sender_->BandwidthEstimate());
- EXPECT_NEAR(100000, sender_->PeakSustainedBandwidth(), 2000);
- EXPECT_NEAR(100000, sender_->SentBandwidth(), 2000);
-}
-
-TEST_F(QuicSendSchedulerTest, Pacing) {
- SetUpCongestionType(kFixRate);
- QuicAckFrame ack;
- ack.received_info.largest_observed = 0;
- sender_->OnIncomingAckFrame(ack);
-
- QuicCongestionFeedbackFrame feedback;
- feedback.type = kFixRate;
- // Test a high bitrate (8Mbit/s) to trigger pacing.
- feedback.fix_rate.bitrate_in_bytes_per_second = 1000000;
- sender_->OnIncomingQuicCongestionFeedbackFrame(feedback);
-
- QuicTime acc_advance_time(QuicTime::Zero());
- for (int i = 1; i <= 100;) {
- EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
- EXPECT_EQ(kMaxPacketSize * 2, sender_->AvailableCongestionWindow());
- sender_->SentPacket(i++, kMaxPacketSize, false);
- EXPECT_TRUE(sender_->TimeUntilSend(false).IsZero());
- sender_->SentPacket(i++, kMaxPacketSize, false);
- QuicTime::Delta advance_time = sender_->TimeUntilSend(false);
- clock_.AdvanceTime(advance_time);
- acc_advance_time = acc_advance_time.Add(advance_time);
- // Ack the packets we sent.
- ack.received_info.RecordReceived(i - 2);
- sender_->OnIncomingAckFrame(ack);
- ack.received_info.RecordReceived(i - 1);
- sender_->OnIncomingAckFrame(ack);
- }
- EXPECT_EQ(QuicTime::FromMilliseconds(120), acc_advance_time);
-}
-
-} // namespace test
-} // namespace net
diff --git a/net/quic/congestion_control/receive_algorithm_interface.h b/net/quic/congestion_control/receive_algorithm_interface.h
index 461ec23..e2bae4b 100644
--- a/net/quic/congestion_control/receive_algorithm_interface.h
+++ b/net/quic/congestion_control/receive_algorithm_interface.h
@@ -33,7 +33,7 @@ class NET_EXPORT_PRIVATE ReceiveAlgorithmInterface {
// timestamp: is the sent timestamp from the QUIC packet header.
// revived: is set if the packet is lost and then recovered with help of FEC
// (Forward Error Correction) packet(s).
- virtual void RecordIncomingPacket(size_t bytes,
+ virtual void RecordIncomingPacket(QuicByteCount bytes,
QuicPacketSequenceNumber sequence_number,
QuicTime timestamp,
bool revived) = 0;
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index 8f83615..efcc172 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -9,27 +9,26 @@
#include "base/basictypes.h"
#include "net/base/net_export.h"
+#include "net/quic/quic_bandwidth.h"
#include "net/quic/quic_clock.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_time.h"
namespace net {
-const int kNoValidEstimate = -1;
-
class NET_EXPORT_PRIVATE SendAlgorithmInterface {
public:
class SentPacket {
public:
- SentPacket(size_t bytes, QuicTime timestamp)
+ SentPacket(QuicByteCount bytes, QuicTime timestamp)
: bytes_sent_(bytes),
send_timestamp_(timestamp) {
}
- size_t BytesSent() { return bytes_sent_; }
+ QuicByteCount BytesSent() { return bytes_sent_; }
QuicTime& SendTimestamp() { return send_timestamp_; }
private:
- size_t bytes_sent_;
+ QuicByteCount bytes_sent_;
QuicTime send_timestamp_;
};
@@ -47,7 +46,7 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface {
// Called for each received ACK, with sequence number from remote peer.
virtual void OnIncomingAck(QuicPacketSequenceNumber acked_sequence_number,
- size_t acked_bytes,
+ QuicByteCount acked_bytes,
QuicTime::Delta rtt) = 0;
virtual void OnIncomingLoss(int number_of_lost_packets) = 0;
@@ -55,7 +54,7 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface {
// Inform that we sent x bytes to the wire, and if that was a retransmission.
// Note: this function must be called for every packet sent to the wire.
virtual void SentPacket(QuicPacketSequenceNumber sequence_number,
- size_t bytes,
+ QuicByteCount bytes,
bool is_retransmission) = 0;
// Calculate the time until we can send the next packet.
@@ -63,12 +62,9 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface {
// of the congestion window.
virtual QuicTime::Delta TimeUntilSend(bool is_retransmission) = 0;
- // The current available congestion window in bytes.
- virtual size_t AvailableCongestionWindow() = 0;
-
// What's the current estimated bandwidth in bytes per second.
- // Returns KNoValidEstimate when it does not have an estimate.
- virtual int BandwidthEstimate() = 0;
+ // Returns 0 when it does not have an estimate.
+ virtual QuicBandwidth BandwidthEstimate() = 0;
};
} // namespace net
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 8087283..f309c77 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -4,15 +4,13 @@
#include "net/quic/congestion_control/tcp_cubic_sender.h"
-#include "net/quic/congestion_control/quic_send_scheduler.h"
-
namespace {
// Constants based on TCP defaults.
-const size_t kHybridStartLowWindow = 16;
-const int kMaxSegmentSize = net::kMaxPacketSize;
-const int kDefaultReceiveWindow = 64000;
-const size_t kInitialCongestionWindow = 10;
-const size_t kMaxCongestionWindow = 10000;
+const int64 kHybridStartLowWindow = 16;
+const net::QuicByteCount kMaxSegmentSize = net::kMaxPacketSize;
+const net::QuicByteCount kDefaultReceiveWindow = 64000;
+const int64 kInitialCongestionWindow = 10;
+const int64 kMaxCongestionWindow = 10000;
const int kMaxBurstLength = 3;
};
@@ -23,7 +21,7 @@ TcpCubicSender::TcpCubicSender(const QuicClock* clock, bool reno)
cubic_(clock),
reno_(reno),
congestion_window_count_(0),
- receiver_congestion_window_in_bytes_(kDefaultReceiveWindow),
+ receiver_congestion_window_(kDefaultReceiveWindow),
last_received_accumulated_number_of_lost_packets_(0),
bytes_in_flight_(0),
update_end_sequence_number_(true),
@@ -47,12 +45,11 @@ void TcpCubicSender::OnIncomingQuicCongestionFeedbackFrame(
OnIncomingLoss(recovered_lost_packets);
}
}
- receiver_congestion_window_in_bytes_ =
- feedback.tcp.receive_window << 4;
+ receiver_congestion_window_ = feedback.tcp.receive_window;
}
void TcpCubicSender::OnIncomingAck(
- QuicPacketSequenceNumber acked_sequence_number, size_t acked_bytes,
+ QuicPacketSequenceNumber acked_sequence_number, QuicByteCount acked_bytes,
QuicTime::Delta rtt) {
bytes_in_flight_ -= acked_bytes;
CongestionAvoidance(acked_sequence_number);
@@ -82,7 +79,7 @@ void TcpCubicSender::OnIncomingLoss(int /*number_of_lost_packets*/) {
}
void TcpCubicSender::SentPacket(QuicPacketSequenceNumber sequence_number,
- size_t bytes,
+ QuicByteCount bytes,
bool is_retransmission) {
if (!is_retransmission) {
bytes_in_flight_ += bytes;
@@ -107,24 +104,24 @@ QuicTime::Delta TcpCubicSender::TimeUntilSend(bool is_retransmission) {
return QuicTime::Delta::Zero();
}
-size_t TcpCubicSender::AvailableCongestionWindow() {
+QuicByteCount TcpCubicSender::AvailableCongestionWindow() {
if (bytes_in_flight_ > CongestionWindow()) {
return 0;
}
return CongestionWindow() - bytes_in_flight_;
}
-size_t TcpCubicSender::CongestionWindow() {
+QuicByteCount TcpCubicSender::CongestionWindow() {
// What's the current congestion window in bytes.
- return std::min(receiver_congestion_window_in_bytes_,
- static_cast<int>(congestion_window_ * kMaxSegmentSize));
+ return std::min(receiver_congestion_window_,
+ congestion_window_ * kMaxSegmentSize);
}
-int TcpCubicSender::BandwidthEstimate() {
+QuicBandwidth TcpCubicSender::BandwidthEstimate() {
// TODO(pwestin): make a long term estimate, based on RTT and loss rate? or
// instantaneous estimate?
// Throughput ~= (1/RTT)*sqrt(3/2p)
- return kNoValidEstimate;
+ return QuicBandwidth::Zero();
}
void TcpCubicSender::Reset() {
@@ -133,12 +130,13 @@ void TcpCubicSender::Reset() {
}
bool TcpCubicSender::IsCwndLimited() const {
- const size_t congestion_window_bytes = congestion_window_ * kMaxSegmentSize;
+ const QuicByteCount congestion_window_bytes = congestion_window_ *
+ kMaxSegmentSize;
if (bytes_in_flight_ >= congestion_window_bytes) {
return true;
}
- const size_t tcp_max_burst = kMaxBurstLength * kMaxSegmentSize;
- const size_t left = congestion_window_bytes - bytes_in_flight_;
+ const QuicByteCount tcp_max_burst = kMaxBurstLength * kMaxSegmentSize;
+ const QuicByteCount left = congestion_window_bytes - bytes_in_flight_;
return left <= tcp_max_burst;
}
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index 54efedd..c91642c 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -14,11 +14,17 @@
#include "net/quic/congestion_control/cubic.h"
#include "net/quic/congestion_control/hybrid_slow_start.h"
#include "net/quic/congestion_control/send_algorithm_interface.h"
+#include "net/quic/quic_bandwidth.h"
#include "net/quic/quic_clock.h"
+#include "net/quic/quic_protocol.h"
#include "net/quic/quic_time.h"
namespace net {
+namespace test {
+class TcpCubicSenderPeer;
+} // namespace test
+
class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
public:
// Reno option provided for testing.
@@ -29,21 +35,21 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
const QuicCongestionFeedbackFrame& feedback,
const SentPacketsMap& sent_packets) OVERRIDE;
virtual void OnIncomingAck(QuicPacketSequenceNumber acked_sequence_number,
- size_t acked_bytes,
+ QuicByteCount acked_bytes,
QuicTime::Delta rtt) OVERRIDE;
virtual void OnIncomingLoss(int number_of_lost_packets) OVERRIDE;
virtual void SentPacket(QuicPacketSequenceNumber sequence_number,
- size_t bytes,
+ QuicByteCount bytes,
bool is_retransmission) OVERRIDE;
virtual QuicTime::Delta TimeUntilSend(bool is_retransmission) OVERRIDE;
- virtual size_t AvailableCongestionWindow() OVERRIDE;
- virtual int BandwidthEstimate() OVERRIDE;
+ virtual QuicBandwidth BandwidthEstimate() OVERRIDE;
// End implementation of SendAlgorithmInterface.
- // Visible for testing.
- size_t CongestionWindow();
-
private:
+ friend class test::TcpCubicSenderPeer;
+
+ QuicByteCount AvailableCongestionWindow();
+ QuicByteCount CongestionWindow();
void Reset();
void AckAccounting(QuicTime::Delta rtt);
void CongestionAvoidance(QuicPacketSequenceNumber ack);
@@ -57,16 +63,16 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
const bool reno_;
// ACK counter for the Reno implementation.
- size_t congestion_window_count_;
+ int64 congestion_window_count_;
// Receiver side advertised window.
- int receiver_congestion_window_in_bytes_;
+ QuicByteCount receiver_congestion_window_;
// Receiver side advertised packet loss.
int last_received_accumulated_number_of_lost_packets_;
// Bytes in flight, aka bytes on the wire.
- size_t bytes_in_flight_;
+ QuicByteCount bytes_in_flight_;
// We need to keep track of the end sequence number of each RTT "burst".
bool update_end_sequence_number_;
@@ -80,6 +86,8 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
// Min RTT during this session.
QuicTime::Delta delay_min_;
+
+ DISALLOW_COPY_AND_ASSIGN(TcpCubicSender);
};
} // namespace net
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index 1ce7d7a..5e3edc4 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -12,26 +12,32 @@
namespace net {
namespace test {
-const uint32 kDefaultWindowTCP = 10 * net::kMaxPacketSize;
-const size_t kNoNBytesInFlight = 0;
+const uint32 kDefaultWindowTCP = 10 * kMaxPacketSize;
+const QuicByteCount kNoNBytesInFlight = 0;
-class QuicTcpCubicSenderTest : public ::testing::Test {
+class TcpCubicSenderPeer : public TcpCubicSender {
+ public:
+ explicit TcpCubicSenderPeer(const QuicClock* clock, bool reno)
+ : TcpCubicSender(clock, reno) {
+ }
+ using TcpCubicSender::AvailableCongestionWindow;
+ using TcpCubicSender::CongestionWindow;
+};
+
+class TcpCubicSenderTest : public ::testing::Test {
protected:
- QuicTcpCubicSenderTest()
+ TcpCubicSenderTest()
: rtt_(QuicTime::Delta::FromMilliseconds(60)),
- one_ms_(QuicTime::Delta::FromMilliseconds(1)) {
- }
- void SetUp() {
- bool reno = true;
- sender_.reset(new TcpCubicSender(&clock_, reno));
- receiver_.reset(new TcpReceiver());
- sequence_number_ = 1;
- acked_sequence_number_ = 0;
+ one_ms_(QuicTime::Delta::FromMilliseconds(1)),
+ sender_(new TcpCubicSenderPeer(&clock_, true)),
+ receiver_(new TcpReceiver()),
+ sequence_number_(1),
+ acked_sequence_number_(0) {
}
void SendAvailableCongestionWindow() {
- size_t bytes_to_send = sender_->AvailableCongestionWindow();
+ QuicByteCount bytes_to_send = sender_->AvailableCongestionWindow();
while (bytes_to_send > 0) {
- size_t bytes_in_packet = std::min(kMaxPacketSize, bytes_to_send);
+ QuicByteCount bytes_in_packet = std::min(kMaxPacketSize, bytes_to_send);
sender_->SentPacket(sequence_number_++, bytes_in_packet, false);
bytes_to_send -= bytes_in_packet;
if (bytes_to_send > 0) {
@@ -52,13 +58,13 @@ class QuicTcpCubicSenderTest : public ::testing::Test {
const QuicTime::Delta one_ms_;
MockClock clock_;
SendAlgorithmInterface::SentPacketsMap not_used_;
- scoped_ptr<TcpCubicSender> sender_;
+ scoped_ptr<TcpCubicSenderPeer> sender_;
scoped_ptr<TcpReceiver> receiver_;
QuicPacketSequenceNumber sequence_number_;
QuicPacketSequenceNumber acked_sequence_number_;
};
-TEST_F(QuicTcpCubicSenderTest, SimpleSender) {
+TEST_F(TcpCubicSenderTest, SimpleSender) {
QuicCongestionFeedbackFrame feedback;
// At startup make sure we are at the default.
EXPECT_EQ(kDefaultWindowTCP,
@@ -77,7 +83,7 @@ TEST_F(QuicTcpCubicSenderTest, SimpleSender) {
EXPECT_TRUE(sender_->TimeUntilSend(true).IsZero());
}
-TEST_F(QuicTcpCubicSenderTest, ExponentialSlowStart) {
+TEST_F(TcpCubicSenderTest, ExponentialSlowStart) {
const int kNumberOfAck = 20;
QuicCongestionFeedbackFrame feedback;
// At startup make sure we can send.
@@ -93,12 +99,12 @@ TEST_F(QuicTcpCubicSenderTest, ExponentialSlowStart) {
SendAvailableCongestionWindow();
AckNPackets(2);
}
- size_t bytes_to_send = sender_->CongestionWindow();
+ QuicByteCount bytes_to_send = sender_->CongestionWindow();
EXPECT_EQ(kDefaultWindowTCP + kMaxPacketSize * 2 * kNumberOfAck,
bytes_to_send);
}
-TEST_F(QuicTcpCubicSenderTest, SlowStartAckTrain) {
+TEST_F(TcpCubicSenderTest, SlowStartAckTrain) {
// Make sure that we fall out of slow start when we send ACK train longer
// than half the RTT, in this test case 30ms, which is more than 30 calls to
// Ack2Packets in one round.
@@ -119,7 +125,7 @@ TEST_F(QuicTcpCubicSenderTest, SlowStartAckTrain) {
SendAvailableCongestionWindow();
AckNPackets(2);
}
- size_t expected_congestion_window = kDefaultWindowTCP +
+ QuicByteCount expected_congestion_window = kDefaultWindowTCP +
(kMaxPacketSize * 2 * kNumberOfAck);
EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow());
// We should now have fallen out of slow start.
@@ -142,7 +148,7 @@ TEST_F(QuicTcpCubicSenderTest, SlowStartAckTrain) {
EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow());
}
-TEST_F(QuicTcpCubicSenderTest, SlowStartPacketLoss) {
+TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) {
// Make sure that we fall out of slow start when we encounter a packet loss.
const int kNumberOfAck = 10;
QuicCongestionFeedbackFrame feedback;
@@ -160,7 +166,7 @@ TEST_F(QuicTcpCubicSenderTest, SlowStartPacketLoss) {
AckNPackets(2);
}
SendAvailableCongestionWindow();
- size_t expected_congestion_window = kDefaultWindowTCP +
+ QuicByteCount expected_congestion_window = kDefaultWindowTCP +
(kMaxPacketSize * 2 * kNumberOfAck);
EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow());
diff --git a/net/quic/congestion_control/tcp_receiver.cc b/net/quic/congestion_control/tcp_receiver.cc
index 3401b21..465e40f 100644
--- a/net/quic/congestion_control/tcp_receiver.cc
+++ b/net/quic/congestion_control/tcp_receiver.cc
@@ -8,11 +8,11 @@
namespace net {
// Originally 64K bytes for TCP, setting it to 256K to support higher bitrates.
-const size_t kReceiveWindowTCP = 256000;
+const QuicByteCount kReceiveWindowTCP = 256000;
TcpReceiver::TcpReceiver()
: accumulated_number_of_recoverd_lost_packets_(0),
- receive_window_in_bytes_(kReceiveWindowTCP) {
+ receive_window_(kReceiveWindowTCP) {
}
bool TcpReceiver::GenerateCongestionFeedback(
@@ -20,11 +20,11 @@ bool TcpReceiver::GenerateCongestionFeedback(
feedback->type = kTCP;
feedback->tcp.accumulated_number_of_lost_packets =
accumulated_number_of_recoverd_lost_packets_;
- feedback->tcp.receive_window = receive_window_in_bytes_ >> 4;
+ feedback->tcp.receive_window = receive_window_;
return true;
}
-void TcpReceiver::RecordIncomingPacket(size_t bytes,
+void TcpReceiver::RecordIncomingPacket(QuicByteCount bytes,
QuicPacketSequenceNumber sequence_number,
QuicTime timestamp,
bool revived) {
diff --git a/net/quic/congestion_control/tcp_receiver.h b/net/quic/congestion_control/tcp_receiver.h
index 48d781f..695ffbb 100644
--- a/net/quic/congestion_control/tcp_receiver.h
+++ b/net/quic/congestion_control/tcp_receiver.h
@@ -24,7 +24,7 @@ class NET_EXPORT_PRIVATE TcpReceiver : public ReceiveAlgorithmInterface {
virtual bool GenerateCongestionFeedback(
QuicCongestionFeedbackFrame* feedback) OVERRIDE;
- virtual void RecordIncomingPacket(size_t bytes,
+ virtual void RecordIncomingPacket(QuicByteCount bytes,
QuicPacketSequenceNumber sequence_number,
QuicTime timestamp,
bool revived) OVERRIDE;
@@ -32,9 +32,10 @@ class NET_EXPORT_PRIVATE TcpReceiver : public ReceiveAlgorithmInterface {
private:
// We need to keep track of FEC recovered packets.
int accumulated_number_of_recoverd_lost_packets_;
- uint32 receive_window_in_bytes_;
+ QuicByteCount receive_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(TcpReceiver);
};
} // namespace net
-
#endif // NET_QUIC_CONGESTION_CONTROL_TCP_RECEIVER_H_
diff --git a/net/quic/congestion_control/tcp_receiver_test.cc b/net/quic/congestion_control/tcp_receiver_test.cc
index 1d4a2bb..5bb12f4 100644
--- a/net/quic/congestion_control/tcp_receiver_test.cc
+++ b/net/quic/congestion_control/tcp_receiver_test.cc
@@ -25,12 +25,12 @@ TEST_F(QuicTcpReceiverTest, SimpleReceiver) {
receiver_->RecordIncomingPacket(1, 1, timestamp, false);
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
EXPECT_EQ(kTCP, feedback.type);
- EXPECT_EQ(256000, feedback.tcp.receive_window << 4);
+ EXPECT_EQ(256000u, feedback.tcp.receive_window);
EXPECT_EQ(0, feedback.tcp.accumulated_number_of_lost_packets);
receiver_->RecordIncomingPacket(1, 2, timestamp, true);
ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
EXPECT_EQ(kTCP, feedback.type);
- EXPECT_EQ(256000, feedback.tcp.receive_window << 4);
+ EXPECT_EQ(256000u, feedback.tcp.receive_window);
EXPECT_EQ(1, feedback.tcp.accumulated_number_of_lost_packets);
}
diff --git a/net/quic/quic_bandwidth.cc b/net/quic/quic_bandwidth.cc
index c270d01..33cb67e 100644
--- a/net/quic/quic_bandwidth.cc
+++ b/net/quic/quic_bandwidth.cc
@@ -41,10 +41,11 @@ QuicBandwidth QuicBandwidth::FromKBytesPerSecond(int64 k_bytes_per_second) {
}
// static
-QuicBandwidth QuicBandwidth::FromBytesAndTimeDelta(int64 bytes,
+QuicBandwidth QuicBandwidth::FromBytesAndTimeDelta(QuicByteCount bytes,
QuicTime::Delta delta) {
DCHECK_LT(bytes,
- kQuicInfiniteBandwidth / (8 * base::Time::kMicrosecondsPerSecond));
+ static_cast<uint64>(kQuicInfiniteBandwidth /
+ (8 * base::Time::kMicrosecondsPerSecond)));
int64 bytes_per_second = (bytes * base::Time::kMicrosecondsPerSecond) /
delta.ToMicroseconds();
return QuicBandwidth(bytes_per_second * 8);
@@ -71,6 +72,17 @@ int64 QuicBandwidth::ToKBytesPerSecond() const {
return bits_per_second_ / 8000;
}
+QuicByteCount QuicBandwidth::ToBytesPerPeriod(
+ QuicTime::Delta time_period) const {
+ return ToBytesPerSecond() * time_period.ToMicroseconds() /
+ base::Time::kMicrosecondsPerSecond;
+}
+
+int64 QuicBandwidth::ToKBytesPerPeriod(QuicTime::Delta time_period) const {
+ return ToKBytesPerSecond() * time_period.ToMicroseconds() /
+ base::Time::kMicrosecondsPerSecond;
+}
+
bool QuicBandwidth::IsZero() const {
return (bits_per_second_ == 0);
}
@@ -83,4 +95,8 @@ QuicBandwidth QuicBandwidth::Subtract(const QuicBandwidth& delta) const {
return QuicBandwidth(bits_per_second_ - delta.bits_per_second_);
}
+QuicBandwidth QuicBandwidth::Scale(float scale_factor) const {
+ return QuicBandwidth(bits_per_second_ * scale_factor);
+}
+
} // namespace net
diff --git a/net/quic/quic_bandwidth.h b/net/quic/quic_bandwidth.h
index 522bd4c..71c4b2d 100644
--- a/net/quic/quic_bandwidth.h
+++ b/net/quic/quic_bandwidth.h
@@ -12,7 +12,10 @@
namespace net {
+typedef uint64 QuicByteCount;
+
class NET_EXPORT_PRIVATE QuicBandwidth {
+
public:
// Creates a new QuicBandwidth with an internal value of 0.
static QuicBandwidth Zero();
@@ -30,7 +33,7 @@ class NET_EXPORT_PRIVATE QuicBandwidth {
static QuicBandwidth FromKBytesPerSecond(int64 k_bytes_per_second);
// Create a new QuicBandwidth based on the bytes per the elapsed delta.
- static QuicBandwidth FromBytesAndTimeDelta(int64 bytes,
+ static QuicBandwidth FromBytesAndTimeDelta(QuicByteCount bytes,
QuicTime::Delta delta);
int64 ToBitsPerSecond() const;
@@ -41,12 +44,18 @@ class NET_EXPORT_PRIVATE QuicBandwidth {
int64 ToKBytesPerSecond() const;
+ QuicByteCount ToBytesPerPeriod(QuicTime::Delta time_period) const;
+
+ int64 ToKBytesPerPeriod(QuicTime::Delta time_period) const;
+
bool IsZero() const;
QuicBandwidth Add(const QuicBandwidth& delta) const;
QuicBandwidth Subtract(const QuicBandwidth& delta) const;
+ QuicBandwidth Scale(float scale_factor) const;
+
private:
explicit QuicBandwidth(int64 bits_per_second);
int64 bits_per_second_;
diff --git a/net/quic/quic_bandwidth_test.cc b/net/quic/quic_bandwidth_test.cc
index aa089e6..1090f0b 100644
--- a/net/quic/quic_bandwidth_test.cc
+++ b/net/quic/quic_bandwidth_test.cc
@@ -6,7 +6,7 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
-namespace testing {
+namespace test {
class QuicBandwidthTest : public ::testing::Test {
};
@@ -57,5 +57,26 @@ TEST_F(QuicBandwidthTest, TimeDelta) {
1000, QuicTime::Delta::FromMilliseconds(100)));
}
-} // namespace testing
+TEST_F(QuicBandwidthTest, Scale) {
+ EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(500),
+ QuicBandwidth::FromKBytesPerSecond(1000).Scale(0.5f));
+ EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(750),
+ QuicBandwidth::FromKBytesPerSecond(1000).Scale(0.75f));
+ EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(1250),
+ QuicBandwidth::FromKBytesPerSecond(1000).Scale(1.25f));
+}
+
+
+TEST_F(QuicBandwidthTest, BytesPerPeriod) {
+ EXPECT_EQ(2000u, QuicBandwidth::FromKBytesPerSecond(2000).ToBytesPerPeriod(
+ QuicTime::Delta::FromMilliseconds(1)));
+ EXPECT_EQ(2u, QuicBandwidth::FromKBytesPerSecond(2000).ToKBytesPerPeriod(
+ QuicTime::Delta::FromMilliseconds(1)));
+ EXPECT_EQ(200000u, QuicBandwidth::FromKBytesPerSecond(2000).ToBytesPerPeriod(
+ QuicTime::Delta::FromMilliseconds(100)));
+ EXPECT_EQ(200u, QuicBandwidth::FromKBytesPerSecond(2000).ToKBytesPerPeriod(
+ QuicTime::Delta::FromMilliseconds(100)));
+}
+
+} // namespace test
} // namespace net
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 77d15f1..c0d2194 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -9,8 +9,6 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "net/base/net_errors.h"
-#include "net/quic/congestion_control/quic_receipt_metrics_collector.h"
-#include "net/quic/congestion_control/quic_send_scheduler.h"
#include "net/quic/quic_utils.h"
using base::hash_map;
@@ -46,7 +44,7 @@ const int kMaxRetransmissionsPerAck = 10;
// delivery.
// TODO(ianswett): Change to match TCP's rule of retransmitting once an ack
// at least 3 sequence numbers larger arrives.
-const int kNumberOfNacksBeforeRetransmission = 3;
+const size_t 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.
@@ -57,9 +55,11 @@ const int kMaxPacketsToSerializeAtOnce = 6;
// eventually cede. 10 is arbitrary.
const int kMaxPacketsPerRetransmissionAlarm = 10;
-// Named constants for SendPacket options.
+// Named constant for WriteQueuedData().
+const bool kFlush = true;
+// Named constant for WritePacket(), SendOrQueuePacket().
const bool kForce = true;
-const bool kShouldRetransmit = true;
+// Named constant for CanWrite().
const bool kIsRetransmission = true;
bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) {
@@ -70,14 +70,12 @@ bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) {
} // namespace
QuicConnection::UnackedPacket::UnackedPacket(QuicFrames unacked_frames)
- : frames(unacked_frames),
- number_nacks(0) {
+ : frames(unacked_frames) {
}
QuicConnection::UnackedPacket::UnackedPacket(QuicFrames unacked_frames,
std::string data)
: frames(unacked_frames),
- number_nacks(0),
data(data) {
}
@@ -166,27 +164,21 @@ void QuicConnection::DeleteEnclosedFrame(QuicFrame* frame) {
void QuicConnection::DeleteEnclosedFrames(UnackedPacket* unacked) {
for (QuicFrames::iterator it = unacked->frames.begin();
it != unacked->frames.end(); ++it) {
- DCHECK(ShouldRetransmit(*it));
DeleteEnclosedFrame(&(*it));
}
}
-bool QuicConnection::ShouldRetransmit(const QuicFrame& frame) {
- return frame.type != ACK_FRAME && frame.type != CONGESTION_FEEDBACK_FRAME;
-}
-
void QuicConnection::OnError(QuicFramer* framer) {
SendConnectionClose(framer->error());
}
-void QuicConnection::OnPacket(const IPEndPoint& self_address,
- const IPEndPoint& peer_address) {
+void QuicConnection::OnPacket() {
time_of_last_packet_ = clock_->Now();
DVLOG(1) << "last packet: " << time_of_last_packet_.ToMicroseconds();
// TODO(alyssar, rch) handle migration!
- self_address_ = self_address;
- peer_address_ = peer_address;
+ self_address_ = last_self_address_;
+ peer_address_ = last_peer_address_;
}
void QuicConnection::OnPublicResetPacket(
@@ -340,9 +332,11 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer(
// incoming_ack shows they've been seen by the peer.
UnackedPacketMap::iterator it = unacked_packets_.begin();
while (it != unacked_packets_.end()) {
- if (!incoming_ack.received_info.IsAwaitingPacket(it->first)) {
+ QuicPacketSequenceNumber sequence_number = it->first;
+ UnackedPacket* unacked = it->second;
+ if (!incoming_ack.received_info.IsAwaitingPacket(sequence_number)) {
// Packet was acked, so remove it from our unacked packet list.
- DVLOG(1) << "Got an ack for " << it->first;
+ DVLOG(1) << "Got an ack for " << sequence_number;
// TODO(rch): This is inefficient and should be sped up.
// TODO(ianswett): Ensure this inner loop is applicable now that we're
// always sending packets with new sequence numbers. I believe it may
@@ -352,46 +346,46 @@ void QuicConnection::UpdatePacketInformationReceivedByPeer(
// attempted).
for (QueuedPacketList::iterator q = queued_packets_.begin();
q != queued_packets_.end(); ++q) {
- if (q->sequence_number == it->first) {
+ if (q->sequence_number == sequence_number) {
queued_packets_.erase(q);
break;
}
}
- acked_packets.insert(it->first);
- DeleteEnclosedFrames(it->second);
- delete it->second;
+ acked_packets.insert(sequence_number);
+ DeleteEnclosedFrames(unacked);
+ delete unacked;
UnackedPacketMap::iterator it_tmp = it;
++it;
unacked_packets_.erase(it_tmp);
+ retransmission_map_.erase(sequence_number);
} else {
// 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;
- if (it->first < lowest_unacked) {
- lowest_unacked = it->first;
+ DVLOG(1) << "still missing " << sequence_number;
+ if (sequence_number < lowest_unacked) {
+ lowest_unacked = sequence_number;
}
-
+ ++it;
// Determine if this packet is being explicitly nacked and, if so, if it
// is worth retransmitting.
- QuicPacketSequenceNumber retransmission_number = 0;
- if (it->first < peer_largest_observed_packet_) {
+ if (sequence_number <= 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 >= kNumberOfNacksBeforeRetransmission &&
+ RetransmissionMap::iterator retransmission_it =
+ retransmission_map_.find(sequence_number);
+ ++(retransmission_it->second.number_nacks);
+ if (retransmission_it->second.number_nacks >=
+ kNumberOfNacksBeforeRetransmission &&
retransmitted_packets < kMaxRetransmissionsPerAck) {
- retransmission_number = it->first;
+ ++retransmitted_packets;
+ DVLOG(1) << "Trying to retransmit packet " << sequence_number
+ << " as it has been nacked 3 or more times.";
+ // TODO(satyamshekhar): save in a vector and retransmit after the
+ // loop.
+ RetransmitPacket(sequence_number);
}
}
-
- ++it;
- if (retransmission_number > 0) {
- ++retransmitted_packets;
- DVLOG(1) << "Trying to retransmit packet " << retransmission_number
- << " as it has been nacked 3 or more times.";
- MaybeRetransmitPacket(retransmission_number);
- }
}
}
if (acked_packets.size() > 0) {
@@ -461,10 +455,9 @@ void QuicConnection::OnPacketComplete() {
DLOG(INFO) << "Got packet " << last_header_.packet_sequence_number
<< " with " << last_stream_frames_.size()
<< " stream frames for " << last_header_.public_header.guid;
- congestion_manager_.RecordIncomingPacket(last_size_,
- last_header_.packet_sequence_number,
- clock_->Now(),
- last_packet_revived_);
+ congestion_manager_.RecordIncomingPacket(
+ last_size_, last_header_.packet_sequence_number,
+ clock_->Now(), last_packet_revived_);
} else {
DLOG(INFO) << "Got revived packet with " << last_stream_frames_.size()
<< " frames.";
@@ -486,53 +479,55 @@ 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(DefaultRetransmissionTime());
+ helper_->SetAckAlarm(congestion_manager_.DefaultRetransmissionTime());
}
send_ack_in_response_to_packet_ = !send_ack_in_response_to_packet_;
}
-QuicConsumedData QuicConnection::SendStreamData(
- QuicStreamId id,
+QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id,
StringPiece data,
QuicStreamOffset offset,
bool fin) {
size_t total_bytes_consumed = 0;
bool fin_consumed = false;
- packet_creator_.MaybeStartFEC();
while (queued_packets_.empty()) {
- QuicFrames frames;
- size_t bytes_consumed =
- packet_creator_.CreateStreamFrame(id, data, offset, fin, &frames);
+ packet_creator_.MaybeStartFEC();
+ QuicFrame frame;
+ size_t bytes_consumed = packet_creator_.CreateStreamFrame(
+ id, data, offset, fin, &frame);
+ bool success = packet_creator_.AddFrame(frame);
+ DCHECK(success);
+
total_bytes_consumed += bytes_consumed;
offset += bytes_consumed;
fin_consumed = fin && bytes_consumed == data.size();
data.remove_prefix(bytes_consumed);
- PacketPair pair = packet_creator_.SerializeAllFrames(frames);
+ // TODO(ianswett): Currently this does not pack stream data together,
+ // because SendStreamData does not know if there are more streams to write.
// TODO(ianswett): Restore packet reordering.
- 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));
+ SendOrQueueCurrentPacket();
- if (packet_creator_.ShouldSendFec(data.size() == 0)) {
+ if (packet_creator_.ShouldSendFec(false)) {
PacketPair fec_pair = packet_creator_.SerializeFec();
- // Never resend FEC packets.
- SendPacket(fec_pair.first, fec_pair.second, !kShouldRetransmit, !kForce,
- !kIsRetransmission);
+ // Never retransmit FEC packets.
+ SendOrQueuePacket(fec_pair.first, fec_pair.second, !kForce);
}
- 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
+ if (data.empty()) {
+ // We're done writing the data. Exit the loop.
+ // We don't make this a precondition because we could have 0 bytes of data
// if we're simply writing a fin.
break;
}
}
+ // Ensure the FEC group is closed at the end of this method.
+ if (packet_creator_.ShouldSendFec(true)) {
+ PacketPair fec_pair = packet_creator_.SerializeFec();
+ // Never retransmit FEC packets.
+ SendOrQueuePacket(fec_pair.first, fec_pair.second, !kForce);
+ }
return QuicConsumedData(total_bytes_consumed, fin_consumed);
}
@@ -543,8 +538,8 @@ void QuicConnection::SendRstStream(QuicStreamId id,
new QuicRstStreamFrame(id, offset, error)));
// Try to write immediately if possible.
- if (CanWrite(false)) {
- WriteData();
+ if (CanWrite(!kIsRetransmission)) {
+ WriteQueuedData(kFlush);
}
}
@@ -553,15 +548,21 @@ void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
const QuicEncryptedPacket& packet) {
last_packet_revived_ = false;
last_size_ = packet.length();
- framer_.ProcessPacket(self_address, peer_address, packet);
-
+ last_self_address_ = self_address;
+ last_peer_address_ = peer_address;
+ framer_.ProcessPacket(packet);
MaybeProcessRevivedPacket();
}
bool QuicConnection::OnCanWrite() {
write_blocked_ = false;
- WriteData();
+ WriteQueuedData(!kFlush);
+
+ // Ensure there's enough room for a StreamFrame before calling the visitor.
+ if (packet_creator_.BytesFree() <= kMinStreamFrameLength) {
+ SendOrQueueCurrentPacket();
+ }
// If we've sent everything we had queued and we're still not blocked, let the
// visitor know it can write more.
@@ -580,56 +581,70 @@ bool QuicConnection::OnCanWrite() {
}
}
+ // If a write can still be performed, ensure there are no pending frames,
+ // even if they didn't fill a packet.
+ if (packet_creator_.HasPendingFrames() && CanWrite(!kIsRetransmission)) {
+ SendOrQueueCurrentPacket();
+ }
+
return !write_blocked_;
}
-bool QuicConnection::WriteData() {
- DCHECK_EQ(false, write_blocked_);
- // Serialize the ack and congestion frames before draining the pending queue.
- if (should_send_ack_) {
- queued_control_frames_.push_back(QuicFrame(&outgoing_ack_));
- }
- if (should_send_congestion_feedback_) {
- queued_control_frames_.push_back(QuicFrame(&outgoing_congestion_feedback_));
- }
- while (!queued_control_frames_.empty()) {
- size_t num_serialized;
- PacketPair pair = packet_creator_.SerializeFrames(
- queued_control_frames_, &num_serialized);
- // 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 (ShouldRetransmit(*iter)) {
- unacked_frames.push_back(*iter);
- }
- }
- if (!unacked_frames.empty()) {
- unacked_packets_.insert(make_pair(pair.first,
- new UnackedPacket(unacked_frames)));
- }
- queued_packets_.push_back(QueuedPacket(
- pair.first, pair.second, !unacked_frames.empty(), false));
- queued_control_frames_.erase(
- queued_control_frames_.begin(),
- queued_control_frames_.begin() + num_serialized);
- }
- should_send_ack_ = false;
- should_send_congestion_feedback_ = false;
+bool QuicConnection::WriteQueuedData(bool flush) {
+ DCHECK(!write_blocked_);
+ DCHECK(!packet_creator_.HasPendingFrames());
+ // Send all queued packets first.
size_t num_queued_packets = queued_packets_.size() + 1;
+ QueuedPacketList::iterator packet_iterator = queued_packets_.begin();
while (!write_blocked_ && !helper_->IsSendAlarmSet() &&
- !queued_packets_.empty()) {
+ packet_iterator != queued_packets_.end()) {
// Ensure that from one iteration of this loop to the next we
// succeeded in sending a packet so we don't infinitely loop.
// TODO(rch): clean up and close the connection if we really hit this.
DCHECK_LT(queued_packets_.size(), num_queued_packets);
num_queued_packets = queued_packets_.size();
- QueuedPacket p = queued_packets_.front();
- queued_packets_.pop_front();
- SendPacket(p.sequence_number, p.packet, p.should_retransmit, !kForce,
- p.is_retransmission);
+ if (WritePacket(packet_iterator->sequence_number,
+ packet_iterator->packet, !kForce)) {
+ packet_iterator = queued_packets_.erase(packet_iterator);
+ } else {
+ // TODO(ianswett): Why not break or return false here?
+ ++packet_iterator;
+ }
+ }
+
+ if (write_blocked_) {
+ return false;
+ }
+
+ while ((!queued_control_frames_.empty() || should_send_ack_ ||
+ should_send_congestion_feedback_) && CanWrite(!kIsRetransmission)) {
+ bool full_packet = false;
+ if (!queued_control_frames_.empty()) {
+ full_packet = !packet_creator_.AddFrame(queued_control_frames_.back());
+ if (!full_packet) {
+ queued_control_frames_.pop_back();
+ }
+ } else if (should_send_ack_) {
+ full_packet = !packet_creator_.AddFrame(QuicFrame(&outgoing_ack_));
+ if (!full_packet) {
+ should_send_ack_ = false;
+ }
+ } else if (should_send_congestion_feedback_) {
+ full_packet = !packet_creator_.AddFrame(
+ QuicFrame(&outgoing_congestion_feedback_));
+ if (!full_packet) {
+ should_send_congestion_feedback_ = false;
+ }
+ }
+
+ if (full_packet) {
+ SendOrQueueCurrentPacket();
+ }
+ }
+
+ if (flush && packet_creator_.HasPendingFrames()) {
+ SendOrQueueCurrentPacket();
}
return !write_blocked_;
@@ -643,44 +658,61 @@ void QuicConnection::RecordPacketReceived(const QuicPacketHeader& header) {
bool QuicConnection::MaybeRetransmitPacketForRTO(
QuicPacketSequenceNumber sequence_number) {
+ DCHECK_EQ(ContainsKey(unacked_packets_, sequence_number),
+ ContainsKey(retransmission_map_, sequence_number));
+
+ if (!ContainsKey(unacked_packets_, sequence_number)) {
+ DVLOG(2) << "alarm fired for " << sequence_number
+ << " but it has been acked or already retransmitted with "
+ << " different sequence number.";
+ // So no extra delay is added for this packet.
+ return true;
+ }
+
// 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
// have been received by the peer and just wasn't acked due to the ack frame
// running out of space.
if (received_truncated_ack_ &&
- sequence_number > peer_largest_observed_packet_ &&
- ContainsKey(unacked_packets_, sequence_number)) {
+ sequence_number > peer_largest_observed_packet_) {
return false;
} else {
- MaybeRetransmitPacket(sequence_number);
+ RetransmitPacket(sequence_number);
return true;
}
}
-void QuicConnection::MaybeRetransmitPacket(
+void QuicConnection::RetransmitPacket(
QuicPacketSequenceNumber sequence_number) {
- UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
-
- if (it != unacked_packets_.end()) {
- 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 retransmission.
- // Retransmitted data packets do not use FEC, even when it's enabled.
- PacketPair packetpair = packet_creator_.SerializeAllFrames(unacked->frames);
- 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, kShouldRetransmit,
- !kForce, kIsRetransmission);
- } else {
- DVLOG(2) << "alarm fired for " << sequence_number
- << " but it has been acked";
- }
+ UnackedPacketMap::iterator unacked_it =
+ unacked_packets_.find(sequence_number);
+ RetransmissionMap::iterator retransmission_it =
+ retransmission_map_.find(sequence_number);
+ // There should always be an entry corresponding to |sequence_number| in
+ // both |retransmission_map_| and |unacked_packets_|. Retransmissions due to
+ // RTO for sequence numbers that are already acked or retransmitted are
+ // ignored by MaybeRetransmitPacketForRTO.
+ DCHECK(unacked_it != unacked_packets_.end());
+ DCHECK(retransmission_it != retransmission_map_.end());
+ UnackedPacket* unacked = unacked_it->second;
+ // TODO(ianswett): Never change the sequence number of the connect packet.
+ // Re-packetize the frames with a new sequence number for retransmission.
+ // Retransmitted data packets do not use FEC, even when it's enabled.
+ PacketPair packetpair = packet_creator_.SerializeAllFrames(unacked->frames);
+ RetransmissionInfo retransmission_info(packetpair.first);
+ retransmission_info.number_retransmissions =
+ retransmission_it->second.number_retransmissions + 1;
+ retransmission_map_.insert(make_pair(packetpair.first, retransmission_info));
+ // Remove info with old sequence number.
+ unacked_packets_.erase(unacked_it);
+ retransmission_map_.erase(retransmission_it);
+ DVLOG(1) << "Retransmitting unacked packet " << sequence_number << " as "
+ << packetpair.first;
+ unacked_packets_.insert(make_pair(packetpair.first, unacked));
+ // Make sure if this was our least unacked packet, that we update our
+ // outgoing ack. If this wasn't the least unacked, this is a no-op.
+ UpdateLeastUnacked(sequence_number);
+ SendOrQueuePacket(packetpair.first, packetpair.second, !kForce);
}
bool QuicConnection::CanWrite(bool is_retransmission) {
@@ -692,81 +724,91 @@ bool QuicConnection::CanWrite(bool is_retransmission) {
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.
+ // TODO(pwestin): we need to handle delay.IsInfinite() separately.
helper_->SetSendAlarm(delay);
return false;
}
return true;
}
-bool QuicConnection::SendPacket(QuicPacketSequenceNumber sequence_number,
- QuicPacket* packet,
- bool should_retransmit,
- bool force,
- bool is_retransmission) {
+bool QuicConnection::IsRetransmission(
+ QuicPacketSequenceNumber sequence_number) {
+ RetransmissionMap::iterator it = retransmission_map_.find(sequence_number);
+ return it != retransmission_map_.end() &&
+ it->second.number_retransmissions > 0;
+}
+
+void QuicConnection::MaybeSetupRetransmission(
+ QuicPacketSequenceNumber sequence_number) {
+ RetransmissionMap::iterator it = retransmission_map_.find(sequence_number);
+ if (it == retransmission_map_.end()) {
+ DVLOG(1) << "Will not retransmit packet " << sequence_number;
+ return;
+ }
+
+ RetransmissionInfo retransmission_info = it->second;
+ QuicTime::Delta retransmission_delay =
+ congestion_manager_.GetRetransmissionDelay(
+ retransmission_info.number_retransmissions);
+ retransmission_info.scheduled_time = clock_->Now().Add(retransmission_delay);
+ retransmission_timeouts_.push(retransmission_info);
+
+ // 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(retransmission_delay);
+ }
+
+ // The second case should never happen in the real world, but does here
+ // because we sometimes send out of order to validate corner cases.
+ if (outgoing_ack_.sent_info.least_unacked == 0 ||
+ sequence_number < outgoing_ack_.sent_info.least_unacked) {
+ outgoing_ack_.sent_info.least_unacked = sequence_number;
+ }
+}
+
+bool QuicConnection::WritePacket(QuicPacketSequenceNumber sequence_number,
+ QuicPacket* packet,
+ bool forced) {
if (!connected_) {
DLOG(INFO)
<< "Dropping packet to be sent since connection is disconnected.";
delete packet;
- return false;
+ // Returning true because we deleted the packet and the caller shouldn't
+ // delete it again.
+ return true;
}
- // 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_retransmission)) {
- queued_packets_.push_back(
- QueuedPacket(sequence_number, packet, should_retransmit,
- is_retransmission));
- return false;
- }
- }
- 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 ||
- sequence_number < outgoing_ack_.sent_info.least_unacked) {
- outgoing_ack_.sent_info.least_unacked = sequence_number;
- }
+ bool is_retransmission = IsRetransmission(sequence_number);
+ // If we are not forced and we can't write, then simply return false;
+ if (!forced && !CanWrite(is_retransmission)) {
+ return false;
}
scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*packet));
- int error;
DLOG(INFO) << "Sending packet : "
<< (packet->is_fec_packet() ? "FEC " :
- (should_retransmit ? "data bearing " : " ack only "))
+ (ContainsKey(retransmission_map_, sequence_number) ?
+ "data bearing " : " ack only "))
<< "packet " << sequence_number;
DCHECK(encrypted->length() <= kMaxPacketSize)
<< "Packet " << sequence_number << " will not be read; too large: "
- << packet->length() << " " << encrypted->length() << " " << outgoing_ack_;
+ << packet->length() << " " << encrypted->length() << " "
+ << outgoing_ack_;
+ int error;
int rv = helper_->WritePacketToWire(*encrypted, &error);
- if (rv == -1) {
- if (error == ERR_IO_PENDING) {
- write_blocked_ = true;
-
- // TODO(rch): uncomment when we get non-blocking (and non-retrying)
- // UDP sockets.
- /*
- queued_packets_.push_front(
- QueuedPacket(sequence_number, packet, should_retransmit,
- is_retransmission));
- */
- return false;
- }
- // TODO(wtc): is it correct to fall through to return true?
+ if (rv == -1 && error == ERR_IO_PENDING) {
+ write_blocked_ = true;
+ return false;
}
+ // TODO(wtc): Is it correct to continue if the write failed.
+
+ // Set the retransmit alarm only when we have sent the packet to the client
+ // and not when it goes to the pending queue, otherwise we will end up adding
+ // an entry to retransmission_timeout_ every time we attempt a write.
+ MaybeSetupRetransmission(sequence_number);
time_of_last_packet_ = clock_->Now();
DVLOG(1) << "last packet: " << time_of_last_packet_.ToMicroseconds();
@@ -777,6 +819,41 @@ bool QuicConnection::SendPacket(QuicPacketSequenceNumber sequence_number,
return true;
}
+void QuicConnection::SendOrQueueCurrentPacket() {
+ QuicFrames retransmittable_frames;
+ PacketPair pair = packet_creator_.SerializePacket(&retransmittable_frames);
+ const bool should_retransmit = !retransmittable_frames.empty();
+ if (should_retransmit) {
+ UnackedPacket* unacked = new UnackedPacket(retransmittable_frames);
+ for (size_t i = 0; i < retransmittable_frames.size(); ++i) {
+ if (retransmittable_frames[i].type == STREAM_FRAME) {
+ DCHECK(unacked->data.empty());
+ // Make an owned copy of the StringPiece.
+ unacked->data =
+ retransmittable_frames[i].stream_frame->data.as_string();
+ // Ensure the frame's StringPiece points to the owned copy of the data.
+ retransmittable_frames[i].stream_frame->data =
+ StringPiece(unacked->data);
+ }
+ }
+ unacked_packets_.insert(make_pair(pair.first, unacked));
+ // All unacked packets might be retransmitted.
+ retransmission_map_.insert(make_pair(pair.first,
+ RetransmissionInfo(pair.first)));
+ }
+ SendOrQueuePacket(pair.first, pair.second, !kForce);
+}
+
+bool QuicConnection::SendOrQueuePacket(QuicPacketSequenceNumber sequence_number,
+ QuicPacket* packet,
+ bool force) {
+ if (!WritePacket(sequence_number, packet, force)) {
+ queued_packets_.push_back(QueuedPacket(sequence_number, packet));
+ return false;
+ }
+ return true;
+}
+
bool QuicConnection::ShouldSimulateLostPacket() {
// TODO(rch): enable this
return false;
@@ -805,8 +882,8 @@ void QuicConnection::SendAck() {
should_send_congestion_feedback_ = true;
}
// Try to write immediately if possible.
- if (CanWrite(false)) {
- WriteData();
+ if (CanWrite(!kIsRetransmission)) {
+ WriteQueuedData(kFlush);
}
}
@@ -820,23 +897,22 @@ QuicTime QuicConnection::OnRetransmissionTimeout() {
// 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()) {
+ for (int i = 0; i < kMaxPacketsPerRetransmissionAlarm &&
+ !retransmission_timeouts_.empty(); ++i) {
+ RetransmissionInfo retransmission_info = retransmission_timeouts_.top();
+ DCHECK(retransmission_info.scheduled_time.IsInitialized());
+ if (retransmission_info.scheduled_time > clock_->Now()) {
break;
}
- if (!MaybeRetransmitPacketForRTO(retransmission_timeouts_.front().first)) {
+ retransmission_timeouts_.pop();
+ if (!MaybeRetransmitPacketForRTO(retransmission_info.sequence_number)) {
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;
+ << "adding an extra delay for "
+ << retransmission_info.sequence_number;
+ retransmission_info.scheduled_time = clock_->Now().Add(
+ congestion_manager_.DefaultRetransmissionTime());
+ retransmission_timeouts_.push(retransmission_info);
}
- retransmission_timeouts_.pop_front();
}
handling_retransmission_timeout_ = false;
@@ -847,7 +923,7 @@ QuicTime QuicConnection::OnRetransmissionTimeout() {
// We have packets remaining. Return the absolute RTO of the oldest packet
// on the list.
- return retransmission_timeouts_.front().second;
+ return retransmission_timeouts_.top().scheduled_time;
}
void QuicConnection::MaybeProcessRevivedPacket() {
@@ -896,9 +972,9 @@ void QuicConnection::SendConnectionCloseWithDetails(QuicErrorCode error,
frame.ack_frame = outgoing_ack_;
PacketPair packetpair = packet_creator_.CloseConnection(&frame);
- // There's no point in retransmitting this: we're closing the connection.
- SendPacket(packetpair.first, packetpair.second, !kShouldRetransmit, kForce,
- !kIsRetransmission);
+ // There's no point in retransmitting/queueing this: we're closing the
+ // connection.
+ WritePacket(packetpair.first, packetpair.second, kForce);
CloseConnection(error, false);
}
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index b436f9c..b28727e 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -17,6 +17,7 @@
#define NET_QUIC_QUIC_CONNECTION_H_
#include <list>
+#include <queue>
#include <set>
#include <vector>
@@ -148,7 +149,6 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface,
base::StringPiece data,
QuicStreamOffset offset,
bool fin);
-
// Send a stream reset frame to the peer.
virtual void SendRstStream(QuicStreamId id,
QuicErrorCode error,
@@ -175,8 +175,7 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface,
// From QuicFramerVisitorInterface
virtual void OnError(QuicFramer* framer) OVERRIDE;
- virtual void OnPacket(const IPEndPoint& self_address,
- const IPEndPoint& peer_address) OVERRIDE;
+ virtual void OnPacket() OVERRIDE;
virtual void OnPublicResetPacket(
const QuicPublicResetPacket& packet) OVERRIDE;
virtual void OnRevivedPacket() OVERRIDE;
@@ -212,7 +211,7 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface,
// 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);
+ void RetransmitPacket(QuicPacketSequenceNumber sequence_number);
QuicPacketCreator::Options* options() { return packet_creator_.options(); }
@@ -242,18 +241,31 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface,
QuicTime OnRetransmissionTimeout();
protected:
- // 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.
+ // Serializes then sends or queues the packet currently open.
+ void SendOrQueueCurrentPacket();
+
+ // Send a packet to the peer. If |sequence_number| is present in the
+ // |retransmission_map_|, then contents of this packet will be retransmitted
+ // with a new sequence number if it's not acked by the peer. Deletes
+ // |packet| via WritePacket call or transfers ownership to QueuedPacket,
+ // ultimately deleted via WritePacket. If |force| is true, then the packet
+ // will be sent immediately and the send scheduler will not be consulted.
// TODO(wtc): none of the callers check the return value.
- virtual bool SendPacket(QuicPacketSequenceNumber number,
- QuicPacket* packet,
- bool should_retransmit,
- bool force,
- bool is_retransmission);
+ virtual bool SendOrQueuePacket(QuicPacketSequenceNumber sequence_number,
+ QuicPacket* packet,
+ bool force);
+
+ // Writes the given packet to socket with the help of helper. Returns true on
+ // successful write, false otherwise. However, behavior is undefined if
+ // connection is not established or broken. In any circumstances, a return
+ // value of true implies that |packet| has been deleted and should not be
+ // accessed. If |sequence_number| is present in |retransmission_map_| it also
+ // sets up retransmission of the given packet in case of successful write. If
+ // |force| is true, then the packet will be sent immediately and the send
+ // scheduler will not be consulted.
+ bool WritePacket(QuicPacketSequenceNumber sequence_number,
+ QuicPacket* packet,
+ bool force);
// Make sure an ack we got from our peer is sane.
bool ValidateAckFrame(const QuicAckFrame& incoming_ack);
@@ -280,22 +292,18 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface,
private:
friend class test::QuicConnectionPeer;
+
// Packets which have not been written to the wire.
+ // Owns the QuicPacket* packet.
struct QueuedPacket {
QueuedPacket(QuicPacketSequenceNumber sequence_number,
- QuicPacket* packet,
- bool should_retransmit,
- bool is_retransmission)
+ QuicPacket* packet)
: sequence_number(sequence_number),
- packet(packet),
- should_retransmit(should_retransmit),
- is_retransmission(is_retransmission) {
+ packet(packet) {
}
QuicPacketSequenceNumber sequence_number;
QuicPacket* packet;
- bool should_retransmit;
- bool is_retransmission;
};
struct UnackedPacket {
@@ -304,32 +312,58 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface,
~UnackedPacket();
QuicFrames frames;
- uint8 number_nacks;
// Data referenced by the StringPiece of a QuicStreamFrame.
std::string data;
};
+ struct RetransmissionInfo {
+ explicit RetransmissionInfo(QuicPacketSequenceNumber sequence_number)
+ : sequence_number(sequence_number),
+ scheduled_time(QuicTime::Zero()),
+ number_nacks(0),
+ number_retransmissions(0) {
+ }
+
+ QuicPacketSequenceNumber sequence_number;
+ QuicTime scheduled_time;
+ size_t number_nacks;
+ size_t number_retransmissions;
+ };
+
+ class RetransmissionInfoComparator {
+ public:
+ bool operator()(const RetransmissionInfo& lhs,
+ const RetransmissionInfo& rhs) const {
+ DCHECK(lhs.scheduled_time.IsInitialized() &&
+ rhs.scheduled_time.IsInitialized());
+ return lhs.scheduled_time > rhs.scheduled_time;
+ }
+ };
+
typedef std::list<QueuedPacket> QueuedPacketList;
typedef base::hash_map<QuicPacketSequenceNumber,
UnackedPacket*> UnackedPacketMap;
typedef std::map<QuicFecGroupNumber, QuicFecGroup*> FecGroupMap;
- typedef std::list<std::pair<QuicPacketSequenceNumber, QuicTime> >
+ typedef base::hash_map<QuicPacketSequenceNumber,
+ RetransmissionInfo> RetransmissionMap;
+ typedef std::priority_queue<RetransmissionInfo,
+ std::vector<RetransmissionInfo>,
+ RetransmissionInfoComparator>
RetransmissionTimeouts;
- // The amount of time we wait before retransmitting a packet.
- static const QuicTime::Delta DefaultRetransmissionTime() {
- return QuicTime::Delta::FromMilliseconds(500);
- }
-
static void DeleteEnclosedFrames(UnackedPacket* unacked);
- static bool ShouldRetransmit(const QuicFrame& frame);
// Checks if a packet can be written now, and sets the timer if necessary.
bool CanWrite(bool is_retransmission);
+ void MaybeSetupRetransmission(QuicPacketSequenceNumber sequence_number);
+ bool IsRetransmission(QuicPacketSequenceNumber sequence_number);
+
// Writes as much queued data as possible. The connection must not be
- // blocked when this is called.
- bool WriteData();
+ // blocked when this is called. Will leave queued frames in the PacketCreator
+ // if the queued data was not enough to fill a packet and |force_send| is
+ // false.
+ bool WriteQueuedData(bool flush);
// If a packet can be revived from the current FEC group, then
// revive and process the packet.
@@ -340,9 +374,6 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface,
// Get the FEC group associate with the last processed packet.
QuicFecGroup* GetFecGroup();
- // Fills the ack frame with the appropriate latched information.
- void FillAckFrame(QuicAckFrame* ack);
-
// Closes any FEC groups protecting packets before |sequence_number|.
void CloseFecGroupsBefore(QuicPacketSequenceNumber sequence_number);
@@ -352,8 +383,14 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface,
QuicRandom* random_generator_;
const QuicGuid guid_;
+ // Address on the last successfully processed packet received from the
+ // client.
IPEndPoint self_address_;
IPEndPoint peer_address_;
+ // Address on the last(currently being processed) packet received. Not
+ // verified/authenticated.
+ IPEndPoint last_self_address_;
+ IPEndPoint last_peer_address_;
bool last_packet_revived_; // True if the last packet was revived from FEC.
size_t last_size_; // Size of the last received packet.
@@ -374,13 +411,17 @@ class NET_EXPORT_PRIVATE QuicConnection : public QuicFramerVisitorInterface,
// 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.
+ // Heap of packets that we might need to retransmit, and the time at
+ // which we should retransmit them. Every time a packet is sent it is added
+ // to this heap which is O(log(number of pending packets to be retransmitted))
+ // which might be costly. This should be optimized to O(1) by maintaining a
+ // priority queue of lists of packets to be retransmitted, where list x
+ // contains all packets that have been retransmitted x times.
RetransmissionTimeouts retransmission_timeouts_;
+ // Map from sequence number to the retransmission info.
+ RetransmissionMap retransmission_map_;
+
// True while OnRetransmissionTimeout is running to prevent
// SetRetransmissionAlarm from being called erroneously.
bool handling_retransmission_timeout_;
diff --git a/net/quic/quic_connection_helper.cc b/net/quic/quic_connection_helper.cc
index 18fd69d..3af51ac 100644
--- a/net/quic/quic_connection_helper.cc
+++ b/net/quic/quic_connection_helper.cc
@@ -9,8 +9,6 @@
#include "base/task_runner.h"
#include "base/time.h"
#include "net/base/io_buffer.h"
-#include "net/quic/congestion_control/quic_receipt_metrics_collector.h"
-#include "net/quic/congestion_control/quic_send_scheduler.h"
#include "net/quic/quic_utils.h"
namespace net {
diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc
index 7bd6ff8..f64f867 100644
--- a/net/quic/quic_connection_helper_test.cc
+++ b/net/quic/quic_connection_helper_test.cc
@@ -34,8 +34,8 @@ class TestConnection : public QuicConnection {
QuicConnectionPeer::SendAck(this);
}
- void SetScheduler(QuicSendScheduler* scheduler) {
- QuicConnectionPeer::SetScheduler(this, scheduler);
+ void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) {
+ QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm);
}
};
@@ -99,12 +99,12 @@ class QuicConnectionHelperTest : public ::testing::Test {
runner_ = new TestTaskRunner(&clock_);
helper_.reset(new QuicConnectionHelper(runner_.get(), &clock_,
&random_generator_, socket));
- scheduler_ = new testing::StrictMock<MockScheduler>();
- EXPECT_CALL(*scheduler_, TimeUntilSend(_)).
+ send_algorithm_ = new testing::StrictMock<MockSendAlgorithm>();
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_)).
WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
connection_.reset(new TestConnection(guid_, IPEndPoint(), helper_.get()));
connection_->set_visitor(&visitor_);
- connection_->SetScheduler(scheduler_);
+ connection_->SetSendAlgorithm(send_algorithm_);
}
// Returns a newly created packet to send kData on stream 1.
@@ -125,7 +125,7 @@ class QuicConnectionHelperTest : public ::testing::Test {
QuicCongestionFeedbackFrame feedback;
feedback.type = kTCP;
feedback.tcp.accumulated_number_of_lost_packets = 0;
- feedback.tcp.receive_window = 16000;
+ feedback.tcp.receive_window = 16000 << 4;
QuicFrames frames;
frames.push_back(QuicFrame(&ack));
@@ -150,7 +150,7 @@ class QuicConnectionHelperTest : public ::testing::Test {
return ConstructPacket(header_, QuicFrame(&close));
}
- testing::StrictMock<MockScheduler>* scheduler_;
+ testing::StrictMock<MockSendAlgorithm>* send_algorithm_;
scoped_refptr<TestTaskRunner> runner_;
scoped_ptr<QuicConnectionHelper> helper_;
scoped_array<MockWrite> mock_writes_;
@@ -225,7 +225,7 @@ TEST_F(QuicConnectionHelperTest, SetAckAlarm) {
EXPECT_EQ(base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()),
runner_->GetPostedTasks()[1].delay);
- EXPECT_CALL(*scheduler_, SentPacket(1, _, false));
+ EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false));
runner_->RunNextTask();
EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now());
}
@@ -269,7 +269,7 @@ TEST_F(QuicConnectionHelperTest, ResetAckAlarm) {
// Verify that the ack alarm task has been re-posted.
ASSERT_EQ(2u, runner_->GetPostedTasks().size());
- EXPECT_CALL(*scheduler_, SentPacket(1, _, false));
+ EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false));
runner_->RunNextTask();
EXPECT_EQ(QuicTime::Zero().Add(delta2), clock_.Now());
}
@@ -283,10 +283,10 @@ TEST_F(QuicConnectionHelperTest, TestRetransmission) {
QuicTime::Delta::FromMilliseconds(500);
QuicTime start = clock_.Now();
- EXPECT_CALL(*scheduler_, SentPacket(1, _, false));
+ EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false));
// Send a packet.
connection_->SendStreamData(1, kData, 0, false);
- EXPECT_CALL(*scheduler_, SentPacket(2, _, true));
+ EXPECT_CALL(*send_algorithm_, SentPacket(2, _, true));
// Since no ack was received, the retransmission alarm will fire and
// retransmit it.
runner_->RunNextTask();
@@ -304,7 +304,7 @@ TEST_F(QuicConnectionHelperTest, InitialTimeout) {
EXPECT_EQ(base::TimeDelta::FromMicroseconds(kDefaultTimeoutUs),
runner_->GetPostedTasks().front().delay);
- EXPECT_CALL(*scheduler_, SentPacket(1, _, false));
+ EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false));
// After we run the next task, we should close the connection.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
@@ -348,7 +348,7 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) {
// When we send a packet, the timeout will change to 5000 + kDefaultTimeout.
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(5000));
EXPECT_EQ(5000u, clock_.Now().ToMicroseconds());
- EXPECT_CALL(*scheduler_, SentPacket(1, _, false));
+ EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false));
// Send an ack so we don't set the retransmission alarm.
connection_->SendAck();
@@ -362,7 +362,7 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) {
// This time, we should time out.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
- EXPECT_CALL(*scheduler_, SentPacket(2, _, false));
+ EXPECT_CALL(*send_algorithm_, SentPacket(2, _, false));
runner_->RunNextTask();
EXPECT_EQ(kDefaultTimeoutUs + 5000, clock_.Now().ToMicroseconds());
EXPECT_FALSE(connection_->connected());
@@ -374,16 +374,16 @@ TEST_F(QuicConnectionHelperTest, SendSchedulerDelayThenSend) {
Initialize();
// Test that if we send a packet with a delay, it ends up queued.
- EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(1)));
connection_->SendStreamData(1, kData, 0, false);
- EXPECT_CALL(*scheduler_, SentPacket(1, _, false));
+ EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false));
EXPECT_EQ(1u, connection_->NumQueuedPackets());
// Advance the clock to fire the alarm, and configure the scheduler
// to permit the packet to be sent.
- EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
QuicTime::Delta::Zero()));
EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(testing::Return(true));
runner_->RunNextTask();
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 2a91326..1dbde23 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -5,8 +5,8 @@
#include "net/quic/quic_connection.h"
#include "net/base/net_errors.h"
-#include "net/quic/congestion_control/quic_receipt_metrics_collector.h"
-#include "net/quic/congestion_control/quic_send_scheduler.h"
+#include "net/quic/congestion_control/receive_algorithm_interface.h"
+#include "net/quic/congestion_control/send_algorithm_interface.h"
#include "net/quic/crypto/null_encrypter.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
@@ -23,8 +23,10 @@ using testing::_;
using testing::AnyNumber;
using testing::Between;
using testing::ContainerEq;
+using testing::InSequence;
using testing::Return;
using testing::StrictMock;
+using testing::SaveArg;
namespace net {
namespace test {
@@ -33,11 +35,10 @@ namespace {
const char data1[] = "foo";
const char data2[] = "bar";
-class TestCollector : public QuicReceiptMetricsCollector {
+class TestReceiveAlgorithm : public ReceiveAlgorithmInterface {
public:
- explicit TestCollector(QuicCongestionFeedbackFrame* feedback)
- : QuicReceiptMetricsCollector(&clock_, kFixRate),
- feedback_(feedback) {
+ explicit TestReceiveAlgorithm(QuicCongestionFeedbackFrame* feedback)
+ : feedback_(feedback) {
}
bool GenerateCongestionFeedback(
@@ -50,13 +51,12 @@ class TestCollector : public QuicReceiptMetricsCollector {
}
MOCK_METHOD4(RecordIncomingPacket,
- void(size_t, QuicPacketSequenceNumber, QuicTime, bool));
+ void(QuicByteCount, QuicPacketSequenceNumber, QuicTime, bool));
private:
- MockClock clock_;
QuicCongestionFeedbackFrame* feedback_;
- DISALLOW_COPY_AND_ASSIGN(TestCollector);
+ DISALLOW_COPY_AND_ASSIGN(TestReceiveAlgorithm);
};
class TestConnectionHelper : public QuicConnectionHelperInterface {
@@ -87,7 +87,7 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
QuicEncrypter::Create(kNULL));
FramerVisitorCapturingAcks visitor;
framer.set_visitor(&visitor);
- EXPECT_TRUE(framer.ProcessPacket(IPEndPoint(), IPEndPoint(), packet));
+ EXPECT_TRUE(framer.ProcessPacket(packet));
header_ = *visitor.header();
if (visitor.ack()) {
ack_.reset(new QuicAckFrame(*visitor.ack()));
@@ -166,22 +166,15 @@ class TestConnection : public QuicConnection {
QuicConnectionPeer::SendAck(this);
}
- void SetCollector(QuicReceiptMetricsCollector* collector) {
- QuicConnectionPeer::SetCollector(this, collector);
+ void SetReceiveAlgorithm(TestReceiveAlgorithm* receive_algorithm) {
+ QuicConnectionPeer::SetReceiveAlgorithm(this, receive_algorithm);
}
- void SetScheduler(QuicSendScheduler* scheduler) {
- QuicConnectionPeer::SetScheduler(this, scheduler);
+ void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) {
+ QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm);
}
- bool SendPacket(QuicPacketSequenceNumber sequence_number,
- QuicPacket* packet,
- bool should_retransmit,
- bool force,
- bool is_retransmission) {
- return QuicConnection::SendPacket(
- sequence_number, packet, should_retransmit, force, is_retransmission);
- }
+ using QuicConnection::SendOrQueuePacket;
private:
DISALLOW_COPY_AND_ASSIGN(TestConnection);
@@ -193,21 +186,21 @@ class QuicConnectionTest : public ::testing::Test {
: guid_(42),
framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)),
creator_(guid_, &framer_),
- scheduler_(new StrictMock<MockScheduler>),
+ send_algorithm_(new StrictMock<MockSendAlgorithm>),
helper_(new TestConnectionHelper(&clock_, &random_generator_)),
connection_(guid_, IPEndPoint(), helper_.get()),
frame1_(1, false, 0, data1),
frame2_(1, false, 3, data2),
accept_packet_(true) {
connection_.set_visitor(&visitor_);
- connection_.SetScheduler(scheduler_);
+ connection_.SetSendAlgorithm(send_algorithm_);
// Simplify tests by not sending feedback unless specifically configured.
SetFeedback(NULL);
- EXPECT_CALL(*scheduler_, TimeUntilSend(_)).WillRepeatedly(Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_)).WillRepeatedly(Return(
QuicTime::Delta::Zero()));
- EXPECT_CALL(*collector_,
+ EXPECT_CALL(*receive_algorithm_,
RecordIncomingPacket(_, _, _, _)).Times(AnyNumber());
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(AnyNumber());
}
QuicAckFrame* outgoing_ack() {
@@ -299,30 +292,25 @@ class QuicConnectionTest : public ::testing::Test {
void SendStreamDataToPeer(QuicStreamId id, StringPiece data,
QuicStreamOffset offset, bool fin,
QuicPacketSequenceNumber* last_packet) {
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _));
connection_.SendStreamData(id, data, offset, fin);
if (last_packet != NULL) {
*last_packet =
QuicConnectionPeer::GetPacketCreator(&connection_)->sequence_number();
}
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(AnyNumber());
}
void SendAckPacketToPeer() {
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(1);
connection_.SendAck();
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(AnyNumber());
}
- void ProcessAckPacket(QuicAckFrame* frame, bool expect_success = true) {
- if (expect_success) {
- EXPECT_CALL(*scheduler_, OnIncomingAckFrame(_));
- }
+ void ProcessAckPacket(QuicAckFrame* frame) {
QuicFrames frames;
frames.push_back(QuicFrame(frame));
- size_t num_serialized;
-
- PacketPair pair = creator_.SerializeFrames(frames, &num_serialized);
+ PacketPair pair = creator_.SerializeAllFrames(frames);
scoped_ptr<QuicPacket> packet(pair.second);
scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*packet));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
@@ -368,16 +356,16 @@ class QuicConnectionTest : public ::testing::Test {
}
void SetFeedback(QuicCongestionFeedbackFrame* feedback) {
- collector_ = new TestCollector(feedback);
- connection_.SetCollector(collector_);
+ receive_algorithm_ = new TestReceiveAlgorithm(feedback);
+ connection_.SetReceiveAlgorithm(receive_algorithm_);
}
QuicGuid guid_;
QuicFramer framer_;
QuicPacketCreator creator_;
- MockScheduler* scheduler_;
- TestCollector* collector_;
+ MockSendAlgorithm* send_algorithm_;
+ TestReceiveAlgorithm* receive_algorithm_;
MockClock clock_;
MockRandom random_generator_;
scoped_ptr<TestConnectionHelper> helper_;
@@ -489,19 +477,20 @@ TEST_F(QuicConnectionTest, RejectPacketTooFarOut) {
TEST_F(QuicConnectionTest, TruncatedAck) {
EXPECT_CALL(visitor_, OnAck(_)).Times(testing::AnyNumber());
+ EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(2);
for (int i = 0; i < 200; ++i) {
SendStreamDataToPeer(1, "foo", i * 3, false, NULL);
}
QuicAckFrame frame(0, 1);
frame.received_info.RecordReceived(193);
- ProcessAckPacket(&frame, true);
+ ProcessAckPacket(&frame);
EXPECT_TRUE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_));
frame.received_info.missing_packets.erase(192);
- ProcessAckPacket(&frame, true);
+ ProcessAckPacket(&frame);
EXPECT_FALSE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_));
}
@@ -520,20 +509,21 @@ TEST_F(QuicConnectionTest, LeastUnackedLower) {
creator_.set_sequence_number(1);
QuicAckFrame frame2(0, 1);
// The scheduler will not process out of order acks.
- ProcessAckPacket(&frame2, false);
+ ProcessAckPacket(&frame2);
// Now claim it's one, but set the ordering so it was sent "after" the first
// one. This should cause a connection error.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _));
creator_.set_sequence_number(7);
- ProcessAckPacket(&frame2, false);
+ ProcessAckPacket(&frame2);
}
TEST_F(QuicConnectionTest, LargestObservedLower) {
SendStreamDataToPeer(1, "foo", 0, false, NULL);
SendStreamDataToPeer(1, "bar", 3, false, NULL);
SendStreamDataToPeer(1, "eep", 6, false, NULL);
+ EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(2);
// Start out saying the largest observed is 2.
QuicAckFrame frame(2, 0);
@@ -543,16 +533,16 @@ TEST_F(QuicConnectionTest, LargestObservedLower) {
// Now change it to 1, and it should cause a connection error.
QuicAckFrame frame2(1, 0);
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
- ProcessAckPacket(&frame2, false);
+ ProcessAckPacket(&frame2);
}
TEST_F(QuicConnectionTest, LeastUnackedGreaterThanPacketSequenceNumber) {
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _));
// Create an ack with least_unacked is 2 in packet number 1.
creator_.set_sequence_number(0);
QuicAckFrame frame(0, 2);
- ProcessAckPacket(&frame, false);
+ ProcessAckPacket(&frame);
}
TEST_F(QuicConnectionTest,
@@ -562,18 +552,18 @@ TEST_F(QuicConnectionTest,
SendStreamDataToPeer(1, "eep", 6, false, NULL);
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _));
QuicAckFrame frame(0, 1);
frame.received_info.missing_packets.insert(3);
- ProcessAckPacket(&frame, false);
+ ProcessAckPacket(&frame);
}
TEST_F(QuicConnectionTest, AckUnsentData) {
// Ack a packet which has not been sent.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_ACK_DATA, false));
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _));
QuicAckFrame frame(1, 0);
- ProcessAckPacket(&frame, false);
+ ProcessAckPacket(&frame);
}
TEST_F(QuicConnectionTest, AckAll) {
@@ -585,6 +575,7 @@ TEST_F(QuicConnectionTest, AckAll) {
}
TEST_F(QuicConnectionTest, BasicSending) {
+ EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(6);
QuicPacketSequenceNumber last_packet;
SendStreamDataToPeer(1, "foo", 0, false, &last_packet); // Packet 1
EXPECT_EQ(1u, last_packet);
@@ -635,7 +626,39 @@ TEST_F(QuicConnectionTest, BasicSending) {
EXPECT_EQ(9u, last_ack()->sent_info.least_unacked);
}
+TEST_F(QuicConnectionTest, FECSending) {
+ // Limit to one byte per packet.
+ size_t ciphertext_size = NullEncrypter().GetCiphertextSize(1);
+ connection_.options()->max_packet_length =
+ ciphertext_size + QuicUtils::StreamFramePacketOverhead(1);
+ // And send FEC every two packets.
+ connection_.options()->max_packets_per_fec_group = 2;
+
+ // Send 4 data packets and 2 FEC packets.
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(6);
+ connection_.SendStreamData(1, "food", 0, false);
+ // Expect the FEC group to be closed after SendStreamData.
+ EXPECT_FALSE(creator_.ShouldSendFec(true));
+}
+
+TEST_F(QuicConnectionTest, FECQueueing) {
+ // Limit to one byte per packet.
+ size_t ciphertext_size = NullEncrypter().GetCiphertextSize(1);
+ connection_.options()->max_packet_length =
+ ciphertext_size + QuicUtils::StreamFramePacketOverhead(1);
+ // And send FEC every two packets.
+ connection_.options()->max_packets_per_fec_group = 2;
+
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ helper_->set_blocked(true);
+ connection_.SendStreamData(1, "food", 0, false);
+ EXPECT_FALSE(creator_.ShouldSendFec(true));
+ // Expect the first data packet and the fec packet to be queued.
+ EXPECT_EQ(2u, connection_.NumQueuedPackets());
+}
+
TEST_F(QuicConnectionTest, RetransmitOnNack) {
+ EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(2);
QuicPacketSequenceNumber last_packet;
SendStreamDataToPeer(1, "foo", 0, false, &last_packet); // Packet 1
SendStreamDataToPeer(1, "foos", 3, false, &last_packet); // Packet 2
@@ -664,11 +687,29 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) {
ProcessAckPacket(&nack_two);
// The third nack should trigger a retransimission.
- EXPECT_CALL(*scheduler_, SentPacket(_, 37, true)).Times(1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, 37, true)).Times(1);
ProcessAckPacket(&nack_two);
}
+TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) {
+ QuicPacketSequenceNumber largest_observed;
+ QuicByteCount packet_size;
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, false)).WillOnce(DoAll(
+ SaveArg<0>(&largest_observed), SaveArg<1>(&packet_size)));
+ connection_.SendStreamData(1, "foo", 0, false);
+ QuicAckFrame frame(1, largest_observed);
+ frame.received_info.missing_packets.insert(largest_observed);
+ ProcessAckPacket(&frame);
+ // Second udp packet will force an ack frame.
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, false));
+ ProcessAckPacket(&frame);
+ // Third nack should retransmit the largest observed packet.
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, packet_size, true));
+ ProcessAckPacket(&frame);
+}
+
TEST_F(QuicConnectionTest, LimitPacketsPerNack) {
+ EXPECT_CALL(*send_algorithm_, OnIncomingAck(12, _, _)).Times(1);
int offset = 0;
// Send packets 1 to 12
for (int i = 0; i < 12; ++i) {
@@ -689,19 +730,20 @@ TEST_F(QuicConnectionTest, LimitPacketsPerNack) {
// Nack three times.
ProcessAckPacket(&nack);
// The second call will trigger an ack.
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(1);
ProcessAckPacket(&nack);
// The third call should trigger retransmitting 10 packets.
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(10);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(10);
ProcessAckPacket(&nack);
// The fourth call should trigger retransmitting the 11th packet and an ack.
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(2);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(2);
ProcessAckPacket(&nack);
}
// Test sending multiple acks from the connection to the session.
TEST_F(QuicConnectionTest, MultipleAcks) {
+ EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(6);
QuicPacketSequenceNumber last_packet;
SendStreamDataToPeer(1u, "foo", 0, false, &last_packet); // Packet 1
EXPECT_EQ(1u, last_packet);
@@ -741,6 +783,7 @@ TEST_F(QuicConnectionTest, MultipleAcks) {
}
TEST_F(QuicConnectionTest, DontLatchUnackedPacket) {
+ EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1);
SendStreamDataToPeer(1, "foo", 0, false, NULL); // Packet 1;
SendAckPacketToPeer(); // Packet 2
@@ -814,14 +857,89 @@ TEST_F(QuicConnectionTest, TestRetransmit) {
EXPECT_EQ(default_retransmission_time, helper_->retransmission_alarm());
// Simulate the retransimission alarm firing
clock_.AdvanceTime(kDefaultRetransmissionTime);
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
- connection_.MaybeRetransmitPacket(1);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _));
+ connection_.RetransmitPacket(1);
EXPECT_EQ(2u, last_header()->packet_sequence_number);
EXPECT_EQ(2u, outgoing_ack->sent_info.least_unacked);
}
-// TODO(rch): Enable after we get non-blocking sockets.
-TEST_F(QuicConnectionTest, DISABLED_TestQueued) {
+TEST_F(QuicConnectionTest, TestRetransmitOrder) {
+ QuicByteCount first_packet_size;
+ EXPECT_CALL(*send_algorithm_, SentPacket(_,_,_)).WillOnce(
+ SaveArg<1>(&first_packet_size));
+ connection_.SendStreamData(1, "first_packet", 0, false);
+ QuicByteCount second_packet_size;
+ EXPECT_CALL(*send_algorithm_, SentPacket(_,_,_)).WillOnce(
+ SaveArg<1>(&second_packet_size));
+ connection_.SendStreamData(1, "second_packet", 12, false);
+ EXPECT_NE(first_packet_size, second_packet_size);
+ // Advance the clock by huge time to make sure packets will be retransmitted.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
+ {
+ InSequence s;
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, first_packet_size, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, second_packet_size, _));
+ }
+ connection_.OnRetransmissionTimeout();
+}
+
+TEST_F(QuicConnectionTest, TestRetransmissionCountCalculation) {
+ QuicPacketSequenceNumber original_sequence_number;
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, false)).WillOnce(
+ SaveArg<0>(&original_sequence_number));
+ connection_.SendStreamData(1, "foo", 0, false);
+ EXPECT_TRUE(QuicConnectionPeer::IsSavedForRetransmission(
+ &connection_, original_sequence_number));
+ EXPECT_EQ(0u, QuicConnectionPeer::GetRetransmissionCount(
+ &connection_, original_sequence_number));
+ // Force retransmission due to RTO.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
+ QuicPacketSequenceNumber rto_sequence_number;
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, true)).WillOnce(
+ SaveArg<0>(&rto_sequence_number));
+ connection_.OnRetransmissionTimeout();
+ EXPECT_FALSE(QuicConnectionPeer::IsSavedForRetransmission(
+ &connection_, original_sequence_number));
+ EXPECT_TRUE(QuicConnectionPeer::IsSavedForRetransmission(
+ &connection_, rto_sequence_number));
+ EXPECT_EQ(1u, QuicConnectionPeer::GetRetransmissionCount(
+ &connection_, rto_sequence_number));
+ // Once by explicit nack.
+ QuicPacketSequenceNumber nack_sequence_number;
+ // Ack packets might generate some other packets, which are not
+ // retransmissions. (More ack packets).
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, false)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, true)).WillOnce(
+ SaveArg<0>(&nack_sequence_number));
+ QuicAckFrame ack(rto_sequence_number, 0);
+ // Ack the retransmitted packet.
+ EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1);
+ ack.received_info.missing_packets.insert(rto_sequence_number);
+ for (int i = 0; i < 3; i++) {
+ ProcessAckPacket(&ack);
+ }
+ EXPECT_FALSE(QuicConnectionPeer::IsSavedForRetransmission(
+ &connection_, rto_sequence_number));
+ EXPECT_TRUE(QuicConnectionPeer::IsSavedForRetransmission(
+ &connection_, nack_sequence_number));
+ EXPECT_EQ(2u, QuicConnectionPeer::GetRetransmissionCount(
+ &connection_, nack_sequence_number));
+}
+
+TEST_F(QuicConnectionTest, SetRTOAfterWritingToSocket) {
+ helper_->set_blocked(true);
+ connection_.SendStreamData(1, "foo", 0, false);
+ // Make sure that RTO is not started when the packet is queued.
+ EXPECT_EQ(0u, QuicConnectionPeer::GetNumRetransmissionTimeouts(&connection_));
+
+ // Test that RTO is started once we write to the socket.
+ helper_->set_blocked(false);
+ EXPECT_CALL(visitor_, OnCanWrite());
+ connection_.OnCanWrite();
+ EXPECT_EQ(1u, QuicConnectionPeer::GetNumRetransmissionTimeouts(&connection_));
+}
+
+TEST_F(QuicConnectionTest, TestQueued) {
EXPECT_EQ(0u, connection_.NumQueuedPackets());
helper_->set_blocked(true);
connection_.SendStreamData(1, "foo", 0, false);
@@ -861,33 +979,32 @@ TEST_F(QuicConnectionTest, NoQuicCongestionFeedbackFrame) {
TEST_F(QuicConnectionTest, WithQuicCongestionFeedbackFrame) {
QuicCongestionFeedbackFrame info;
info.type = kFixRate;
- info.fix_rate.bitrate_in_bytes_per_second = 123;
+ info.fix_rate.bitrate = QuicBandwidth::FromBytesPerSecond(123);
SetFeedback(&info);
SendAckPacketToPeer();
EXPECT_EQ(kFixRate, last_feedback()->type);
- EXPECT_EQ(info.fix_rate.bitrate_in_bytes_per_second,
- last_feedback()->fix_rate.bitrate_in_bytes_per_second);
+ EXPECT_EQ(info.fix_rate.bitrate, last_feedback()->fix_rate.bitrate);
}
TEST_F(QuicConnectionTest, UpdateQuicCongestionFeedbackFrame) {
SendAckPacketToPeer();
- EXPECT_CALL(*collector_, RecordIncomingPacket(_, _, _, _));
+ EXPECT_CALL(*receive_algorithm_, RecordIncomingPacket(_, _, _, _));
ProcessPacket(1);
}
TEST_F(QuicConnectionTest, DontUpdateQuicCongestionFeedbackFrameForRevived) {
SendAckPacketToPeer();
// Process an FEC packet, and revive the missing data packet
- // but only contact the collector once.
- EXPECT_CALL(*collector_, RecordIncomingPacket(_, _, _, _));
+ // but only contact the receive_algorithm once.
+ EXPECT_CALL(*receive_algorithm_, RecordIncomingPacket(_, _, _, _));
ProcessFecPacket(2, 1, true);
}
TEST_F(QuicConnectionTest, InitialTimeout) {
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _));
QuicTime default_timeout = clock_.Now().Add(
QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs));
@@ -924,7 +1041,7 @@ TEST_F(QuicConnectionTest, TimeoutAfterSend) {
// This time, we should time out.
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _));
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)),
clock_.Now());
@@ -936,77 +1053,83 @@ TEST_F(QuicConnectionTest, TimeoutAfterSend) {
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(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
QuicTime::Delta::Zero()));
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
- connection_.SendPacket(1, packet, true, false, false);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _));
+ connection_.SendOrQueuePacket(1, packet, false);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerDelay) {
// Test that if we send a packet with a delay, it ends up queued.
QuicPacket* packet = ConstructDataPacket(1, 0);
- EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(1)));
- EXPECT_CALL(*scheduler_, SentPacket(1, _, _)).Times(0);
- connection_.SendPacket(1, packet, true, false, false);
+ EXPECT_CALL(*send_algorithm_, SentPacket(1, _, _)).Times(0);
+ connection_.SendOrQueuePacket(1, packet, false);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerForce) {
// Test that if we force send a packet, it is not queued.
QuicPacket* packet = ConstructDataPacket(1, 0);
- EXPECT_CALL(*scheduler_, TimeUntilSend(true)).Times(0);
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
- connection_.SendPacket(1, packet, true, true, false);
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(true)).Times(0);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _));
+ connection_.SendOrQueuePacket(1, packet, true);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
-// TODO(rch): Enable after we get non-blocking sockets.
-TEST_F(QuicConnectionTest, DISABLED_SendSchedulerEAGAIN) {
+TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) {
QuicPacket* packet = ConstructDataPacket(1, 0);
helper_->set_blocked(true);
- EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
QuicTime::Delta::Zero()));
- EXPECT_CALL(*scheduler_, SentPacket(1, _, _)).Times(0);
- connection_.SendPacket(1, packet, true, false, false);
+ EXPECT_CALL(*send_algorithm_, SentPacket(1, _, _)).Times(0);
+ connection_.SendOrQueuePacket(1, packet, false);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) {
// Test that if we send a packet with a delay, it ends up queued.
QuicPacket* packet = ConstructDataPacket(1, 0);
- EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(1)));
- connection_.SendPacket(1, packet, true, false, false);
+ connection_.SendOrQueuePacket(1, packet, 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(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
QuicTime::Delta::Zero()));
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1));
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _));
EXPECT_CALL(visitor_, OnCanWrite());
connection_.OnCanWrite();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
+ // Fake packet loss.
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
+ QuicTime::Delta::Zero()));
+ EXPECT_CALL(*send_algorithm_, SentPacket(1, _, false));
+ connection_.SendStreamData(1, "foo", 0, false);
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ // Advance the time for retransmission of lost packet.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(501));
// Test that if we send a retransmit with a delay, it ends up queued.
- QuicPacket* packet = ConstructDataPacket(1, 0);
- EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(1)));
- connection_.SendPacket(1, packet, true, false, true);
+ connection_.OnRetransmissionTimeout();
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Advance the clock to fire the alarm, and configure the scheduler
// to permit the packet to be sent.
- EXPECT_CALL(*scheduler_, TimeUntilSend(true)).WillOnce(testing::Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(true)).WillOnce(testing::Return(
QuicTime::Delta::Zero()));
// Ensure the scheduler is notified this is a retransmit.
- EXPECT_CALL(*scheduler_, SentPacket(1, _, true));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, true));
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(1));
EXPECT_CALL(visitor_, OnCanWrite());
connection_.OnCanWrite();
@@ -1015,30 +1138,31 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
TEST_F(QuicConnectionTest, SendSchedulerDelayAndQueue) {
QuicPacket* packet = ConstructDataPacket(1, 0);
- EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(1)));
- connection_.SendPacket(1, packet, true, false, false);
+ connection_.SendOrQueuePacket(1, packet, false);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Attempt to send another packet and make sure that it gets queued.
packet = ConstructDataPacket(2, 0);
- connection_.SendPacket(2, packet, true, false, false);
+ connection_.SendOrQueuePacket(2, packet, false);
EXPECT_EQ(2u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
QuicPacket* packet = ConstructDataPacket(1, 0);
- EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(10)));
- connection_.SendPacket(1, packet, true, false, false);
+ connection_.SendOrQueuePacket(1, packet, false);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Now send non-retransmitting information, that we're not going to
// retransmit 3. The far end should stop waiting for it.
QuicAckFrame frame(0, 1);
- EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillRepeatedly(testing::Return(
- QuicTime::Delta::Zero()));
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _));
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(false)).WillRepeatedly(
+ testing::Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _));
EXPECT_CALL(visitor_, OnCanWrite());
ProcessAckPacket(&frame);
@@ -1049,15 +1173,15 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
QuicPacket* packet = ConstructDataPacket(1, 0);
- EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(10)));
- connection_.SendPacket(1, packet, true, false, false);
+ connection_.SendOrQueuePacket(1, packet, false);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// Now send non-retransmitting information, that we're not going to
// retransmit 3. The far end should stop waiting for it.
QuicAckFrame frame(0, 1);
- EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(1)));
ProcessAckPacket(&frame);
@@ -1066,9 +1190,9 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
TEST_F(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) {
QuicPacket* packet = ConstructDataPacket(1, 0);
- EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(10)));
- connection_.SendPacket(1, packet, true, false, false);
+ connection_.SendOrQueuePacket(1, packet, false);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
// OnCanWrite should not send the packet (because of the delay)
@@ -1085,7 +1209,7 @@ TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
ciphertext_size + QuicUtils::StreamFramePacketOverhead(1);
// Queue the first packet.
- EXPECT_CALL(*scheduler_, TimeUntilSend(false)).WillOnce(testing::Return(
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(false)).WillOnce(testing::Return(
QuicTime::Delta::FromMicroseconds(10)));
EXPECT_EQ(1u, connection_.SendStreamData(
1, "EnoughDataToQueue", 0, false).bytes_consumed);
@@ -1099,16 +1223,16 @@ TEST_F(QuicConnectionTest, LoopThroughSendingPackets) {
ciphertext_size + QuicUtils::StreamFramePacketOverhead(1);
// Queue the first packet.
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(17);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(17);
EXPECT_EQ(17u, connection_.SendStreamData(
1, "EnoughDataToQueue", 0, false).bytes_consumed);
}
TEST_F(QuicConnectionTest, NoAckForClose) {
ProcessPacket(1);
- EXPECT_CALL(*scheduler_, OnIncomingAckFrame(_));
+ EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(0);
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CLIENT_GOING_AWAY, true));
- EXPECT_CALL(*scheduler_, SentPacket(_, _, _)).Times(0);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _)).Times(0);
ProcessClosePacket(2, 0);
}
@@ -1118,8 +1242,8 @@ TEST_F(QuicConnectionTest, SendWhenDisconnected) {
connection_.CloseConnection(QUIC_CLIENT_GOING_AWAY, false);
EXPECT_FALSE(connection_.connected());
QuicPacket* packet = ConstructDataPacket(1, 0);
- EXPECT_CALL(*scheduler_, SentPacket(1, _, _)).Times(0);
- connection_.SendPacket(1, packet, true, false, false);
+ EXPECT_CALL(*send_algorithm_, SentPacket(1, _, _)).Times(0);
+ connection_.SendOrQueuePacket(1, packet, false);
}
TEST_F(QuicConnectionTest, PublicReset) {
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 2ef645b..adbf139 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -84,8 +84,7 @@ void TestMockHelper::CheckClientHelloPacket(
QuicEncrypter::Create(kNULL));
TestQuicVisitor quic_visitor;
quic_framer.set_visitor(&quic_visitor);
- ASSERT_TRUE(quic_framer.ProcessPacket(IPEndPoint(), IPEndPoint(),
- packet));
+ ASSERT_TRUE(quic_framer.ProcessPacket(packet));
EXPECT_EQ(kCryptoStreamId, quic_visitor.frame()->stream_id);
EXPECT_FALSE(quic_visitor.frame()->fin);
EXPECT_EQ(0u, quic_visitor.frame()->offset);
diff --git a/net/quic/quic_data_writer.cc b/net/quic/quic_data_writer.cc
index 3bbad4e..f90670f 100644
--- a/net/quic/quic_data_writer.cc
+++ b/net/quic/quic_data_writer.cc
@@ -99,6 +99,10 @@ bool QuicDataWriter::WriteBytes(const void* data, size_t data_len) {
}
void QuicDataWriter::WritePadding() {
+ DCHECK_LE(length_, capacity_);
+ if (length_ > capacity_) {
+ return;
+ }
memset(buffer_ + length_, 0x00, capacity_ - length_);
length_ = capacity_;
}
diff --git a/net/quic/quic_fec_group.cc b/net/quic/quic_fec_group.cc
index 2a2695d..af976a3 100644
--- a/net/quic/quic_fec_group.cc
+++ b/net/quic/quic_fec_group.cc
@@ -26,10 +26,6 @@ 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) {
diff --git a/net/quic/quic_fec_group.h b/net/quic/quic_fec_group.h
index 67cba64..14fdec8 100644
--- a/net/quic/quic_fec_group.h
+++ b/net/quic/quic_fec_group.h
@@ -21,12 +21,6 @@ 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,
@@ -61,6 +55,14 @@ class NET_EXPORT_PRIVATE QuicFecGroup {
return base::StringPiece(parity_, parity_len_);
}
+ QuicPacketSequenceNumber min_protected_packet() const {
+ return min_protected_packet_;
+ }
+
+ size_t NumReceivedPackets() const {
+ return received_packets_.size();
+ }
+
private:
bool UpdateParity(base::StringPiece payload);
// Returns the number of missing packets, or size_t max if the number
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index c9392a6..a794701 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -15,6 +15,7 @@ using base::StringPiece;
using std::make_pair;
using std::map;
using std::numeric_limits;
+using std::string;
namespace net {
@@ -61,74 +62,53 @@ bool CanTruncate(const QuicFrame& frame) {
return false;
}
-QuicPacket* QuicFramer::ConstructFrameDataPacket(
- const QuicPacketHeader& header,
- const QuicFrames& frames) {
- size_t num_consumed = 0;
- QuicPacket* packet =
- ConstructMaxFrameDataPacket(header, frames, &num_consumed);
- DCHECK_EQ(frames.size(), num_consumed);
- return packet;
+size_t QuicFramer::GetSerializedFrameLength(
+ const QuicFrame& frame, size_t free_bytes, bool first_frame) {
+ if (frame.type == PADDING_FRAME) {
+ // PADDING implies end of packet.
+ return free_bytes;
+ }
+ size_t frame_len = kFrameTypeSize;
+ frame_len += ComputeFramePayloadLength(frame);
+ if (frame_len > free_bytes) {
+ // Only truncate the first frame in a packet, so if subsequent ones go
+ // over, stop including more frames.
+ if (!first_frame) {
+ return 0;
+ }
+ if (CanTruncate(frame)) {
+ // Truncate the frame so the packet will not exceed kMaxPacketSize.
+ // Note that we may not use every byte of the writer in this case.
+ DLOG(INFO) << "Truncating large frame";
+ return free_bytes;
+ }
+ }
+ return frame_len;
}
-QuicPacket* QuicFramer::ConstructMaxFrameDataPacket(
- const QuicPacketHeader& header,
- const QuicFrames& frames,
- size_t* num_consumed) {
- DCHECK(!frames.empty());
- // Compute the length of the packet. We use "magic numbers" here because
- // sizeof(member_) is not necessarily the same as sizeof(member_wire_format).
+QuicPacket* QuicFramer::ConstructFrameDataPacket(const QuicPacketHeader& header,
+ const QuicFrames& frames) {
const size_t max_plaintext_size = GetMaxPlaintextSize(kMaxPacketSize);
- size_t len = kPacketHeaderSize;
- bool truncating = false;
+ size_t packet_size = kPacketHeaderSize;
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) {
- // Only truncate the first frame in a packet, so if subsequent ones go
- // over, stop including more frames.
- if (i > 0) {
- break;
- }
- if (CanTruncate(frames[0])) {
- // Truncate the frame so the packet will not exceed kMaxPacketSize.
- // Note that we may not use every byte of the writer in this case.
- len = max_plaintext_size;
- *num_consumed = 1;
- truncating = true;
- DLOG(INFO) << "Truncating large frame";
- break;
- } else {
- return NULL;
- }
- }
- len += frame_len;
- *num_consumed = i + 1;
- }
- if (truncating) {
- DCHECK_EQ(1u, *num_consumed);
+ DCHECK_LE(packet_size, max_plaintext_size);
+ const size_t frame_size = GetSerializedFrameLength(
+ frames[i], max_plaintext_size - packet_size, i == 0);
+ DCHECK(frame_size);
+ packet_size += frame_size;
}
+ return ConstructFrameDataPacket(header, frames, packet_size);
+}
- QuicDataWriter writer(len);
-
+QuicPacket* QuicFramer::ConstructFrameDataPacket(const QuicPacketHeader& header,
+ const QuicFrames& frames,
+ size_t packet_size) {
+ QuicDataWriter writer(packet_size);
if (!WritePacketHeader(header, &writer)) {
return NULL;
}
- // frame count
- if (*num_consumed > 256u) {
- return NULL;
- }
-
- for (size_t i = 0; i < *num_consumed; ++i) {
+ for (size_t i = 0; i < frames.size(); ++i) {
const QuicFrame& frame = frames[i];
if (!writer.WriteUInt8(frame.type)) {
return NULL;
@@ -171,9 +151,11 @@ QuicPacket* QuicFramer::ConstructMaxFrameDataPacket(
}
}
- DCHECK(truncating || len == writer.length());
// Save the length before writing, because take clears it.
- len = writer.length();
+ const size_t len = writer.length();
+ // Less than or equal because truncated acks end up with max_plaintex_size
+ // length, even though they're typically slightly shorter.
+ DCHECK_LE(len, packet_size);
QuicPacket* packet = QuicPacket::NewDataPacket(writer.take(), len, true);
if (fec_builder_) {
@@ -231,10 +213,7 @@ QuicEncryptedPacket* QuicFramer::ConstructPublicResetPacket(
return new QuicEncryptedPacket(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) {
+bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) {
DCHECK(!reader_.get());
reader_.reset(new QuicDataReader(packet.data(), packet.length()));
@@ -250,7 +229,7 @@ bool QuicFramer::ProcessPacket(const IPEndPoint& self_address,
if (public_header.flags & PACKET_PUBLIC_FLAGS_RST) {
rv = ProcessPublicResetPacket(public_header);
} else {
- rv = ProcessDataPacket(public_header, self_address, peer_address, packet);
+ rv = ProcessDataPacket(public_header, packet);
}
reader_.reset(NULL);
@@ -259,10 +238,8 @@ bool QuicFramer::ProcessPacket(const IPEndPoint& self_address,
bool QuicFramer::ProcessDataPacket(
const QuicPacketPublicHeader& public_header,
- const IPEndPoint& self_address,
- const IPEndPoint& peer_address,
const QuicEncryptedPacket& packet) {
- visitor_->OnPacket(self_address, peer_address);
+ visitor_->OnPacket();
QuicPacketHeader header(public_header);
if (!ProcessPacketHeader(&header, packet)) {
@@ -314,7 +291,6 @@ bool QuicFramer::ProcessPublicResetPacket(
set_detailed_error("Unable to read rejected sequence number.");
return false;
}
-
visitor_->OnPublicResetPacket(packet);
return true;
}
@@ -400,13 +376,6 @@ QuicPacketSequenceNumber QuicFramer::CalculatePacketSequenceNumberFromWire(
next_epoch + packet_sequence_number));
}
-/* static */
-bool QuicFramer::ReadGuidFromPacket(const QuicEncryptedPacket& packet,
- QuicGuid* guid) {
- QuicDataReader reader(packet.data(), packet.length());
- return reader.ReadUInt64(guid);
-}
-
bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) {
if (!reader_->ReadUInt64(&public_header->guid)) {
set_detailed_error("Unable to read GUID.");
@@ -428,6 +397,13 @@ bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) {
return true;
}
+// static
+bool QuicFramer::ReadGuidFromPacket(const QuicEncryptedPacket& packet,
+ QuicGuid* guid) {
+ QuicDataReader reader(packet.data(), packet.length());
+ return reader.ReadUInt64(guid);
+}
+
bool QuicFramer::ProcessPacketHeader(
QuicPacketHeader* header,
const QuicEncryptedPacket& packet) {
@@ -682,11 +658,12 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame(
break;
}
case kFixRate: {
- CongestionFeedbackMessageFixRate* fix_rate = &frame->fix_rate;
- if (!reader_->ReadUInt32(&fix_rate->bitrate_in_bytes_per_second)) {
+ uint32 bitrate = 0;
+ if (!reader_->ReadUInt32(&bitrate)) {
set_detailed_error("Unable to read bitrate.");
return false;
}
+ frame->fix_rate.bitrate = QuicBandwidth::FromBytesPerSecond(bitrate);
break;
}
case kTCP: {
@@ -696,10 +673,13 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame(
"Unable to read accumulated number of lost packets.");
return false;
}
- if (!reader_->ReadUInt16(&tcp->receive_window)) {
+ uint16 receive_window = 0;
+ if (!reader_->ReadUInt16(&receive_window)) {
set_detailed_error("Unable to read receive window.");
return false;
}
+ // Simple bit packing, don't send the 4 least significant bits.
+ tcp->receive_window = static_cast<QuicByteCount>(receive_window) << 4;
break;
}
default:
@@ -1034,17 +1014,20 @@ bool QuicFramer::AppendQuicCongestionFeedbackFramePayload(
case kFixRate: {
const CongestionFeedbackMessageFixRate& fix_rate =
frame.fix_rate;
- if (!writer->WriteUInt32(fix_rate.bitrate_in_bytes_per_second)) {
+ if (!writer->WriteUInt32(fix_rate.bitrate.ToBytesPerSecond())) {
return false;
}
break;
}
case kTCP: {
const CongestionFeedbackMessageTCP& tcp = frame.tcp;
+ DCHECK_LE(tcp.receive_window, 1u << 20);
+ // Simple bit packing, don't send the 4 least significant bits.
+ uint16 receive_window = static_cast<uint16>(tcp.receive_window >> 4);
if (!writer->WriteUInt16(tcp.accumulated_number_of_lost_packets)) {
return false;
}
- if (!writer->WriteUInt16(tcp.receive_window)) {
+ if (!writer->WriteUInt16(receive_window)) {
return false;
}
break;
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index d507630..297ca05 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -11,7 +11,6 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/string_piece.h"
-#include "net/base/ip_endpoint.h"
#include "net/base/net_export.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
@@ -39,8 +38,7 @@ class NET_EXPORT_PRIVATE QuicFramerVisitorInterface {
// Called when a new packet has been received, before it
// has been validated or processed.
- virtual void OnPacket(const IPEndPoint& self_address,
- const IPEndPoint& peer_address) = 0;
+ virtual void OnPacket() = 0;
// Called when a public reset packet has been parsed but has not yet
// been validated.
@@ -135,9 +133,7 @@ class NET_EXPORT_PRIVATE QuicFramer {
// single, complete UDP packet (not a frame of a packet). This packet
// might be null padded past the end of the payload, which will be correctly
// ignored.
- bool ProcessPacket(const IPEndPoint& self_address,
- const IPEndPoint& peer_address,
- const QuicEncryptedPacket& packet);
+ bool ProcessPacket(const QuicEncryptedPacket& packet);
// Pass a data packet that was revived from FEC data into the framer
// for parsing.
@@ -146,17 +142,24 @@ class NET_EXPORT_PRIVATE QuicFramer {
bool ProcessRevivedPacket(const QuicPacketHeader& header,
base::StringPiece payload);
+ // Returns the number of bytes added to the packet for the specified frame,
+ // and 0 if the frame doesn't fit. Includes the header size for the first
+ // frame.
+ size_t GetSerializedFrameLength(
+ const QuicFrame& frame, size_t free_bytes, bool first_frame);
+
// Returns a new QuicPacket, owned by the caller, populated with the fields
// in |header| and |frames|, or NULL if the packet could not be created.
+ // TODO(ianswett): Used for testing only.
QuicPacket* ConstructFrameDataPacket(const QuicPacketHeader& header,
const QuicFrames& frames);
- // Returns a new QuicPacket, owned by the caller, populated with the fields
- // in |header| and |fec|, or NULL if the packet could not be created. Sets
- // num_consumed to the number of frames consumed constructing the packet.
- QuicPacket* ConstructMaxFrameDataPacket(const QuicPacketHeader& header,
- const QuicFrames& frames,
- size_t* num_consumed);
+ // Returns a new QuicPacket from the first |num_frames| frames, owned by the
+ // caller or NULL if the packet could not be created. The packet must be of
+ // size |packet_size|.
+ QuicPacket* ConstructFrameDataPacket(const QuicPacketHeader& header,
+ const QuicFrames& frames,
+ size_t packet_size);
// Returns a new QuicPacket, owned by the caller, populated with the fields
// in |header| and |fec|, or NULL if the packet could not be created.
@@ -185,8 +188,6 @@ class NET_EXPORT_PRIVATE QuicFramer {
friend class test::QuicFramerPeer;
bool ProcessDataPacket(const QuicPacketPublicHeader& public_header,
- const IPEndPoint& self_address,
- const IPEndPoint& peer_address,
const QuicEncryptedPacket& packet);
bool ProcessPublicResetPacket(const QuicPacketPublicHeader& public_header);
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index 3c0497d..2b5cb38 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -103,11 +103,7 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface {
error_count_++;
}
- virtual void OnPacket(const IPEndPoint& self_address,
- const IPEndPoint& peer_address) {
- self_address_ = self_address;
- peer_address_ = peer_address;
- }
+ virtual void OnPacket() {}
virtual void OnPublicResetPacket(const QuicPublicResetPacket& packet) {
public_reset_packet_.reset(new QuicPublicResetPacket(packet));
@@ -171,8 +167,6 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface {
int revived_packets_;
bool accept_packet_;
- IPEndPoint self_address_;
- IPEndPoint peer_address_;
scoped_ptr<QuicPacketHeader> header_;
scoped_ptr<QuicPublicResetPacket> public_reset_packet_;
vector<QuicStreamFrame*> stream_frames_;
@@ -189,9 +183,7 @@ class QuicFramerTest : public ::testing::Test {
QuicFramerTest()
: encrypter_(new test::TestEncrypter()),
decrypter_(new test::TestDecrypter()),
- framer_(decrypter_, encrypter_),
- self_address_(IPAddressNumber(), 1),
- peer_address_(IPAddressNumber(), 2) {
+ framer_(decrypter_, encrypter_) {
framer_.set_visitor(&visitor_);
}
@@ -244,8 +236,7 @@ class QuicFramerTest : public ::testing::Test {
string expected_error,
QuicErrorCode error_code) {
QuicEncryptedPacket encrypted(AsChars(packet), len, false);
- EXPECT_FALSE(framer_.ProcessPacket(self_address_, peer_address_,
- encrypted)) << "len: " << len;
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted)) << "len: " << len;
EXPECT_EQ(expected_error, framer_.detailed_error()) << "len: " << len;
EXPECT_EQ(error_code, framer_.error()) << "len: " << len;
}
@@ -274,8 +265,6 @@ class QuicFramerTest : public ::testing::Test {
test::TestDecrypter* decrypter_;
QuicFramer framer_;
test::TestQuicVisitor visitor_;
- IPEndPoint self_address_;
- IPEndPoint peer_address_;
};
TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearEpochStart) {
@@ -380,7 +369,7 @@ TEST_F(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearNextMax) {
TEST_F(QuicFramerTest, EmptyPacket) {
char packet[] = { 0x00 };
QuicEncryptedPacket encrypted(packet, 0, false);
- EXPECT_FALSE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
}
@@ -403,7 +392,7 @@ TEST_F(QuicFramerTest, LargePacket) {
memset(packet + kPacketHeaderSize, 0, kMaxPacketSize - kPacketHeaderSize + 1);
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_FALSE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
ASSERT_TRUE(visitor_.header_.get());
// Make sure we've parsed the packet header, so we can send an error.
@@ -430,7 +419,7 @@ TEST_F(QuicFramerTest, PacketHeader) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_FALSE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
@@ -567,12 +556,10 @@ TEST_F(QuicFramerTest, PaddingFrame) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet))));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- 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());
@@ -621,13 +608,11 @@ TEST_F(QuicFramerTest, StreamFrame) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet))));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- ASSERT_EQ(peer_address_, visitor_.peer_address_);
- ASSERT_EQ(self_address_, visitor_.self_address_);
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
@@ -692,12 +677,11 @@ TEST_F(QuicFramerTest, RejectPacket) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet))));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- ASSERT_EQ(peer_address_, visitor_.peer_address_);
ASSERT_EQ(0u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
@@ -787,7 +771,7 @@ TEST_F(QuicFramerTest, StreamFrameInFecGroup) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet))));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -797,7 +781,6 @@ TEST_F(QuicFramerTest, StreamFrameInFecGroup) {
EXPECT_EQ(string(AsChars(packet) + kStartOfFecProtectedData,
arraysize(packet) - kStartOfFecProtectedData),
visitor_.fec_protected_payload_);
- ASSERT_EQ(peer_address_, visitor_.peer_address_);
ASSERT_EQ(1u, visitor_.stream_frames_.size());
EXPECT_EQ(0u, visitor_.ack_frames_.size());
@@ -839,7 +822,7 @@ TEST_F(QuicFramerTest, AckFrame) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet))));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -899,7 +882,7 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameTCP) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet))));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -912,7 +895,7 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameTCP) {
ASSERT_EQ(kTCP, frame.type);
EXPECT_EQ(0x0201,
frame.tcp.accumulated_number_of_lost_packets);
- EXPECT_EQ(0x0403, frame.tcp.receive_window);
+ EXPECT_EQ(0x4030u, frame.tcp.receive_window);
// Now test framing boundaries
for (size_t i = 0; i < 6; ++i) {
@@ -971,7 +954,7 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet))));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -1052,7 +1035,7 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameFixRate) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet))));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -1064,7 +1047,7 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameFixRate) {
*visitor_.congestion_feedback_frames_[0];
ASSERT_EQ(kFixRate, frame.type);
EXPECT_EQ(static_cast<uint32>(0x04030201),
- frame.fix_rate.bitrate_in_bytes_per_second);
+ frame.fix_rate.bitrate.ToBytesPerSecond());
// Now test framing boundaries
for (size_t i = 0; i < 6; ++i) {
@@ -1104,7 +1087,7 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInvalidFeedback) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_FALSE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet))));
EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
}
@@ -1144,12 +1127,11 @@ TEST_F(QuicFramerTest, RstStreamFrame) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet))));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.header_.get());
- ASSERT_EQ(peer_address_, visitor_.peer_address_);
EXPECT_EQ(GG_UINT64_C(0x01020304), visitor_.rst_stream_frame_.stream_id);
EXPECT_EQ(0x05060708, visitor_.rst_stream_frame_.error_code);
@@ -1217,7 +1199,7 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet))));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -1266,7 +1248,7 @@ TEST_F(QuicFramerTest, PublicResetPacket) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.public_reset_packet_.get());
EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
@@ -1317,7 +1299,7 @@ TEST_F(QuicFramerTest, FecPacket) {
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, encrypted));
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet))));
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
@@ -1495,7 +1477,7 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) {
QuicCongestionFeedbackFrame congestion_feedback_frame;
congestion_feedback_frame.type = kTCP;
congestion_feedback_frame.tcp.accumulated_number_of_lost_packets = 0x0201;
- congestion_feedback_frame.tcp.receive_window = 0x0403;
+ congestion_feedback_frame.tcp.receive_window = 0x4030;
QuicFrames frames;
frames.push_back(QuicFrame(&congestion_feedback_frame));
@@ -1611,8 +1593,8 @@ TEST_F(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) {
QuicCongestionFeedbackFrame congestion_feedback_frame;
congestion_feedback_frame.type = kFixRate;
- congestion_feedback_frame.fix_rate.bitrate_in_bytes_per_second
- = 0x04030201;
+ congestion_feedback_frame.fix_rate.bitrate
+ = QuicBandwidth::FromBytesPerSecond(0x04030201);
QuicFrames frames;
frames.push_back(QuicFrame(&congestion_feedback_frame));
@@ -1927,6 +1909,7 @@ TEST_F(QuicFramerTest, DISABLED_Truncation) {
close_frame.error_code = static_cast<QuicErrorCode>(0x05060708);
close_frame.error_details = "because I can";
ack_frame->received_info.largest_observed = 201;
+ ack_frame->sent_info.least_unacked = 0;
for (uint64 i = 1; i < ack_frame->received_info.largest_observed; ++i) {
ack_frame->received_info.missing_packets.insert(i);
}
@@ -1959,11 +1942,10 @@ TEST_F(QuicFramerTest, DISABLED_Truncation) {
framer_.EncryptPacket(*raw_close_packet));
// Now make sure we can turn our ack packet back into an ack frame
- ASSERT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, *ack_packet));
+ ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
// And do the same for the close frame.
- ASSERT_TRUE(framer_.ProcessPacket(self_address_, peer_address_,
- *close_packet));
+ ASSERT_TRUE(framer_.ProcessPacket(*close_packet));
}
TEST_F(QuicFramerTest, CleanTruncation) {
@@ -2012,11 +1994,10 @@ TEST_F(QuicFramerTest, CleanTruncation) {
framer_.EncryptPacket(*raw_close_packet));
// Now make sure we can turn our ack packet back into an ack frame
- ASSERT_TRUE(framer_.ProcessPacket(self_address_, peer_address_, *ack_packet));
+ ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
// And do the same for the close frame.
- ASSERT_TRUE(framer_.ProcessPacket(self_address_, peer_address_,
- *close_packet));
+ ASSERT_TRUE(framer_.ProcessPacket(*close_packet));
// Test for clean truncation of the ack by comparing the length of the
// original packets to the re-serialized packets.
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 8ca25c0..5cdf5cd 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -11,6 +11,8 @@
#include "net/base/upload_bytes_element_reader.h"
#include "net/base/upload_data_stream.h"
#include "net/http/http_response_headers.h"
+#include "net/quic/congestion_control/receive_algorithm_interface.h"
+#include "net/quic/congestion_control/send_algorithm_interface.h"
#include "net/quic/quic_client_session.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_connection_helper.h"
@@ -42,20 +44,19 @@ class TestQuicConnection : public QuicConnection {
: QuicConnection(guid, address, helper) {
}
- void SetScheduler(QuicSendScheduler* scheduler) {
- QuicConnectionPeer::SetScheduler(this, scheduler);
+ void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) {
+ QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm);
}
- void SetCollector(QuicReceiptMetricsCollector* collector) {
- QuicConnectionPeer::SetCollector(this, collector);
+ void SetReceiveAlgorithm(ReceiveAlgorithmInterface* receive_algorithm) {
+ QuicConnectionPeer::SetReceiveAlgorithm(this, receive_algorithm);
}
};
-class TestCollector : public QuicReceiptMetricsCollector {
+class TestReceiveAlgorithm : public ReceiveAlgorithmInterface {
public:
- explicit TestCollector(QuicCongestionFeedbackFrame* feedback)
- : QuicReceiptMetricsCollector(&clock_, kFixRate),
- feedback_(feedback) {
+ explicit TestReceiveAlgorithm(QuicCongestionFeedbackFrame* feedback)
+ : feedback_(feedback) {
}
bool GenerateCongestionFeedback(
@@ -68,13 +69,13 @@ class TestCollector : public QuicReceiptMetricsCollector {
}
MOCK_METHOD4(RecordIncomingPacket,
- void(size_t, QuicPacketSequenceNumber, QuicTime, bool));
+ void(QuicByteCount, QuicPacketSequenceNumber, QuicTime, bool));
private:
MockClock clock_;
QuicCongestionFeedbackFrame* feedback_;
- DISALLOW_COPY_AND_ASSIGN(TestCollector);
+ DISALLOW_COPY_AND_ASSIGN(TestReceiveAlgorithm);
};
// Subclass of QuicHttpStream that closes itself when the first piece of data
@@ -162,16 +163,16 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
net_log_.net_log());
socket->Connect(peer_addr_);
runner_ = new TestTaskRunner(&clock_);
- scheduler_ = new MockScheduler();
- collector_ = new TestCollector(NULL);
- EXPECT_CALL(*scheduler_, TimeUntilSend(_)).
+ send_algorithm_ = new MockSendAlgorithm();
+ receive_algorithm_ = new TestReceiveAlgorithm(NULL);
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_)).
WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
helper_ = new QuicConnectionHelper(runner_.get(), &clock_,
&random_generator_, socket);
connection_ = new TestQuicConnection(guid_, peer_addr_, helper_);
connection_->set_visitor(&visitor_);
- connection_->SetScheduler(scheduler_);
- connection_->SetCollector(collector_);
+ connection_->SetSendAlgorithm(send_algorithm_);
+ connection_->SetReceiveAlgorithm(receive_algorithm_);
session_.reset(new QuicClientSession(connection_, helper_, NULL,
"www.google.com"));
CryptoHandshakeMessage message;
@@ -255,8 +256,8 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
BoundNetLog net_log_;
bool use_closing_stream_;
- MockScheduler* scheduler_;
- TestCollector* collector_;
+ MockSendAlgorithm* send_algorithm_;
+ TestReceiveAlgorithm* receive_algorithm_;
scoped_refptr<TestTaskRunner> runner_;
scoped_array<MockWrite> mock_writes_;
MockClock clock_;
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index 39d9f7e..e80ea85 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -19,7 +19,8 @@ QuicPacketCreator::QuicPacketCreator(QuicGuid guid, QuicFramer* framer)
: guid_(guid),
framer_(framer),
sequence_number_(0),
- fec_group_number_(0) {
+ fec_group_number_(0),
+ packet_size_(kPacketHeaderSize) {
framer_->set_fec_builder(this);
}
@@ -34,16 +35,13 @@ void QuicPacketCreator::OnBuiltFecProtectedPayload(
}
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);
+ return fec_group_.get() != NULL &&
+ (force_close ||
+ fec_group_->NumReceivedPackets() >= options_.max_packets_per_fec_group);
}
void QuicPacketCreator::MaybeStartFEC() {
- if (options_.max_packets_per_fec_group > 0) {
- DCHECK(fec_group_.get() == NULL);
+ if (options_.max_packets_per_fec_group > 0 && fec_group_.get() == NULL) {
// Set the fec group number to the sequence number of the next packet.
fec_group_number_ = sequence_number() + 1;
fec_group_.reset(new QuicFecGroup());
@@ -54,65 +52,84 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
StringPiece data,
QuicStreamOffset offset,
bool fin,
- QuicFrames* frames) {
+ QuicFrame* frame) {
DCHECK_GT(options_.max_packet_length,
QuicUtils::StreamFramePacketOverhead(1));
+ const size_t free_bytes = BytesFree();
+ DCHECK_GE(free_bytes, kFrameTypeSize + kMinStreamFrameLength);
- size_t unconsumed_bytes = data.size();
+ size_t bytes_consumed = 0;
if (data.size() != 0) {
- size_t max_frame_len = framer_->GetMaxPlaintextSize(
- options_.max_packet_length -
- QuicUtils::StreamFramePacketOverhead(1));
- DCHECK_GT(max_frame_len, 0u);
- size_t frame_len = min<size_t>(max_frame_len, unconsumed_bytes);
-
- if (unconsumed_bytes > 0) {
- bool set_fin = false;
- 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);
- frames->push_back(QuicFrame(new QuicStreamFrame(
- id, set_fin, offset, data_frame)));
-
- unconsumed_bytes -= frame_len;
- }
- // If we haven't finished serializing all the data, don't set any final fin.
- if (unconsumed_bytes > 0) {
- fin = false;
- }
+ size_t max_data_len = free_bytes - kFrameTypeSize - kMinStreamFrameLength;
+ bytes_consumed = min<size_t>(max_data_len, data.size());
+
+ bool set_fin = fin && bytes_consumed == data.size(); // Last frame.
+ StringPiece data_frame(data.data(), bytes_consumed);
+ *frame = QuicFrame(new QuicStreamFrame(id, set_fin, offset, data_frame));
+ } else {
+ DCHECK(fin);
+ // Create a new packet for the fin, if necessary.
+ *frame = QuicFrame(new QuicStreamFrame(id, true, offset, ""));
}
- // Create a new packet for the fin, if necessary.
- if (fin && data.size() == 0) {
- QuicStreamFrame* frame = new QuicStreamFrame(id, true, offset, "");
- frames->push_back(QuicFrame(frame));
+ return bytes_consumed;
+}
+
+PacketPair QuicPacketCreator::SerializeAllFrames(const QuicFrames& frames) {
+ DCHECK_EQ(0u, queued_frames_.size());
+ for (size_t i = 0; i < frames.size(); ++i) {
+ bool success = AddFrame(frames[i]);
+ DCHECK(success);
}
+ return SerializePacket(NULL);
+}
- return data.size() - unconsumed_bytes;
+bool QuicPacketCreator::HasPendingFrames() {
+ return !queued_frames_.empty();
}
-PacketPair QuicPacketCreator::SerializeAllFrames(const QuicFrames& frames) {
- size_t num_serialized;
- PacketPair pair = SerializeFrames(frames, &num_serialized);
- DCHECK_EQ(frames.size(), num_serialized);
- return pair;
+size_t QuicPacketCreator::BytesFree() {
+ const size_t max_plaintext_size =
+ framer_->GetMaxPlaintextSize(options_.max_packet_length);
+ if (packet_size_ > max_plaintext_size) {
+ return 0;
+ } else {
+ return max_plaintext_size - packet_size_;
+ }
+}
+
+bool QuicPacketCreator::AddFrame(const QuicFrame& frame) {
+ size_t frame_len = framer_->GetSerializedFrameLength(
+ frame, BytesFree(), queued_frames_.empty());
+ if (frame_len == 0) {
+ return false;
+ }
+ packet_size_ += frame_len;
+ queued_frames_.push_back(frame);
+ return true;
}
-PacketPair QuicPacketCreator::SerializeFrames(const QuicFrames& frames,
- size_t* num_serialized) {
+PacketPair QuicPacketCreator::SerializePacket(
+ QuicFrames* retransmittable_frames) {
+ DCHECK_EQ(false, queued_frames_.empty());
QuicPacketHeader header;
FillPacketHeader(fec_group_number_, PACKET_PRIVATE_FLAGS_NONE, &header);
- QuicPacket* packet = framer_->ConstructMaxFrameDataPacket(
- header, frames, num_serialized);
+ QuicPacket* packet = framer_->ConstructFrameDataPacket(
+ header, queued_frames_, packet_size_);
+ for (size_t i = 0; i < queued_frames_.size(); ++i) {
+ if (retransmittable_frames != NULL && ShouldRetransmit(queued_frames_[i])) {
+ retransmittable_frames->push_back(queued_frames_[i]);
+ }
+ }
+ queued_frames_.clear();
+ packet_size_ = kPacketHeaderSize;
return make_pair(header.packet_sequence_number, packet);
}
QuicPacketCreator::PacketPair QuicPacketCreator::SerializeFec() {
- DCHECK_LT(0u, fec_group_->GroupSize());
+ DCHECK_LT(0u, fec_group_->NumReceivedPackets());
+ DCHECK_EQ(0u, queued_frames_.size());
QuicPacketHeader header;
FillPacketHeader(fec_group_number_, PACKET_PRIVATE_FLAGS_FEC, &header);
@@ -129,15 +146,9 @@ QuicPacketCreator::PacketPair QuicPacketCreator::SerializeFec() {
QuicPacketCreator::PacketPair QuicPacketCreator::CloseConnection(
QuicConnectionCloseFrame* close_frame) {
-
- QuicPacketHeader header;
- FillPacketHeader(0, PACKET_PRIVATE_FLAGS_NONE, &header);
-
QuicFrames frames;
frames.push_back(QuicFrame(close_frame));
- QuicPacket* packet = framer_->ConstructFrameDataPacket(header, frames);
- DCHECK(packet);
- return make_pair(header.packet_sequence_number, packet);
+ return SerializeAllFrames(frames);
}
void QuicPacketCreator::FillPacketHeader(QuicFecGroupNumber fec_group,
@@ -150,4 +161,9 @@ void QuicPacketCreator::FillPacketHeader(QuicFecGroupNumber fec_group,
header->fec_group = fec_group;
}
+bool QuicPacketCreator::ShouldRetransmit(const QuicFrame& frame) {
+ return frame.type != ACK_FRAME && frame.type != CONGESTION_FEEDBACK_FRAME &&
+ frame.type != PADDING_FRAME;
+}
+
} // namespace net
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index f9836f3..b5eb9b8 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Some helpers for quic packet creation.
+// Accumulates frames for the next packet until more frames no longer fit or
+// it's time to create a packet from them. Also provides packet creation of
+// FEC packets based on previously created packets.
#ifndef NET_QUIC_QUIC_PACKET_CREATOR_H_
#define NET_QUIC_QUIC_PACKET_CREATOR_H_
@@ -20,6 +22,8 @@ namespace net {
class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
public:
+ typedef std::pair<QuicPacketSequenceNumber, QuicPacket*> PacketPair;
+
// Options for controlling how packets are created.
struct Options {
Options()
@@ -28,7 +32,6 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
max_packets_per_fec_group(0) {
}
- // TODO(alyssar, rch) max frames/packet
size_t max_packet_length;
bool random_reorder; // Inefficient: rewrite if used at scale.
// 0 indicates fec is disabled.
@@ -43,32 +46,41 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
virtual void OnBuiltFecProtectedPayload(const QuicPacketHeader& header,
base::StringPiece payload) OVERRIDE;
- 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.
+ // Starts a new FEC group with the next serialized packet, if FEC is enabled
+ // and there is not already an FEC group open.
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.
+ // Converts a raw payload to a frame which fits into the currently open
+ // packet if there is one. Returns the number of bytes consumed from data.
+ // If data is empty and fin is true, the expected behavior is to consume the
+ // fin but return 0.
size_t CreateStreamFrame(QuicStreamId id,
base::StringPiece data,
QuicStreamOffset offset,
bool fin,
- QuicFrames* frames);
+ QuicFrame* frame);
// 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);
+ // Returns true if there are frames pending to be serialized.
+ bool HasPendingFrames();
+
+ // Returns the number of bytes which are free to frames in the current packet.
+ size_t BytesFree();
+
+ // Adds |frame| to the packet creator's list of frames to be serialized.
+ // Returns false if the frame doesn't fit into the current packet.
+ bool AddFrame(const QuicFrame& frame);
+
+ // Serializes all frames which have been added and adds any which should be
+ // retransmitted to |retransmittable_frames| if it's not NULL.
+ PacketPair SerializePacket(QuicFrames* retransmittable_frames);
// Packetize FEC data.
PacketPair SerializeFec();
@@ -90,6 +102,8 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
}
private:
+ static bool ShouldRetransmit(const QuicFrame& frame);
+
void FillPacketHeader(QuicFecGroupNumber fec_group,
QuicPacketPrivateFlags flags,
QuicPacketHeader* header);
@@ -100,7 +114,8 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
QuicPacketSequenceNumber sequence_number_;
QuicFecGroupNumber fec_group_number_;
scoped_ptr<QuicFecGroup> fec_group_;
-
+ size_t packet_size_;
+ QuicFrames queued_frames_;
};
} // namespace net
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index d4bdb28..1c202d0 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -28,7 +28,7 @@ class QuicPacketCreatorTest : public ::testing::Test {
sequence_number_(0),
guid_(2),
data_("foo"),
- utils_(guid_, &framer_) {
+ creator_(guid_, &framer_) {
framer_.set_visitor(&framer_visitor_);
}
~QuicPacketCreatorTest() {
@@ -39,7 +39,17 @@ class QuicPacketCreatorTest : public ::testing::Test {
void ProcessPacket(QuicPacket* packet) {
scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(*packet));
- framer_.ProcessPacket(IPEndPoint(), IPEndPoint(), *encrypted);
+ framer_.ProcessPacket(*encrypted);
+ }
+
+ void CheckStreamFrame(const QuicFrame& frame, QuicStreamId stream_id,
+ const string& data, QuicStreamOffset offset, bool fin) {
+ EXPECT_EQ(STREAM_FRAME, frame.type);
+ ASSERT_TRUE(frame.stream_frame);
+ EXPECT_EQ(stream_id, frame.stream_frame->stream_id);
+ EXPECT_EQ(data, frame.stream_frame->data);
+ EXPECT_EQ(offset, frame.stream_frame->offset);
+ EXPECT_EQ(fin, frame.stream_frame->fin);
}
QuicFrames frames_;
@@ -49,17 +59,17 @@ class QuicPacketCreatorTest : public ::testing::Test {
QuicPacketSequenceNumber sequence_number_;
QuicGuid guid_;
string data_;
- QuicPacketCreator utils_;
+ QuicPacketCreator creator_;
};
TEST_F(QuicPacketCreatorTest, SerializeFrame) {
frames_.push_back(QuicFrame(new QuicStreamFrame(
0u, false, 0u, StringPiece(""))));
- PacketPair pair = utils_.SerializeAllFrames(frames_);
+ PacketPair pair = creator_.SerializeAllFrames(frames_);
{
InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket(_, _));
+ EXPECT_CALL(framer_visitor_, OnPacket());
EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
EXPECT_CALL(framer_visitor_, OnPacketComplete());
@@ -74,11 +84,11 @@ TEST_F(QuicPacketCreatorTest, SerializeFrames) {
0u, false, 0u, StringPiece(""))));
frames_.push_back(QuicFrame(new QuicStreamFrame(
0u, true, 0u, StringPiece(""))));
- PacketPair pair = utils_.SerializeAllFrames(frames_);
+ PacketPair pair = creator_.SerializeAllFrames(frames_);
{
InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket(_, _));
+ EXPECT_CALL(framer_visitor_, OnPacket());
EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
EXPECT_CALL(framer_visitor_, OnAckFrame(_));
EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
@@ -90,16 +100,17 @@ TEST_F(QuicPacketCreatorTest, SerializeFrames) {
}
TEST_F(QuicPacketCreatorTest, SerializeWithFEC) {
- utils_.options()->max_packets_per_fec_group = 6;
- utils_.MaybeStartFEC();
+ creator_.options()->max_packets_per_fec_group = 6;
+ ASSERT_FALSE(creator_.ShouldSendFec(false));
+ creator_.MaybeStartFEC();
frames_.push_back(QuicFrame(new QuicStreamFrame(
0u, false, 0u, StringPiece(""))));
- PacketPair pair = utils_.SerializeAllFrames(frames_);
+ PacketPair pair = creator_.SerializeAllFrames(frames_);
{
InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket(_, _));
+ EXPECT_CALL(framer_visitor_, OnPacket());
EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
EXPECT_CALL(framer_visitor_, OnFecProtectedPayload(_));
EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
@@ -108,15 +119,15 @@ TEST_F(QuicPacketCreatorTest, SerializeWithFEC) {
ProcessPacket(pair.second);
delete pair.second;
- ASSERT_FALSE(utils_.ShouldSendFec(false));
- ASSERT_TRUE(utils_.ShouldSendFec(true));
+ ASSERT_FALSE(creator_.ShouldSendFec(false));
+ ASSERT_TRUE(creator_.ShouldSendFec(true));
- pair = utils_.SerializeFec();
+ pair = creator_.SerializeFec();
ASSERT_EQ(2u, pair.first);
{
InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket(_, _));
+ EXPECT_CALL(framer_visitor_, OnPacket());
EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
EXPECT_CALL(framer_visitor_, OnFecData(_));
EXPECT_CALL(framer_visitor_, OnPacketComplete());
@@ -130,12 +141,12 @@ TEST_F(QuicPacketCreatorTest, CloseConnection) {
frame.error_code = QUIC_NO_ERROR;
frame.ack_frame = QuicAckFrame(0u, 0u);
- PacketPair pair = utils_.CloseConnection(&frame);
+ PacketPair pair = creator_.CloseConnection(&frame);
ASSERT_EQ(1u, pair.first);
- ASSERT_EQ(1u, utils_.sequence_number());
+ ASSERT_EQ(1u, creator_.sequence_number());
InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket(_, _));
+ EXPECT_CALL(framer_visitor_, OnPacket());
EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
EXPECT_CALL(framer_visitor_, OnAckFrame(_));
EXPECT_CALL(framer_visitor_, OnConnectionCloseFrame(_));
@@ -145,6 +156,86 @@ TEST_F(QuicPacketCreatorTest, CloseConnection) {
delete pair.second;
}
+TEST_F(QuicPacketCreatorTest, CreateStreamFrame) {
+ QuicFrame frame;
+ size_t consumed = creator_.CreateStreamFrame(1u, "test", 0u, false, &frame);
+ EXPECT_EQ(4u, consumed);
+ CheckStreamFrame(frame, 1u, "test", 0u, false);
+ delete frame.stream_frame;
+}
+
+TEST_F(QuicPacketCreatorTest, CreateStreamFrameFin) {
+ QuicFrame frame;
+ size_t consumed = creator_.CreateStreamFrame(1u, "test", 10u, true, &frame);
+ EXPECT_EQ(4u, consumed);
+ CheckStreamFrame(frame, 1u, "test", 10u, true);
+ delete frame.stream_frame;
+}
+
+TEST_F(QuicPacketCreatorTest, CreateStreamFrameFinOnly) {
+ QuicFrame frame;
+ size_t consumed = creator_.CreateStreamFrame(1u, "", 0u, true, &frame);
+ EXPECT_EQ(0u, consumed);
+ CheckStreamFrame(frame, 1u, "", 0u, true);
+ delete frame.stream_frame;
+}
+
+TEST_F(QuicPacketCreatorTest, CreateStreamFrameTooLarge) {
+ // A string larger than fits into a frame.
+ size_t ciphertext_size = NullEncrypter().GetCiphertextSize(1);
+ creator_.options()->max_packet_length =
+ ciphertext_size + QuicUtils::StreamFramePacketOverhead(1);
+ QuicFrame frame;
+ size_t consumed = creator_.CreateStreamFrame(1u, "test", 0u, true, &frame);
+ EXPECT_EQ(1u, consumed);
+ CheckStreamFrame(frame, 1u, "t", 0u, false);
+ delete frame.stream_frame;
+}
+
+TEST_F(QuicPacketCreatorTest, AddFrameAndSerialize) {
+ const size_t max_plaintext_size =
+ framer_.GetMaxPlaintextSize(creator_.options()->max_packet_length);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_EQ(max_plaintext_size - kPacketHeaderSize, creator_.BytesFree());
+
+ // Add a variety of frame types and then a padding frame.
+ QuicAckFrame ack_frame;
+ EXPECT_TRUE(creator_.AddFrame(QuicFrame(&ack_frame)));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+
+ QuicCongestionFeedbackFrame congestion_feedback;
+ congestion_feedback.type = kFixRate;
+ EXPECT_TRUE(creator_.AddFrame(QuicFrame(&congestion_feedback)));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+
+ QuicFrame frame;
+ size_t consumed = creator_.CreateStreamFrame(1u, "test", 0u, false, &frame);
+ EXPECT_EQ(4u, consumed);
+ ASSERT_TRUE(frame.stream_frame);
+ EXPECT_TRUE(creator_.AddFrame(frame));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+
+ QuicPaddingFrame padding_frame;
+ EXPECT_TRUE(creator_.AddFrame(QuicFrame(&padding_frame)));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_EQ(0u, creator_.BytesFree());
+
+ EXPECT_FALSE(creator_.AddFrame(QuicFrame(&ack_frame)));
+
+ // Ensure the packet is successfully created.
+ QuicFrames retransmittable_frames;
+ PacketPair pair = creator_.SerializePacket(&retransmittable_frames);
+ ASSERT_TRUE(pair.second);
+ delete pair.second;
+ ASSERT_EQ(1u, retransmittable_frames.size());
+ EXPECT_EQ(STREAM_FRAME, retransmittable_frames[0].type);
+
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_EQ(max_plaintext_size - kPacketHeaderSize, creator_.BytesFree());
+
+ delete frame.stream_frame;
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 90a5dab..14ad48b 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -121,7 +121,7 @@ ostream& operator<<(ostream& os,
}
case kFixRate: {
os << " bitrate_in_bytes_per_second: "
- << congestion_frame.fix_rate.bitrate_in_bytes_per_second;
+ << congestion_frame.fix_rate.bitrate.ToBytesPerSecond();
break;
}
case kTCP: {
@@ -131,10 +131,6 @@ ostream& operator<<(ostream& os,
os << " receive_window: " << tcp.receive_window;
break;
}
- default: {
- DLOG(FATAL) << "Unsupported congestion info type: "
- << congestion_frame.type;
- }
}
return os;
}
@@ -145,6 +141,10 @@ ostream& operator<<(ostream& os, const QuicAckFrame& ack_frame) {
return os;
}
+CongestionFeedbackMessageFixRate::CongestionFeedbackMessageFixRate()
+ : bitrate(QuicBandwidth::Zero()) {
+}
+
CongestionFeedbackMessageInterArrival::
CongestionFeedbackMessageInterArrival() {}
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 9d641ee..a88d884 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -20,6 +20,7 @@
#include "base/string_piece.h"
#include "net/base/int128.h"
#include "net/base/net_export.h"
+#include "net/quic/quic_bandwidth.h"
#include "net/quic/quic_time.h"
namespace net {
@@ -36,7 +37,8 @@ typedef QuicPacketSequenceNumber QuicFecGroupNumber;
typedef uint64 QuicPublicResetNonceProof;
// TODO(rch): Consider Quic specific names for these constants.
-const size_t kMaxPacketSize = 1200; // Maximum size in bytes of a QUIC packet.
+// Maximum size in bytes of a QUIC packet.
+const QuicByteCount kMaxPacketSize = 1200;
// Maximum number of open streams per connection.
const size_t kDefaultMaxStreamsPerConnection = 100;
@@ -53,6 +55,8 @@ const size_t kPrivateFlagsSize = 1;
const size_t kFecGroupSize = 1;
// Number of bytes reserved for the nonce proof in public reset packet.
const size_t kPublicResetNonceSize = 8;
+// Number of bytes reserved for the frame type preceding each frame.
+const size_t kFrameTypeSize = 1;
// Size in bytes of the data or fec packet header.
const size_t kPacketHeaderSize = kQuicGuidSize + kPublicFlagsSize +
@@ -318,7 +322,7 @@ enum CongestionFeedbackType {
struct NET_EXPORT_PRIVATE CongestionFeedbackMessageTCP {
uint16 accumulated_number_of_lost_packets;
- uint16 receive_window; // Number of bytes >> 4.
+ QuicByteCount receive_window;
};
struct NET_EXPORT_PRIVATE CongestionFeedbackMessageInterArrival {
@@ -331,7 +335,8 @@ struct NET_EXPORT_PRIVATE CongestionFeedbackMessageInterArrival {
};
struct NET_EXPORT_PRIVATE CongestionFeedbackMessageFixRate {
- uint32 bitrate_in_bytes_per_second;
+ CongestionFeedbackMessageFixRate();
+ QuicBandwidth bitrate;
};
struct NET_EXPORT_PRIVATE QuicCongestionFeedbackFrame {
@@ -418,7 +423,6 @@ struct NET_EXPORT_PRIVATE QuicFecData {
// 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
// less than the sequence number of the FEC packet.
base::StringPiece redundancy;
diff --git a/net/quic/quic_protocol_test.cc b/net/quic/quic_protocol_test.cc
new file mode 100644
index 0000000..a77582f
--- /dev/null
+++ b/net/quic/quic_protocol_test.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_protocol.h"
+
+#include "base/stl_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+namespace {
+
+TEST(QuicProtocolTest, ReceivedInfo_RecordReceived) {
+ ReceivedPacketInfo received_info;
+ received_info.RecordReceived(1u);
+
+ EXPECT_EQ(1u, received_info.largest_observed);
+ EXPECT_EQ(0u, received_info.missing_packets.size());
+
+ received_info.RecordReceived(3u);
+
+ EXPECT_EQ(3u, received_info.largest_observed);
+ EXPECT_EQ(1u, received_info.missing_packets.size());
+
+ received_info.RecordReceived(2u);
+
+ EXPECT_EQ(3u, received_info.largest_observed);
+ EXPECT_EQ(0u, received_info.missing_packets.size());
+}
+
+TEST(QuicProtocolTest, ReceivedInfo_ClearMissingBefore) {
+ ReceivedPacketInfo received_info;
+ received_info.RecordReceived(1u);
+
+ // Clear nothing.
+ received_info.ClearMissingBefore(1);
+ EXPECT_EQ(0u, received_info.missing_packets.size());
+
+ received_info.RecordReceived(3u);
+
+ // Clear the first packet.
+ received_info.ClearMissingBefore(2);
+ EXPECT_EQ(1u, received_info.missing_packets.size());
+
+ // Clear the second packet, which has not been received.
+ received_info.ClearMissingBefore(3);
+ EXPECT_EQ(0u, received_info.missing_packets.size());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index f1872d2..1c41ffd 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -184,7 +184,7 @@ void QuicSession::OnCryptoHandshakeComplete(QuicErrorCode error) {
}
void QuicSession::ActivateStream(ReliableQuicStream* stream) {
- LOG(INFO) << "num_streams: " << stream_map_.size()
+ DLOG(INFO) << "num_streams: " << stream_map_.size()
<< ". activating " << stream->id();
DCHECK(stream_map_.count(stream->id()) == 0);
stream_map_[stream->id()] = stream;
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index c5c8b265..32bffc1 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -104,7 +104,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
virtual QuicCryptoStream* GetCryptoStream() = 0;
// Adds 'stream' to the active stream map.
- void ActivateStream(ReliableQuicStream* stream);
+ virtual void ActivateStream(ReliableQuicStream* stream);
// Returns the stream id for a new stream.
QuicStreamId GetNextStreamId();
diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h
index db95241..e780ca5 100644
--- a/net/quic/quic_time.h
+++ b/net/quic/quic_time.h
@@ -67,7 +67,7 @@ class NET_EXPORT_PRIVATE QuicTime {
explicit QuicTime(base::TimeTicks ticks);
// Creates a new QuicTime with an internal value of 0. IsInitialized()
- // will return true for these times.
+ // will return false for these times.
static QuicTime Zero();
// Create a new QuicTime holding the time_ms.
diff --git a/net/quic/quic_time_test.cc b/net/quic/quic_time_test.cc
index 811204bd..fc7d7e3 100644
--- a/net/quic/quic_time_test.cc
+++ b/net/quic/quic_time_test.cc
@@ -7,7 +7,7 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
-namespace testing {
+namespace test {
class QuicTimeDeltaTest : public ::testing::Test {
protected:
@@ -112,5 +112,5 @@ TEST_F(QuicTimeTest, MockClock) {
EXPECT_EQ(now, time);
}
-} // namespace testing
+} // namespace test
} // namespace net
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index 5ae9c35..0cfac44 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -13,10 +13,11 @@ namespace net {
size_t QuicUtils::StreamFramePacketOverhead(int num_frames) {
// TODO(jar): Use sizeof(some name).
return kPacketHeaderSize +
- (1 + // 8 bit type
+ (kFrameTypeSize +
kMinStreamFrameLength) * num_frames;
}
+// static
uint128 QuicUtils::FNV1a_128_Hash(const char* data, int len) {
// The following two constants are defined as part of the hash algorithm.
// 309485009821345068724781371
@@ -41,6 +42,7 @@ uint128 QuicUtils::FNV1a_128_Hash(const char* data, int len) {
case x: \
return #x;
+// static
const char* QuicUtils::ErrorToString(QuicErrorCode error) {
switch (error) {
RETURN_STRING_LITERAL(QUIC_NO_ERROR);
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
new file mode 100644
index 0000000..86323ac
--- /dev/null
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -0,0 +1,91 @@
+// 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/reliable_quic_stream.h"
+
+#include "net/quic/quic_connection.h"
+#include "net/quic/quic_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using base::StringPiece;
+using testing::_;
+using testing::InSequence;
+using testing::Return;
+using testing::StrEq;
+
+namespace net {
+namespace test {
+namespace {
+
+const char kData1[] = "FooAndBar";
+const char kData2[] = "EepAndBaz";
+const size_t kDataLen = 9;
+
+class QuicReliableTestStream : public ReliableQuicStream {
+ public:
+ QuicReliableTestStream(QuicStreamId id, QuicSession* session)
+ : ReliableQuicStream(id, session) {
+ }
+ virtual uint32 ProcessData(const char* data, uint32 data_len) {
+ return 0;
+ }
+ using ReliableQuicStream::WriteData;
+};
+
+class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> {
+ public:
+ ReliableQuicStreamTest()
+ : connection_(new MockConnection(1, IPEndPoint())),
+ session_(connection_, true),
+ stream_(1, &session_) {
+ }
+
+ MockConnection* connection_;
+ MockSession session_;
+ QuicReliableTestStream stream_;
+};
+
+TEST_F(ReliableQuicStreamTest, WriteAllData) {
+ connection_->options()->max_packet_length =
+ 1 + QuicUtils::StreamFramePacketOverhead(1);
+ // TODO(rch): figure out how to get StrEq working here.
+ //EXPECT_CALL(session_, WriteData(_, StrEq(kData1), _, _)).WillOnce(
+ EXPECT_CALL(session_, WriteData(1, _, _, _)).WillOnce(
+ Return(QuicConsumedData(kDataLen, true)));
+ EXPECT_EQ(kDataLen, stream_.WriteData(kData1, false).bytes_consumed);
+}
+
+TEST_F(ReliableQuicStreamTest, WriteData) {
+ connection_->options()->max_packet_length =
+ 1 + QuicUtils::StreamFramePacketOverhead(1);
+ //EXPECT_CALL(session_, WriteData(_, StrEq(kData1), _, _)).WillOnce(
+ EXPECT_CALL(session_, WriteData(_, _, _, _)).WillOnce(
+ Return(QuicConsumedData(kDataLen - 1, false)));
+ // The return will be kDataLen, because the last byte gets buffered.
+ EXPECT_EQ(kDataLen, stream_.WriteData(kData1, false).bytes_consumed);
+
+ // Queue a bytes_consumed write.
+ EXPECT_EQ(kDataLen, stream_.WriteData(kData2, false).bytes_consumed);
+
+ // Make sure we get the tail of the first write followed by the bytes_consumed
+ InSequence s;
+ //EXPECT_CALL(session_, WriteData(_, StrEq(&kData2[kDataLen - 1]), _, _)).
+ EXPECT_CALL(session_, WriteData(_, _, _, _)).
+ WillOnce(Return(QuicConsumedData(1, false)));
+ //EXPECT_CALL(session_, WriteData(_, StrEq(kData2), _, _)).
+ EXPECT_CALL(session_, WriteData(_, _, _, _)).
+ WillOnce(Return(QuicConsumedData(kDataLen - 2, false)));
+ stream_.OnCanWrite();
+
+ // And finally the end of the bytes_consumed
+ //EXPECT_CALL(session_, WriteData(_, StrEq(&kData2[kDataLen - 2]), _, _)).
+ EXPECT_CALL(session_, WriteData(_, _, _, _)).
+ WillOnce(Return(QuicConsumedData(2, true)));
+ stream_.OnCanWrite();
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc
index 1411e5b..7befa32 100644
--- a/net/quic/test_tools/quic_connection_peer.cc
+++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -4,9 +4,10 @@
#include "net/quic/test_tools/quic_connection_peer.h"
+#include "base/stl_util.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/congestion_control/receive_algorithm_interface.h"
+#include "net/quic/congestion_control/send_algorithm_interface.h"
#include "net/quic/quic_connection.h"
namespace net {
@@ -18,15 +19,17 @@ void QuicConnectionPeer::SendAck(QuicConnection* connection) {
}
// static
-void QuicConnectionPeer::SetCollector(QuicConnection* connection,
- QuicReceiptMetricsCollector* collector) {
- connection->congestion_manager_.collector_.reset(collector);
+void QuicConnectionPeer::SetReceiveAlgorithm(
+ QuicConnection* connection,
+ ReceiveAlgorithmInterface* receive_algorithm) {
+ connection->congestion_manager_.receive_algorithm_.reset(receive_algorithm);
}
// static
-void QuicConnectionPeer::SetScheduler(QuicConnection* connection,
- QuicSendScheduler* scheduler) {
- connection->congestion_manager_.scheduler_.reset(scheduler);
+void QuicConnectionPeer::SetSendAlgorithm(
+ QuicConnection* connection,
+ SendAlgorithmInterface* send_algorithm) {
+ connection->congestion_manager_.send_algorithm_.reset(send_algorithm);
}
// static
@@ -50,5 +53,27 @@ bool QuicConnectionPeer::GetReceivedTruncatedAck(QuicConnection* connection) {
return connection->received_truncated_ack_;
}
+// static
+size_t QuicConnectionPeer::GetNumRetransmissionTimeouts(
+ QuicConnection* connection) {
+ return connection->retransmission_timeouts_.size();
+}
+
+// static
+bool QuicConnectionPeer::IsSavedForRetransmission(
+ QuicConnection* connection,
+ QuicPacketSequenceNumber sequence_number) {
+ return ContainsKey(connection->retransmission_map_, sequence_number);
+}
+
+// static
+size_t QuicConnectionPeer::GetRetransmissionCount(
+ QuicConnection* connection,
+ QuicPacketSequenceNumber sequence_number) {
+ QuicConnection::RetransmissionMap::iterator it =
+ connection->retransmission_map_.find(sequence_number);
+ return it->second.number_retransmissions;
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h
index 46b20929..deb313e0 100644
--- a/net/quic/test_tools/quic_connection_peer.h
+++ b/net/quic/test_tools/quic_connection_peer.h
@@ -6,6 +6,7 @@
#define NET_QUIC_TEST_TOOLS_QUIC_CONNECTION_PEER_H_
#include "base/basictypes.h"
+#include "net/quic/quic_protocol.h"
namespace net {
@@ -13,8 +14,8 @@ struct QuicAckFrame;
class QuicConnection;
class QuicConnectionVisitorInterface;
class QuicPacketCreator;
-class QuicReceiptMetricsCollector;
-class QuicSendScheduler;
+class ReceiveAlgorithmInterface;
+class SendAlgorithmInterface;
namespace test {
@@ -23,11 +24,11 @@ class QuicConnectionPeer {
public:
static void SendAck(QuicConnection* connection);
- static void SetCollector(QuicConnection* connection,
- QuicReceiptMetricsCollector* collector);
+ static void SetReceiveAlgorithm(QuicConnection* connection,
+ ReceiveAlgorithmInterface* receive_algorithm);
- static void SetScheduler(QuicConnection* connection,
- QuicSendScheduler* scheduler);
+ static void SetSendAlgorithm(QuicConnection* connection,
+ SendAlgorithmInterface* send_algorithm);
static QuicAckFrame* GetOutgoingAck(QuicConnection* connection);
@@ -38,6 +39,16 @@ class QuicConnectionPeer {
static bool GetReceivedTruncatedAck(QuicConnection* connection);
+ static size_t GetNumRetransmissionTimeouts(QuicConnection* connection);
+
+ static bool IsSavedForRetransmission(
+ QuicConnection* connection,
+ QuicPacketSequenceNumber sequence_number);
+
+ static size_t GetRetransmissionCount(
+ QuicConnection* connection,
+ QuicPacketSequenceNumber sequence_number);
+
private:
DISALLOW_COPY_AND_ASSIGN(QuicConnectionPeer);
};
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 634218f..c53f797 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -50,6 +50,17 @@ void FramerVisitorCapturingAcks::OnCongestionFeedbackFrame(
feedback_.reset(new QuicCongestionFeedbackFrame(frame));
}
+FramerVisitorCapturingPublicReset::FramerVisitorCapturingPublicReset() {
+}
+
+FramerVisitorCapturingPublicReset::~FramerVisitorCapturingPublicReset() {
+}
+
+void FramerVisitorCapturingPublicReset::OnPublicResetPacket(
+ const QuicPublicResetPacket& public_reset) {
+ public_reset_packet_ = public_reset;
+}
+
MockConnectionVisitor::MockConnectionVisitor() {
}
@@ -94,11 +105,10 @@ PacketSavingConnection::~PacketSavingConnection() {
STLDeleteElements(&packets_);
}
-bool PacketSavingConnection::SendPacket(QuicPacketSequenceNumber number,
- QuicPacket* packet,
- bool should_retransmit,
- bool force,
- bool is_retransmission) {
+bool PacketSavingConnection::SendOrQueuePacket(
+ QuicPacketSequenceNumber sequence_number,
+ QuicPacket* packet,
+ bool force) {
packets_.push_back(packet);
return true;
}
@@ -112,11 +122,10 @@ MockSession::MockSession(QuicConnection* connection, bool is_server)
MockSession::~MockSession() {
}
-MockScheduler::MockScheduler()
- : QuicSendScheduler(NULL, kFixRate) {
+MockSendAlgorithm::MockSendAlgorithm() {
}
-MockScheduler::~MockScheduler() {
+MockSendAlgorithm::~MockSendAlgorithm() {
}
namespace {
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 0b2a67a..a269693 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -7,7 +7,7 @@
#ifndef NET_QUIC_TEST_TOOLS_QUIC_TEST_UTILS_H_
#define NET_QUIC_TEST_TOOLS_QUIC_TEST_UTILS_H_
-#include "net/quic/congestion_control/quic_send_scheduler.h"
+#include "net/quic/congestion_control/send_algorithm_interface.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_framer.h"
#include "net/quic/quic_session.h"
@@ -49,8 +49,7 @@ class MockFramerVisitor : public QuicFramerVisitorInterface {
~MockFramerVisitor();
MOCK_METHOD1(OnError, void(QuicFramer* framer));
- MOCK_METHOD2(OnPacket, void(const IPEndPoint& self_address,
- const IPEndPoint& peer_address));
+ MOCK_METHOD0(OnPacket, void());
MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket& header));
MOCK_METHOD0(OnRevivedPacket, void());
// The constructor set this up to return true by default.
@@ -75,8 +74,7 @@ class NoOpFramerVisitor : public QuicFramerVisitorInterface {
NoOpFramerVisitor() {}
virtual void OnError(QuicFramer* framer) OVERRIDE {}
- virtual void OnPacket(const IPEndPoint& self_address,
- const IPEndPoint& peer_address) OVERRIDE {}
+ virtual void OnPacket() OVERRIDE {}
virtual void OnPublicResetPacket(
const QuicPublicResetPacket& packet) OVERRIDE {}
virtual void OnRevivedPacket() OVERRIDE {}
@@ -120,6 +118,22 @@ class FramerVisitorCapturingAcks : public NoOpFramerVisitor {
DISALLOW_COPY_AND_ASSIGN(FramerVisitorCapturingAcks);
};
+class FramerVisitorCapturingPublicReset : public NoOpFramerVisitor {
+ public:
+ FramerVisitorCapturingPublicReset();
+ virtual ~FramerVisitorCapturingPublicReset();
+
+ virtual void OnPublicResetPacket(
+ const QuicPublicResetPacket& packet) OVERRIDE;
+
+ const QuicPublicResetPacket public_reset_packet() {
+ return public_reset_packet_;
+ }
+
+ private:
+ QuicPublicResetPacket public_reset_packet_;
+};
+
class MockConnectionVisitor : public QuicConnectionVisitorInterface {
public:
MockConnectionVisitor();
@@ -190,11 +204,9 @@ class PacketSavingConnection : public MockConnection {
PacketSavingConnection(QuicGuid guid, IPEndPoint address);
virtual ~PacketSavingConnection();
- virtual bool SendPacket(QuicPacketSequenceNumber number,
- QuicPacket* packet,
- bool should_retransmit,
- bool force,
- bool is_retransmission) OVERRIDE;
+ virtual bool SendOrQueuePacket(QuicPacketSequenceNumber sequence_number,
+ QuicPacket* packet,
+ bool force) OVERRIDE;
std::vector<QuicPacket*> packets_;
@@ -226,17 +238,22 @@ class MockSession : public QuicSession {
DISALLOW_COPY_AND_ASSIGN(MockSession);
};
-class MockScheduler : public QuicSendScheduler {
+class MockSendAlgorithm : public SendAlgorithmInterface {
public:
- MockScheduler();
- virtual ~MockScheduler();
-
+ MockSendAlgorithm();
+ virtual ~MockSendAlgorithm();
+
+ MOCK_METHOD2(OnIncomingQuicCongestionFeedbackFrame,
+ void(const QuicCongestionFeedbackFrame&, const SentPacketsMap&));
+ MOCK_METHOD3(OnIncomingAck,
+ void(QuicPacketSequenceNumber, QuicByteCount, QuicTime::Delta));
+ MOCK_METHOD1(OnIncomingLoss, void(int number_of_lost_packets));
+ MOCK_METHOD3(SentPacket, void(QuicPacketSequenceNumber, QuicByteCount, bool));
MOCK_METHOD1(TimeUntilSend, QuicTime::Delta(bool));
- MOCK_METHOD1(OnIncomingAckFrame, void(const QuicAckFrame&));
- MOCK_METHOD3(SentPacket, void(QuicPacketSequenceNumber, size_t, bool));
+ MOCK_METHOD0(BandwidthEstimate, QuicBandwidth(void));
private:
- DISALLOW_COPY_AND_ASSIGN(MockScheduler);
+ DISALLOW_COPY_AND_ASSIGN(MockSendAlgorithm);
};
} // namespace test