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