Merge from Chromium at DEPS revision 275586
This commit was generated by merge_to_master.py.
Change-Id: Ief3a0ffd810858bfddbe0ec5931e3ee90d53f78c
diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc
index 8027205..c346a63 100644
--- a/net/quic/congestion_control/fix_rate_sender.cc
+++ b/net/quic/congestion_control/fix_rate_sender.cc
@@ -26,7 +26,6 @@
bitrate_(QuicBandwidth::FromBytesPerSecond(kInitialBitrate)),
max_segment_size_(kDefaultMaxPacketSize),
fix_rate_leaky_bucket_(bitrate_),
- paced_sender_(bitrate_, max_segment_size_),
latest_rtt_(QuicTime::Delta::Zero()) {
DVLOG(1) << "FixRateSender";
}
@@ -45,7 +44,6 @@
if (feedback.type == kFixRate) {
bitrate_ = feedback.fix_rate.bitrate;
fix_rate_leaky_bucket_.SetDrainingRate(feedback_receive_time, bitrate_);
- paced_sender_.UpdateBandwidthEstimate(feedback_receive_time, bitrate_);
}
// Silently ignore invalid messages in release mode.
}
@@ -63,7 +61,6 @@
QuicByteCount bytes,
HasRetransmittableData /*has_retransmittable_data*/) {
fix_rate_leaky_bucket_.Add(sent_time, bytes);
- paced_sender_.OnPacketSent(sent_time, bytes);
return true;
}
@@ -72,24 +69,12 @@
QuicTime::Delta FixRateSender::TimeUntilSend(
QuicTime now,
- QuicByteCount bytes_in_flight,
- HasRetransmittableData /*has_retransmittable_data*/) {
- if (CongestionWindow() > fix_rate_leaky_bucket_.BytesPending(now)) {
- if (CongestionWindow() <= bytes_in_flight) {
- // We need an ack before we send more.
- return QuicTime::Delta::Infinite();
- }
- return paced_sender_.TimeUntilSend(now, QuicTime::Delta::Zero());
- }
- QuicTime::Delta time_remaining = fix_rate_leaky_bucket_.TimeRemaining(now);
- if (time_remaining.IsZero()) {
- // We need an ack before we send more.
- return QuicTime::Delta::Infinite();
- }
- return paced_sender_.TimeUntilSend(now, time_remaining);
+ QuicByteCount /*bytes_in_flight*/,
+ HasRetransmittableData /*has_retransmittable_data*/) const {
+ return fix_rate_leaky_bucket_.TimeRemaining(now);
}
-QuicByteCount FixRateSender::CongestionWindow() {
+QuicByteCount FixRateSender::CongestionWindow() const {
QuicByteCount window_size_bytes = bitrate_.ToBytesPerPeriod(
QuicTime::Delta::FromMicroseconds(kWindowSizeUs));
// Make sure window size is not less than a packet.
diff --git a/net/quic/congestion_control/fix_rate_sender.h b/net/quic/congestion_control/fix_rate_sender.h
index 6f85090..3cb07ff 100644
--- a/net/quic/congestion_control/fix_rate_sender.h
+++ b/net/quic/congestion_control/fix_rate_sender.h
@@ -14,7 +14,6 @@
#include "net/quic/quic_connection_stats.h"
#include "net/quic/quic_time.h"
#include "net/quic/congestion_control/leaky_bucket.h"
-#include "net/quic/congestion_control/paced_sender.h"
#include "net/quic/congestion_control/send_algorithm_interface.h"
namespace net {
@@ -45,20 +44,19 @@
virtual QuicTime::Delta TimeUntilSend(
QuicTime now,
QuicByteCount bytes_in_flight,
- HasRetransmittableData has_retransmittable_data) OVERRIDE;
+ HasRetransmittableData has_retransmittable_data) const OVERRIDE;
virtual QuicBandwidth BandwidthEstimate() const OVERRIDE;
virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE;
virtual QuicByteCount GetCongestionWindow() const OVERRIDE;
// End implementation of SendAlgorithmInterface.
private:
- QuicByteCount CongestionWindow();
+ QuicByteCount CongestionWindow() const;
const RttStats* rtt_stats_;
QuicBandwidth bitrate_;
QuicByteCount max_segment_size_;
LeakyBucket fix_rate_leaky_bucket_;
- PacedSender paced_sender_;
QuicTime::Delta latest_rtt_;
DISALLOW_COPY_AND_ASSIGN(FixRateSender);
diff --git a/net/quic/congestion_control/fix_rate_test.cc b/net/quic/congestion_control/fix_rate_test.cc
index e696823..c82bb60 100644
--- a/net/quic/congestion_control/fix_rate_test.cc
+++ b/net/quic/congestion_control/fix_rate_test.cc
@@ -68,59 +68,33 @@
sender_->OnPacketSent(clock_.Now(), kUnused, 1, kDefaultMaxPacketSize,
HAS_RETRANSMITTABLE_DATA);
+ EXPECT_FALSE(sender_->TimeUntilSend(clock_.Now(),
+ kDefaultMaxPacketSize,
+ HAS_RETRANSMITTABLE_DATA).IsZero());
+ clock_.AdvanceTime(sender_->TimeUntilSend(clock_.Now(),
+ kDefaultMaxPacketSize,
+ HAS_RETRANSMITTABLE_DATA));
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
kDefaultMaxPacketSize,
HAS_RETRANSMITTABLE_DATA).IsZero());
sender_->OnPacketSent(clock_.Now(), kUnused, 2, kDefaultMaxPacketSize,
HAS_RETRANSMITTABLE_DATA);
- sender_->OnPacketSent(clock_.Now(), kUnused, 3, 600,
- HAS_RETRANSMITTABLE_DATA);
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
- sender_->TimeUntilSend(clock_.Now(),
- kDefaultMaxPacketSize * 2 + 600,
- HAS_RETRANSMITTABLE_DATA));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2));
- EXPECT_EQ(QuicTime::Delta::Infinite(),
- sender_->TimeUntilSend(clock_.Now(),
- kDefaultMaxPacketSize * 2 + 600,
- HAS_RETRANSMITTABLE_DATA));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8));
+ EXPECT_FALSE(sender_->TimeUntilSend(clock_.Now(),
+ kDefaultMaxPacketSize,
+ HAS_RETRANSMITTABLE_DATA).IsZero());
+ // Advance the time twice as much and expect only one packet to be sent.
+ clock_.AdvanceTime(sender_->TimeUntilSend(
+ clock_.Now(),
+ kDefaultMaxPacketSize,
+ HAS_RETRANSMITTABLE_DATA).Multiply(2));
EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- 0,
+ kDefaultMaxPacketSize,
HAS_RETRANSMITTABLE_DATA).IsZero());
-}
-
-TEST_F(FixRateTest, FixRatePacing) {
- const QuicByteCount packet_size = 1200;
- const QuicBandwidth bitrate = QuicBandwidth::FromKBytesPerSecond(240);
- const int64 num_packets = 200;
- QuicCongestionFeedbackFrame feedback;
- receiver_->SetBitrate(QuicBandwidth::FromKBytesPerSecond(240));
- ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
- sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
- QuicTime acc_advance_time(QuicTime::Zero());
- QuicPacketSequenceNumber sequence_number = 0;
- for (int i = 0; i < num_packets; i += 2) {
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- 0,
- HAS_RETRANSMITTABLE_DATA).IsZero());
- sender_->OnPacketSent(clock_.Now(), kUnused, sequence_number++, packet_size,
- HAS_RETRANSMITTABLE_DATA);
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
- kDefaultMaxPacketSize,
- HAS_RETRANSMITTABLE_DATA).IsZero());
- sender_->OnPacketSent(clock_.Now(), kUnused, sequence_number++, packet_size,
- HAS_RETRANSMITTABLE_DATA);
- QuicTime::Delta advance_time =
- sender_->TimeUntilSend(clock_.Now(),
- 2 * kDefaultMaxPacketSize,
- HAS_RETRANSMITTABLE_DATA);
- clock_.AdvanceTime(advance_time);
- acc_advance_time = acc_advance_time.Add(advance_time);
- }
- EXPECT_EQ(num_packets * packet_size * 1000000 / bitrate.ToBytesPerSecond(),
- static_cast<uint64>(acc_advance_time.Subtract(start_)
- .ToMicroseconds()));
+ sender_->OnPacketSent(clock_.Now(), kUnused, 3, kDefaultMaxPacketSize,
+ HAS_RETRANSMITTABLE_DATA);
+ EXPECT_FALSE(sender_->TimeUntilSend(clock_.Now(),
+ kDefaultMaxPacketSize,
+ HAS_RETRANSMITTABLE_DATA).IsZero());
}
} // namespace test
diff --git a/net/quic/congestion_control/leaky_bucket.cc b/net/quic/congestion_control/leaky_bucket.cc
index 06c1f87..f3972f6 100644
--- a/net/quic/congestion_control/leaky_bucket.cc
+++ b/net/quic/congestion_control/leaky_bucket.cc
@@ -24,11 +24,15 @@
bytes_ += bytes;
}
-QuicTime::Delta LeakyBucket::TimeRemaining(QuicTime now) {
- Update(now);
- return QuicTime::Delta::FromMicroseconds(
+QuicTime::Delta LeakyBucket::TimeRemaining(QuicTime now) const {
+ QuicTime::Delta time_since_last_update = now.Subtract(time_last_updated_);
+ QuicTime::Delta send_delay = QuicTime::Delta::FromMicroseconds(
(bytes_ * base::Time::kMicrosecondsPerSecond) /
draining_rate_.ToBytesPerSecond());
+ if (send_delay < time_since_last_update) {
+ return QuicTime::Delta::Zero();
+ }
+ return send_delay.Subtract(time_since_last_update);
}
QuicByteCount LeakyBucket::BytesPending(QuicTime now) {
diff --git a/net/quic/congestion_control/leaky_bucket.h b/net/quic/congestion_control/leaky_bucket.h
index 8717620..eb4cdb0 100644
--- a/net/quic/congestion_control/leaky_bucket.h
+++ b/net/quic/congestion_control/leaky_bucket.h
@@ -29,7 +29,7 @@
void Add(QuicTime now, QuicByteCount bytes);
// Time until the buffer is empty.
- QuicTime::Delta TimeRemaining(QuicTime now);
+ QuicTime::Delta TimeRemaining(QuicTime now) const;
// Number of bytes in the buffer.
QuicByteCount BytesPending(QuicTime now);
diff --git a/net/quic/congestion_control/paced_sender.cc b/net/quic/congestion_control/paced_sender.cc
deleted file mode 100644
index 87042a5..0000000
--- a/net/quic/congestion_control/paced_sender.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/congestion_control/paced_sender.h"
-
-#include <algorithm>
-
-#include "net/quic/quic_protocol.h"
-
-using std::max;
-
-namespace net {
-
-// To prevent too aggressive pacing we allow the following packet burst size.
-const int64 kMinPacketBurstSize = 2;
-// Max estimated time between calls to TimeUntilSend and
-// AvailableCongestionWindow.
-const int64 kMaxSchedulingDelayUs = 2000;
-
-PacedSender::PacedSender(QuicBandwidth estimate, QuicByteCount max_segment_size)
- : leaky_bucket_(estimate),
- pace_(estimate),
- max_segment_size_(kDefaultMaxPacketSize) {
-}
-
-void PacedSender::UpdateBandwidthEstimate(QuicTime now,
- QuicBandwidth estimate) {
- leaky_bucket_.SetDrainingRate(now, estimate);
- pace_ = estimate;
-}
-
-void PacedSender::OnPacketSent(QuicTime now, QuicByteCount bytes) {
- leaky_bucket_.Add(now, bytes);
-}
-
-QuicTime::Delta PacedSender::TimeUntilSend(QuicTime now,
- QuicTime::Delta time_until_send) {
- if (time_until_send.ToMicroseconds() >= kMaxSchedulingDelayUs) {
- return time_until_send;
- }
- // Pace the data.
- QuicByteCount pacing_window = pace_.ToBytesPerPeriod(
- QuicTime::Delta::FromMicroseconds(kMaxSchedulingDelayUs));
- QuicByteCount min_window_size = kMinPacketBurstSize * max_segment_size_;
- pacing_window = max(pacing_window, min_window_size);
-
- if (pacing_window > leaky_bucket_.BytesPending(now)) {
- // We have not filled our pacing window yet.
- return time_until_send;
- }
- return leaky_bucket_.TimeRemaining(now);
-}
-
-} // namespace net
diff --git a/net/quic/congestion_control/paced_sender.h b/net/quic/congestion_control/paced_sender.h
deleted file mode 100644
index d600dcb..0000000
--- a/net/quic/congestion_control/paced_sender.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// Helper class that limits the congestion window to pace the packets.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_PACED_SENDER_H_
-#define NET_QUIC_CONGESTION_CONTROL_PACED_SENDER_H_
-
-#include "base/basictypes.h"
-#include "net/base/net_export.h"
-#include "net/quic/congestion_control/leaky_bucket.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE PacedSender {
- public:
- PacedSender(QuicBandwidth bandwidth_estimate, QuicByteCount max_segment_size);
-
- // The estimated bandidth from the congestion algorithm changed.
- void UpdateBandwidthEstimate(QuicTime now, QuicBandwidth bandwidth_estimate);
-
- // A packet of size bytes was sent.
- void OnPacketSent(QuicTime now, QuicByteCount bytes);
-
- // Return time until we can send based on the pacing.
- QuicTime::Delta TimeUntilSend(QuicTime now, QuicTime::Delta time_until_send);
-
- private:
- // Helper object to track the rate data can leave the buffer for pacing.
- LeakyBucket leaky_bucket_;
- QuicBandwidth pace_;
- QuicByteCount max_segment_size_;
-
- DISALLOW_COPY_AND_ASSIGN(PacedSender);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_PACED_SENDER_H_
diff --git a/net/quic/congestion_control/paced_sender_test.cc b/net/quic/congestion_control/paced_sender_test.cc
deleted file mode 100644
index fa42c2c..0000000
--- a/net/quic/congestion_control/paced_sender_test.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "net/quic/congestion_control/paced_sender.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-const int kHundredKBytesPerS = 100;
-
-class PacedSenderTest : public ::testing::Test {
- protected:
- PacedSenderTest()
- : zero_time_(QuicTime::Delta::Zero()),
- paced_sender_(new PacedSender(
- QuicBandwidth::FromKBytesPerSecond(kHundredKBytesPerS),
- kDefaultMaxPacketSize)) {
- }
-
- const QuicTime::Delta zero_time_;
- MockClock clock_;
- scoped_ptr<PacedSender> paced_sender_;
-};
-
-TEST_F(PacedSenderTest, Basic) {
- paced_sender_->UpdateBandwidthEstimate(clock_.Now(),
- QuicBandwidth::FromKBytesPerSecond(kHundredKBytesPerS * 10));
- EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero());
- paced_sender_->OnPacketSent(clock_.Now(), kDefaultMaxPacketSize);
- EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero());
- paced_sender_->OnPacketSent(clock_.Now(), kDefaultMaxPacketSize);
- EXPECT_EQ(static_cast<int64>(kDefaultMaxPacketSize * 2),
- paced_sender_->TimeUntilSend(
- clock_.Now(), zero_time_).ToMicroseconds());
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(24));
- EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero());
-}
-
-TEST_F(PacedSenderTest, LowRate) {
- paced_sender_->UpdateBandwidthEstimate(clock_.Now(),
- QuicBandwidth::FromKBytesPerSecond(kHundredKBytesPerS));
- EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero());
- paced_sender_->OnPacketSent(clock_.Now(), kDefaultMaxPacketSize);
- EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero());
- paced_sender_->OnPacketSent(clock_.Now(), kDefaultMaxPacketSize);
- EXPECT_EQ(static_cast<int64>(kDefaultMaxPacketSize * 20),
- paced_sender_->TimeUntilSend(
- clock_.Now(), zero_time_).ToMicroseconds());
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(24));
- EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero());
-}
-
-TEST_F(PacedSenderTest, HighRate) {
- QuicBandwidth bandwidth_estimate = QuicBandwidth::FromKBytesPerSecond(
- kHundredKBytesPerS * 100);
- paced_sender_->UpdateBandwidthEstimate(clock_.Now(), bandwidth_estimate);
- EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero());
- for (int i = 0; i < 16; ++i) {
- paced_sender_->OnPacketSent(clock_.Now(), kDefaultMaxPacketSize);
- EXPECT_TRUE(paced_sender_->TimeUntilSend(
- clock_.Now(), zero_time_).IsZero());
- }
- paced_sender_->OnPacketSent(clock_.Now(), kDefaultMaxPacketSize);
- EXPECT_EQ(2040, paced_sender_->TimeUntilSend(
- clock_.Now(), zero_time_).ToMicroseconds());
- clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(20400));
- EXPECT_TRUE(paced_sender_->TimeUntilSend(clock_.Now(), zero_time_).IsZero());
-}
-
-} // namespace test
-} // namespace net
diff --git a/net/quic/congestion_control/pacing_sender.cc b/net/quic/congestion_control/pacing_sender.cc
index c487d2a..97138f7 100644
--- a/net/quic/congestion_control/pacing_sender.cc
+++ b/net/quic/congestion_control/pacing_sender.cc
@@ -10,6 +10,7 @@
QuicTime::Delta alarm_granularity)
: sender_(sender),
alarm_granularity_(alarm_granularity),
+ last_delayed_packet_sent_time_(QuicTime::Zero()),
next_packet_send_time_(QuicTime::Zero()),
was_last_send_delayed_(false),
has_valid_rtt_(false) {
@@ -54,7 +55,30 @@
const float kPacingAggression = 2;
QuicTime::Delta delay =
BandwidthEstimate().Scale(kPacingAggression).TransferTime(bytes);
- next_packet_send_time_ = next_packet_send_time_.Add(delay);
+ // If the last send was delayed, and the alarm took a long time to get
+ // invoked, allow the connection to make up for lost time.
+ if (was_last_send_delayed_) {
+ next_packet_send_time_ = next_packet_send_time_.Add(delay);
+ // The send was application limited if it takes longer than the
+ // pacing delay between sent packets.
+ const bool application_limited =
+ last_delayed_packet_sent_time_.IsInitialized() &&
+ sent_time > last_delayed_packet_sent_time_.Add(delay);
+ const bool making_up_for_lost_time = next_packet_send_time_ <= sent_time;
+ // As long as we're making up time and not application limited,
+ // continue to consider the packets delayed, allowing the packets to be
+ // sent immediately.
+ if (making_up_for_lost_time && !application_limited) {
+ last_delayed_packet_sent_time_ = sent_time;
+ } else {
+ was_last_send_delayed_ = false;
+ last_delayed_packet_sent_time_ = QuicTime::Zero();
+ }
+ } else {
+ next_packet_send_time_ =
+ QuicTime::Max(next_packet_send_time_.Add(delay),
+ sent_time.Add(delay).Subtract(alarm_granularity_));
+ }
}
return sender_->OnPacketSent(sent_time, bytes_in_flight, sequence_number,
bytes, has_retransmittable_data);
@@ -67,7 +91,7 @@
QuicTime::Delta PacingSender::TimeUntilSend(
QuicTime now,
QuicByteCount bytes_in_flight,
- HasRetransmittableData has_retransmittable_data) {
+ HasRetransmittableData has_retransmittable_data) const {
QuicTime::Delta time_until_send =
sender_->TimeUntilSend(now, bytes_in_flight, has_retransmittable_data);
if (!has_valid_rtt_) {
@@ -87,25 +111,14 @@
return QuicTime::Delta::Zero();
}
- if (!was_last_send_delayed_ &&
- (!next_packet_send_time_.IsInitialized() ||
- now > next_packet_send_time_.Add(alarm_granularity_))) {
- // An alarm did not go off late, instead the application is "slow"
- // delivering data. In this case, we restrict the amount of lost time
- // that we can make up for.
- next_packet_send_time_ = now.Subtract(alarm_granularity_);
- }
-
- // If the end of the epoch is far enough in the future, delay the send.
+ // If the next send time is within the alarm granularity, send immediately.
if (next_packet_send_time_ > now.Add(alarm_granularity_)) {
- was_last_send_delayed_ = true;
DVLOG(1) << "Delaying packet: "
<< next_packet_send_time_.Subtract(now).ToMicroseconds();
+ was_last_send_delayed_ = true;
return next_packet_send_time_.Subtract(now);
}
- // Sent it immediately. The epoch end will be adjusted in OnPacketSent.
- was_last_send_delayed_ = false;
DVLOG(1) << "Sending packet now";
return QuicTime::Delta::Zero();
}
diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h
index b1060ac..c741771 100644
--- a/net/quic/congestion_control/pacing_sender.h
+++ b/net/quic/congestion_control/pacing_sender.h
@@ -47,7 +47,7 @@
virtual QuicTime::Delta TimeUntilSend(
QuicTime now,
QuicByteCount bytes_in_flight,
- HasRetransmittableData has_retransmittable_data) OVERRIDE;
+ HasRetransmittableData has_retransmittable_data) const OVERRIDE;
virtual QuicBandwidth BandwidthEstimate() const OVERRIDE;
virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE;
virtual QuicByteCount GetCongestionWindow() const OVERRIDE;
@@ -55,8 +55,10 @@
private:
scoped_ptr<SendAlgorithmInterface> sender_; // Underlying sender.
QuicTime::Delta alarm_granularity_;
+ // Send time of the last packet considered delayed.
+ QuicTime last_delayed_packet_sent_time_;
QuicTime next_packet_send_time_; // When can the next packet be sent.
- bool was_last_send_delayed_; // True when the last send was delayed.
+ mutable bool was_last_send_delayed_; // True when the last send was delayed.
bool has_valid_rtt_; // True if we have at least one RTT update.
DISALLOW_COPY_AND_ASSIGN(PacingSender);
diff --git a/net/quic/congestion_control/pacing_sender_test.cc b/net/quic/congestion_control/pacing_sender_test.cc
index 38e5d02..2dc6960 100644
--- a/net/quic/congestion_control/pacing_sender_test.cc
+++ b/net/quic/congestion_control/pacing_sender_test.cc
@@ -38,15 +38,17 @@
void CheckPacketIsSentImmediately() {
// In order for the packet to be sendable, the underlying sender must
// permit it to be sent immediately.
- EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(),
- kBytesInFlight,
- HAS_RETRANSMITTABLE_DATA))
- .WillOnce(Return(zero_time_));
- // Verify that the packet can be sent immediately.
- EXPECT_EQ(zero_time_,
- pacing_sender_->TimeUntilSend(clock_.Now(),
- kBytesInFlight,
- HAS_RETRANSMITTABLE_DATA));
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
+ HAS_RETRANSMITTABLE_DATA))
+ .WillOnce(Return(zero_time_));
+ // Verify that the packet can be sent immediately.
+ EXPECT_EQ(zero_time_,
+ pacing_sender_->TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
+ HAS_RETRANSMITTABLE_DATA));
+ }
// Actually send the packet.
EXPECT_CALL(*mock_sender_,
@@ -82,15 +84,17 @@
void CheckPacketIsDelayed(QuicTime::Delta delay) {
// In order for the packet to be sendable, the underlying sender must
// permit it to be sent immediately.
- EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(),
- kBytesInFlight,
- HAS_RETRANSMITTABLE_DATA))
- .WillOnce(Return(zero_time_));
- // Verify that the packet is delayed.
- EXPECT_EQ(delay.ToMicroseconds(),
- pacing_sender_->TimeUntilSend(
- clock_.Now(), kBytesInFlight,
- HAS_RETRANSMITTABLE_DATA).ToMicroseconds());
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
+ HAS_RETRANSMITTABLE_DATA))
+ .WillOnce(Return(zero_time_));
+ // Verify that the packet is delayed.
+ EXPECT_EQ(delay.ToMicroseconds(),
+ pacing_sender_->TimeUntilSend(
+ clock_.Now(), kBytesInFlight,
+ HAS_RETRANSMITTABLE_DATA).ToMicroseconds());
+ }
}
const QuicTime::Delta zero_time_;
@@ -102,25 +106,29 @@
};
TEST_F(PacingSenderTest, NoSend) {
- EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(),
- kBytesInFlight,
- HAS_RETRANSMITTABLE_DATA))
- .WillOnce(Return(infinite_time_));
- EXPECT_EQ(infinite_time_,
- pacing_sender_->TimeUntilSend(clock_.Now(),
- kBytesInFlight,
- HAS_RETRANSMITTABLE_DATA));
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
+ HAS_RETRANSMITTABLE_DATA))
+ .WillOnce(Return(infinite_time_));
+ EXPECT_EQ(infinite_time_,
+ pacing_sender_->TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
+ HAS_RETRANSMITTABLE_DATA));
+ }
}
TEST_F(PacingSenderTest, SendNow) {
- EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(),
- kBytesInFlight,
- HAS_RETRANSMITTABLE_DATA))
- .WillOnce(Return(zero_time_));
- EXPECT_EQ(zero_time_,
- pacing_sender_->TimeUntilSend(clock_.Now(),
- kBytesInFlight,
- HAS_RETRANSMITTABLE_DATA));
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
+ HAS_RETRANSMITTABLE_DATA))
+ .WillOnce(Return(zero_time_));
+ EXPECT_EQ(zero_time_,
+ pacing_sender_->TimeUntilSend(clock_.Now(),
+ kBytesInFlight,
+ HAS_RETRANSMITTABLE_DATA));
+ }
}
TEST_F(PacingSenderTest, VariousSending) {
@@ -163,6 +171,29 @@
CheckPacketIsSentImmediately();
CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+ // Wake up really late.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+
+ // Wake up really late again, but application pause partway through.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+
// Wake up too early.
CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index 12cf8f6..6b1c755 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -71,7 +71,7 @@
virtual QuicTime::Delta TimeUntilSend(
QuicTime now,
QuicByteCount bytes_in_flight,
- HasRetransmittableData has_retransmittable_data) = 0;
+ HasRetransmittableData has_retransmittable_data) const = 0;
// What's the current estimated bandwidth in bytes per second.
// Returns 0 when it does not have an estimate.
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index aaec6a4..19f07d4 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -170,7 +170,7 @@
QuicTime::Delta TcpCubicSender::TimeUntilSend(
QuicTime /* now */,
QuicByteCount bytes_in_flight,
- HasRetransmittableData has_retransmittable_data) {
+ HasRetransmittableData has_retransmittable_data) const {
if (has_retransmittable_data == NO_RETRANSMITTABLE_DATA) {
// For TCP we can always send an ACK immediately.
return QuicTime::Delta::Zero();
@@ -184,7 +184,7 @@
return QuicTime::Delta::Infinite();
}
-QuicByteCount TcpCubicSender::SendWindow() {
+QuicByteCount TcpCubicSender::SendWindow() const {
// What's the current send window in bytes.
return min(receive_window_, GetCongestionWindow());
}
@@ -294,7 +294,7 @@
}
QuicTime::Delta TcpCubicSender::PrrTimeUntilSend(
- QuicByteCount bytes_in_flight) {
+ QuicByteCount bytes_in_flight) const {
DCHECK(InRecovery());
// Return QuicTime::Zero In order to ensure limited transmit always works.
if (prr_out_ == 0) {
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index 12fd997..f9234c9 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -57,7 +57,7 @@
virtual QuicTime::Delta TimeUntilSend(
QuicTime now,
QuicByteCount bytes_in_flight,
- HasRetransmittableData has_retransmittable_data) OVERRIDE;
+ HasRetransmittableData has_retransmittable_data) const OVERRIDE;
virtual QuicBandwidth BandwidthEstimate() const OVERRIDE;
virtual QuicTime::Delta RetransmissionDelay() const OVERRIDE;
virtual QuicByteCount GetCongestionWindow() const OVERRIDE;
@@ -73,7 +73,7 @@
void OnPacketLost(QuicPacketSequenceNumber largest_loss,
QuicByteCount bytes_in_flight);
- QuicByteCount SendWindow();
+ QuicByteCount SendWindow() const;
void MaybeIncreaseCwnd(QuicPacketSequenceNumber acked_sequence_number,
QuicByteCount bytes_in_flight);
bool IsCwndLimited(QuicByteCount bytes_in_flight) const;
@@ -81,7 +81,7 @@
// Methods for isolating PRR from the rest of TCP Cubic.
void PrrOnPacketLost(QuicByteCount bytes_in_flight);
void PrrOnPacketAcked(QuicByteCount acked_bytes);
- QuicTime::Delta PrrTimeUntilSend(QuicByteCount bytes_in_flight);
+ QuicTime::Delta PrrTimeUntilSend(QuicByteCount bytes_in_flight) const;
HybridSlowStart hybrid_slow_start_;
diff --git a/net/quic/crypto/crypto_handshake_message.cc b/net/quic/crypto/crypto_handshake_message.cc
index f2cd696..9e08344 100644
--- a/net/quic/crypto/crypto_handshake_message.cc
+++ b/net/quic/crypto/crypto_handshake_message.cc
@@ -256,6 +256,7 @@
case kKEXS:
case kAEAD:
case kCGST:
+ case kCOPT:
case kLOSS:
case kPDMD:
case kVER:
@@ -300,6 +301,10 @@
static_cast<int>(it->second.size()));
done = true;
break;
+ case kUAID:
+ ret += it->second;
+ done = true;
+ break;
}
if (!done) {
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index c508147..c30ce44 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -47,6 +47,9 @@
const QuicTag kPACE = TAG('P', 'A', 'C', 'E'); // Paced TCP cubic
const QuicTag kINAR = TAG('I', 'N', 'A', 'R'); // Inter arrival
+// Congestion control options
+const QuicTag kTBBR = TAG('T', 'B', 'B', 'R'); // Reduced Buffer Bloat TCP
+
// Loss detection algorithm types
const QuicTag kNACK = TAG('N', 'A', 'C', 'K'); // TCP style nack counting
const QuicTag kTIME = TAG('T', 'I', 'M', 'E'); // Time based
@@ -68,6 +71,7 @@
// encryption algorithms
const QuicTag kCGST = TAG('C', 'G', 'S', 'T'); // Congestion control
// feedback types
+const QuicTag kCOPT = TAG('C', 'O', 'P', 'T'); // Congestion control options
// kLOSS was 'L', 'O', 'S', 'S', but was changed from a tag vector to a tag.
const QuicTag kLOSS = TAG('L', 'O', 'S', 'A'); // Loss detection algorithms
const QuicTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle connection state
@@ -89,6 +93,8 @@
const QuicTag kEXPY = TAG('E', 'X', 'P', 'Y'); // Expiry
const QuicTag kIFCW = TAG('I', 'F', 'C', 'W'); // Initial flow control receive
// window.
+const QuicTag kUAID = TAG('U', 'A', 'I', 'D'); // Client's User Agent ID.
+
// Server hello tags
const QuicTag kCADR = TAG('C', 'A', 'D', 'R'); // Client IP address and port
diff --git a/net/quic/crypto/proof_test.cc b/net/quic/crypto/proof_test.cc
index 31b2a60..56e9abc 100644
--- a/net/quic/crypto/proof_test.cc
+++ b/net/quic/crypto/proof_test.cc
@@ -70,22 +70,22 @@
TestProofVerifierCallback* callback =
new TestProofVerifierCallback(&comp_callback, &ok, &error_details);
- ProofVerifier::Status status = verifier->VerifyProof(
+ QuicAsyncStatus status = verifier->VerifyProof(
hostname, server_config, certs, proof, verify_context.get(),
&error_details, &details, callback);
switch (status) {
- case ProofVerifier::FAILURE:
+ case QUIC_FAILURE:
delete callback;
ASSERT_FALSE(expected_ok);
ASSERT_NE("", error_details);
return;
- case ProofVerifier::SUCCESS:
+ case QUIC_SUCCESS:
delete callback;
ASSERT_TRUE(expected_ok);
ASSERT_EQ("", error_details);
return;
- case ProofVerifier::PENDING:
+ case QUIC_PENDING:
comp_callback.WaitForResult();
ASSERT_EQ(expected_ok, ok);
break;
diff --git a/net/quic/crypto/proof_verifier.h b/net/quic/crypto/proof_verifier.h
index 779d63f..12bbb4c 100644
--- a/net/quic/crypto/proof_verifier.h
+++ b/net/quic/crypto/proof_verifier.h
@@ -10,6 +10,7 @@
#include "base/memory/scoped_ptr.h"
#include "net/base/net_export.h"
+#include "net/quic/quic_types.h"
namespace net {
@@ -49,42 +50,33 @@
// chain that backs the public key.
class NET_EXPORT_PRIVATE ProofVerifier {
public:
- // Status enumerates the possible results of verifying a proof.
- enum Status {
- SUCCESS = 0,
- FAILURE = 1,
- // PENDING results from a verification which will occur asynchonously. When
- // the verification is complete, |callback|'s |Run| method will be called.
- PENDING = 2,
- };
-
virtual ~ProofVerifier() {}
// VerifyProof checks that |signature| is a valid signature of
// |server_config| by the public key in the leaf certificate of |certs|, and
// that |certs| is a valid chain for |hostname|. On success, it returns
- // SUCCESS. On failure, it returns ERROR and sets |*error_details| to a
- // description of the problem. In either case it may set |*details|, which the
- // caller takes ownership of.
+ // QUIC_SUCCESS. On failure, it returns QUIC_ERROR and sets |*error_details|
+ // to a description of the problem. In either case it may set |*details|,
+ // which the caller takes ownership of.
//
// |context| specifies an implementation specific struct (which may be NULL
// for some implementations) that provides useful information for the
// verifier, e.g. logging handles.
//
- // This function may also return PENDING, in which case the ProofVerifier
+ // This function may also return QUIC_PENDING, in which case the ProofVerifier
// will call back, on the original thread, via |callback| when complete.
// In this case, the ProofVerifier will take ownership of |callback|.
//
// The signature uses SHA-256 as the hash function and PSS padding in the
// case of RSA.
- virtual Status VerifyProof(const std::string& hostname,
- const std::string& server_config,
- const std::vector<std::string>& certs,
- const std::string& signature,
- const ProofVerifyContext* context,
- std::string* error_details,
- scoped_ptr<ProofVerifyDetails>* details,
- ProofVerifierCallback* callback) = 0;
+ virtual QuicAsyncStatus VerifyProof(const std::string& hostname,
+ const std::string& server_config,
+ const std::vector<std::string>& certs,
+ const std::string& signature,
+ const ProofVerifyContext* context,
+ std::string* error_details,
+ scoped_ptr<ProofVerifyDetails>* details,
+ ProofVerifierCallback* callback) = 0;
};
} // namespace net
diff --git a/net/quic/crypto/proof_verifier_chromium.cc b/net/quic/crypto/proof_verifier_chromium.cc
index cbb4436..9829c97 100644
--- a/net/quic/crypto/proof_verifier_chromium.cc
+++ b/net/quic/crypto/proof_verifier_chromium.cc
@@ -42,13 +42,13 @@
// Starts the proof verification. If |PENDING| is returned, then |callback|
// will be invoked asynchronously when the verification completes.
- Status VerifyProof(const std::string& hostname,
- const std::string& server_config,
- const std::vector<std::string>& certs,
- const std::string& signature,
- std::string* error_details,
- scoped_ptr<ProofVerifyDetails>* verify_details,
- ProofVerifierCallback* callback);
+ QuicAsyncStatus VerifyProof(const std::string& hostname,
+ const std::string& server_config,
+ const std::vector<std::string>& certs,
+ const std::string& signature,
+ std::string* error_details,
+ scoped_ptr<ProofVerifyDetails>* verify_details,
+ ProofVerifierCallback* callback);
private:
enum State {
@@ -98,7 +98,7 @@
net_log_(net_log) {
}
-ProofVerifierChromium::Status ProofVerifierChromium::Job::VerifyProof(
+QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof(
const string& hostname,
const string& server_config,
const vector<string>& certs,
@@ -115,7 +115,7 @@
if (STATE_NONE != next_state_) {
*error_details = "Certificate is already set and VerifyProof has begun";
DLOG(DFATAL) << *error_details;
- return FAILURE;
+ return QUIC_FAILURE;
}
verify_details_.reset(new ProofVerifyDetailsChromium);
@@ -125,7 +125,7 @@
DLOG(WARNING) << *error_details;
verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
verify_details->reset(verify_details_.release());
- return FAILURE;
+ return QUIC_FAILURE;
}
// Convert certs to X509Certificate.
@@ -139,7 +139,7 @@
DLOG(WARNING) << *error_details;
verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
verify_details->reset(verify_details_.release());
- return FAILURE;
+ return QUIC_FAILURE;
}
// We call VerifySignature first to avoid copying of server_config and
@@ -149,7 +149,7 @@
DLOG(WARNING) << *error_details;
verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
verify_details->reset(verify_details_.release());
- return FAILURE;
+ return QUIC_FAILURE;
}
hostname_ = hostname;
@@ -158,14 +158,14 @@
switch (DoLoop(OK)) {
case OK:
verify_details->reset(verify_details_.release());
- return SUCCESS;
+ return QUIC_SUCCESS;
case ERR_IO_PENDING:
callback_.reset(callback);
- return PENDING;
+ return QUIC_PENDING;
default:
*error_details = error_details_;
verify_details->reset(verify_details_.release());
- return FAILURE;
+ return QUIC_FAILURE;
}
}
@@ -317,7 +317,7 @@
STLDeleteElements(&active_jobs_);
}
-ProofVerifierChromium::Status ProofVerifierChromium::VerifyProof(
+QuicAsyncStatus ProofVerifierChromium::VerifyProof(
const std::string& hostname,
const std::string& server_config,
const std::vector<std::string>& certs,
@@ -328,14 +328,15 @@
ProofVerifierCallback* callback) {
if (!verify_context) {
*error_details = "Missing context";
- return FAILURE;
+ return QUIC_FAILURE;
}
const ProofVerifyContextChromium* chromium_context =
reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
scoped_ptr<Job> job(new Job(this, cert_verifier_, chromium_context->net_log));
- Status status = job->VerifyProof(hostname, server_config, certs, signature,
- error_details, verify_details, callback);
- if (status == PENDING) {
+ QuicAsyncStatus status = job->VerifyProof(hostname, server_config, certs,
+ signature, error_details,
+ verify_details, callback);
+ if (status == QUIC_PENDING) {
active_jobs_.insert(job.release());
}
return status;
diff --git a/net/quic/crypto/proof_verifier_chromium.h b/net/quic/crypto/proof_verifier_chromium.h
index ebf9a2c..6f8a231 100644
--- a/net/quic/crypto/proof_verifier_chromium.h
+++ b/net/quic/crypto/proof_verifier_chromium.h
@@ -48,14 +48,15 @@
virtual ~ProofVerifierChromium();
// ProofVerifier interface
- virtual Status VerifyProof(const std::string& hostname,
- const std::string& server_config,
- const std::vector<std::string>& certs,
- const std::string& signature,
- const ProofVerifyContext* verify_context,
- std::string* error_details,
- scoped_ptr<ProofVerifyDetails>* verify_details,
- ProofVerifierCallback* callback) OVERRIDE;
+ virtual QuicAsyncStatus VerifyProof(
+ const std::string& hostname,
+ const std::string& server_config,
+ const std::vector<std::string>& certs,
+ const std::string& signature,
+ const ProofVerifyContext* verify_context,
+ std::string* error_details,
+ scoped_ptr<ProofVerifyDetails>* verify_details,
+ ProofVerifierCallback* callback) OVERRIDE;
private:
class Job;
diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc
index f9b31fd..f19a5b4 100644
--- a/net/quic/crypto/quic_crypto_client_config.cc
+++ b/net/quic/crypto/quic_crypto_client_config.cc
@@ -305,6 +305,10 @@
}
out->SetValue(kVER, QuicVersionToQuicTag(preferred_version));
+ if (!user_agent_id_.empty()) {
+ out->SetStringPiece(kUAID, user_agent_id_);
+ }
+
if (!cached->source_address_token().empty()) {
out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token());
}
diff --git a/net/quic/crypto/quic_crypto_client_config.h b/net/quic/crypto/quic_crypto_client_config.h
index 38575c8..a0b5c89 100644
--- a/net/quic/crypto/quic_crypto_client_config.h
+++ b/net/quic/crypto/quic_crypto_client_config.h
@@ -245,6 +245,11 @@
// TODO(rch): remove this method when we drop support for Windows XP.
void DisableEcdsa();
+ // Saves the |user_agent_id| that will be passed in QUIC's CHLO message.
+ void set_user_agent_id(const std::string& user_agent_id) {
+ user_agent_id_ = user_agent_id;
+ }
+
private:
typedef std::map<QuicServerId, CachedState*> CachedStateMap;
@@ -274,6 +279,9 @@
// True if ECDSA should be disabled.
bool disable_ecdsa_;
+ // The |user_agent_id_| passed in QUIC's CHLO message.
+ std::string user_agent_id_;
+
DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientConfig);
};
diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc
index 260c0d4..52acd43 100644
--- a/net/quic/crypto/quic_crypto_server_config.cc
+++ b/net/quic/crypto/quic_crypto_server_config.cc
@@ -1278,7 +1278,11 @@
QuicRandom* rand,
QuicWallTime now) const {
SourceAddressToken source_address_token;
- source_address_token.set_ip(IPAddressToPackedString(ip.address()));
+ IPAddressNumber ip_address = ip.address();
+ if (ip.GetSockAddrFamily() == AF_INET) {
+ ip_address = ConvertIPv4NumberToIPv6Number(ip_address);
+ }
+ source_address_token.set_ip(IPAddressToPackedString(ip_address));
source_address_token.set_timestamp(now.ToUNIXSeconds());
return config.source_address_token_boxer->Box(
@@ -1302,7 +1306,11 @@
return false;
}
- if (source_address_token.ip() != IPAddressToPackedString(ip.address())) {
+ IPAddressNumber ip_address = ip.address();
+ if (ip.GetSockAddrFamily() == AF_INET) {
+ ip_address = ConvertIPv4NumberToIPv6Number(ip_address);
+ }
+ if (source_address_token.ip() != IPAddressToPackedString(ip_address)) {
// It's for a different IP address.
return false;
}
diff --git a/net/quic/crypto/quic_crypto_server_config_test.cc b/net/quic/crypto/quic_crypto_server_config_test.cc
index 8aeef00..069c523 100644
--- a/net/quic/crypto/quic_crypto_server_config_test.cc
+++ b/net/quic/crypto/quic_crypto_server_config_test.cc
@@ -14,6 +14,7 @@
#include "net/quic/crypto/strike_register_client.h"
#include "net/quic/quic_time.h"
#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/quic_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -261,17 +262,20 @@
EXPECT_TRUE(peer.ConfigHasDefaultSourceAddressTokenBoxer(kPrimary));
EXPECT_FALSE(peer.ConfigHasDefaultSourceAddressTokenBoxer(kOverride));
- IPAddressNumber ip;
- CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
- IPEndPoint ip4 = IPEndPoint(ip, 1);
- CHECK(ParseIPLiteralToNumber("2001:db8:0::42", &ip));
- IPEndPoint ip6 = IPEndPoint(ip, 2);
+ IPEndPoint ip4 = IPEndPoint(Loopback4(), 1);
+ IPEndPoint ip4d = IPEndPoint(ConvertIPv4NumberToIPv6Number(ip4.address()), 1);
+ IPEndPoint ip6 = IPEndPoint(Loopback6(), 2);
// Primary config generates configs that validate successfully.
const string token4 = peer.NewSourceAddressToken(kPrimary, ip4, rand, now);
+ const string token4d = peer.NewSourceAddressToken(kPrimary, ip4d, rand, now);
const string token6 = peer.NewSourceAddressToken(kPrimary, ip6, rand, now);
EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token4, ip4, now));
+ EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token4, ip4d, now));
EXPECT_FALSE(peer.ValidateSourceAddressToken(kPrimary, token4, ip6, now));
+ EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token4d, ip4, now));
+ EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token4d, ip4d, now));
+ EXPECT_FALSE(peer.ValidateSourceAddressToken(kPrimary, token4d, ip6, now));
EXPECT_TRUE(peer.ValidateSourceAddressToken(kPrimary, token6, ip6, now));
// Override config generates configs that validate successfully.
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index 00b1411..a218dcd 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -28,6 +28,10 @@
namespace {
+// The length of time to wait for a 0-RTT handshake to complete
+// before allowing the requests to possibly proceed over TCP.
+const int k0RttHandshakeTimeoutMs = 300;
+
// Histograms for tracking down the crashes from http://crbug.com/354669
// Note: these values must be kept in sync with the corresponding values in:
// tools/metrics/histograms/histograms.xml
@@ -138,6 +142,7 @@
const QuicConfig& config,
uint32 max_flow_control_receive_window_bytes,
QuicCryptoClientConfig* crypto_config,
+ base::TaskRunner* task_runner,
NetLog* net_log)
: QuicClientSessionBase(connection,
max_flow_control_receive_window_bytes,
@@ -150,6 +155,7 @@
server_info_(server_info.Pass()),
read_pending_(false),
num_total_streams_(0),
+ task_runner_(task_runner),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
logger_(net_log_),
num_packets_read_(0),
@@ -436,16 +442,39 @@
return ERR_CONNECTION_FAILED;
}
- bool can_notify = require_confirmation_ ?
- IsCryptoHandshakeConfirmed() : IsEncryptionEstablished();
- if (can_notify) {
+ if (IsCryptoHandshakeConfirmed())
return OK;
+
+ // Unless we require handshake confirmation, activate the session if
+ // we have established initial encryption.
+ if (!require_confirmation_ && IsEncryptionEstablished()) {
+ // To mitigate the effects of hanging 0-RTT connections, set up a timer to
+ // cancel any requests, if the handshake takes too long.
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&QuicClientSession::OnConnectTimeout,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs));
+ return OK;
+
}
callback_ = callback;
return ERR_IO_PENDING;
}
+int QuicClientSession::ResumeCryptoConnect(const CompletionCallback& callback) {
+
+ if (IsCryptoHandshakeConfirmed())
+ return OK;
+
+ if (!connection()->connected())
+ return ERR_QUIC_HANDSHAKE_FAILED;
+
+ callback_ = callback;
+ return ERR_IO_PENDING;
+}
+
int QuicClientSession::GetNumSentClientHellos() const {
return crypto_stream_->num_sent_client_hellos();
}
@@ -800,4 +829,16 @@
stream_factory_->OnSessionClosed(this);
}
+void QuicClientSession::OnConnectTimeout() {
+ DCHECK(callback_.is_null());
+ DCHECK(IsEncryptionEstablished());
+
+ if (IsCryptoHandshakeConfirmed())
+ return;
+
+ if (stream_factory_)
+ stream_factory_->OnSessionConnectTimeout(this);
+ CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
+}
+
} // namespace net
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index ca4d7b8..f12003e 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -99,6 +99,7 @@
const QuicConfig& config,
uint32 max_flow_control_receive_window_bytes,
QuicCryptoClientConfig* crypto_config,
+ base::TaskRunner* task_runner,
NetLog* net_log);
virtual ~QuicClientSession();
@@ -150,6 +151,9 @@
int CryptoConnect(bool require_confirmation,
const CompletionCallback& callback);
+ // Resumes a crypto handshake with the server after a timeout.
+ int ResumeCryptoConnect(const CompletionCallback& callback);
+
// Causes the QuicConnectionHelper to start reading from the socket
// and passing the data along to the QuicConnection.
void StartReading();
@@ -214,6 +218,8 @@
// delete |this|.
void NotifyFactoryOfSessionClosed();
+ void OnConnectTimeout();
+
bool require_confirmation_;
scoped_ptr<QuicCryptoClientStream> crypto_stream_;
QuicStreamFactory* stream_factory_;
@@ -227,6 +233,7 @@
bool read_pending_;
CompletionCallback callback_;
size_t num_total_streams_;
+ base::TaskRunner* task_runner_;
BoundNetLog net_log_;
QuicConnectionLogger logger_;
// Number of packets read in the current read loop.
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index 2ca8bc9..8706d7c 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -73,7 +73,9 @@
QuicServerId(kServerHostname, kServerPort, false,
PRIVACY_MODE_DISABLED),
DefaultQuicConfig(), kInitialFlowControlWindowForTest,
- &crypto_config_, &net_log_) {
+ &crypto_config_,
+ base::MessageLoop::current()->message_loop_proxy().get(),
+ &net_log_) {
session_.config()->SetDefaults();
crypto_config_.SetDefaults();
}
diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc
index 9c60671..b9703c4 100644
--- a/net/quic/quic_config.cc
+++ b/net/quic/quic_config.cc
@@ -129,8 +129,7 @@
void QuicNegotiableTag::set(const QuicTagVector& possible,
QuicTag default_value) {
- DCHECK(std::find(possible.begin(), possible.end(), default_value) !=
- possible.end());
+ DCHECK(ContainsQuicTag(possible, default_value));
possible_values_ = possible;
default_value_ = default_value;
}
@@ -194,8 +193,7 @@
if (hello_type == SERVER) {
if (received_tags_length != 1 ||
- std::find(possible_values_.begin(), possible_values_.end(),
- *received_tags) == possible_values_.end()) {
+ !ContainsQuicTag(possible_values_, *received_tags)) {
*error_details = "Invalid " + QuicUtils::TagToString(tag_);
return QUIC_INVALID_NEGOTIATED_VALUE;
}
@@ -268,11 +266,10 @@
QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value_);
switch (error) {
case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
- if (presence_ == PRESENCE_REQUIRED) {
- *error_details = "Missing " + QuicUtils::TagToString(tag_);
- break;
+ if (presence_ == PRESENCE_OPTIONAL) {
+ return QUIC_NO_ERROR;
}
- error = QUIC_NO_ERROR;
+ *error_details = "Missing " + QuicUtils::TagToString(tag_);
break;
case QUIC_NO_ERROR:
has_receive_value_ = true;
@@ -329,18 +326,17 @@
}
QuicErrorCode QuicFixedTag::ProcessPeerHello(
- const CryptoHandshakeMessage& client_hello,
+ const CryptoHandshakeMessage& peer_hello,
HelloType hello_type,
string* error_details) {
DCHECK(error_details != NULL);
- QuicErrorCode error = client_hello.GetUint32(tag_, &receive_value_);
+ QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value_);
switch (error) {
case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
- if (presence_ == PRESENCE_REQUIRED) {
- *error_details = "Missing " + QuicUtils::TagToString(tag_);
- break;
+ if (presence_ == PRESENCE_OPTIONAL) {
+ return QUIC_NO_ERROR;
}
- error = QUIC_NO_ERROR;
+ *error_details = "Missing " + QuicUtils::TagToString(tag_);
break;
case QUIC_NO_ERROR:
has_receive_value_ = true;
@@ -352,8 +348,82 @@
return error;
}
+QuicFixedTagVector::QuicFixedTagVector(QuicTag name,
+ QuicConfigPresence presence)
+ : QuicConfigValue(name, presence),
+ has_send_values_(false),
+ has_receive_values_(false) {
+}
+
+QuicFixedTagVector::~QuicFixedTagVector() {}
+
+bool QuicFixedTagVector::HasSendValues() const {
+ return has_send_values_;
+}
+
+QuicTagVector QuicFixedTagVector::GetSendValues() const {
+ LOG_IF(DFATAL, !has_send_values_) << "No send values to get for tag:" << tag_;
+ return send_values_;
+}
+
+void QuicFixedTagVector::SetSendValues(const QuicTagVector& values) {
+ has_send_values_ = true;
+ send_values_ = values;
+}
+
+bool QuicFixedTagVector::HasReceivedValues() const {
+ return has_receive_values_;
+}
+
+QuicTagVector QuicFixedTagVector::GetReceivedValues() const {
+ LOG_IF(DFATAL, !has_receive_values_)
+ << "No receive value to get for tag:" << tag_;
+ return receive_values_;
+}
+
+void QuicFixedTagVector::SetReceivedValues(const QuicTagVector& values) {
+ has_receive_values_ = true;
+ receive_values_ = values;
+}
+
+void QuicFixedTagVector::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
+ if (has_send_values_) {
+ out->SetVector(tag_, send_values_);
+ }
+}
+
+QuicErrorCode QuicFixedTagVector::ProcessPeerHello(
+ const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ string* error_details) {
+ DCHECK(error_details != NULL);
+ const QuicTag* received_tags;
+ size_t received_tags_length;
+ QuicErrorCode error =
+ peer_hello.GetTaglist(tag_, &received_tags, &received_tags_length);
+ switch (error) {
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ if (presence_ == PRESENCE_OPTIONAL) {
+ return QUIC_NO_ERROR;
+ }
+ *error_details = "Missing " + QuicUtils::TagToString(tag_);
+ break;
+ case QUIC_NO_ERROR:
+ has_receive_values_ = true;
+ for (size_t i = 0; i < received_tags_length; ++i) {
+ receive_values_.push_back(received_tags[i]);
+ }
+ break;
+ default:
+ *error_details = "Bad " + QuicUtils::TagToString(tag_);
+ break;
+ }
+ return error;
+}
+
QuicConfig::QuicConfig()
- : congestion_control_(kCGST, PRESENCE_REQUIRED),
+ : congestion_feedback_(kCGST, PRESENCE_REQUIRED),
+ congestion_options_(kCOPT, PRESENCE_OPTIONAL),
loss_detection_(kLOSS, PRESENCE_OPTIONAL),
idle_connection_state_lifetime_seconds_(kICSL, PRESENCE_REQUIRED),
keepalive_timeout_seconds_(kKATO, PRESENCE_OPTIONAL),
@@ -368,14 +438,27 @@
QuicConfig::~QuicConfig() {}
-void QuicConfig::set_congestion_control(
- const QuicTagVector& congestion_control,
- QuicTag default_congestion_control) {
- congestion_control_.set(congestion_control, default_congestion_control);
+void QuicConfig::set_congestion_feedback(
+ const QuicTagVector& congestion_feedback,
+ QuicTag default_congestion_feedback) {
+ congestion_feedback_.set(congestion_feedback, default_congestion_feedback);
}
-QuicTag QuicConfig::congestion_control() const {
- return congestion_control_.GetTag();
+QuicTag QuicConfig::congestion_feedback() const {
+ return congestion_feedback_.GetTag();
+}
+
+void QuicConfig::SetCongestionOptionsToSend(
+ const QuicTagVector& congestion_options) {
+ congestion_options_.SetSendValues(congestion_options);
+}
+
+bool QuicConfig::HasReceivedCongestionOptions() const {
+ return congestion_options_.HasReceivedValues();
+}
+
+QuicTagVector QuicConfig::ReceivedCongestionOptions() const {
+ return congestion_options_.GetReceivedValues();
}
void QuicConfig::SetLossDetectionToSend(QuicTag loss_detection) {
@@ -466,19 +549,19 @@
// TODO(ianswett): Add the negotiated parameters once and iterate over all
// of them in negotiated, ToHandshakeMessage, ProcessClientHello, and
// ProcessServerHello.
- return congestion_control_.negotiated() &&
+ return congestion_feedback_.negotiated() &&
idle_connection_state_lifetime_seconds_.negotiated() &&
keepalive_timeout_seconds_.negotiated() &&
max_streams_per_connection_.negotiated();
}
void QuicConfig::SetDefaults() {
- QuicTagVector congestion_control;
+ QuicTagVector congestion_feedback;
if (FLAGS_enable_quic_pacing) {
- congestion_control.push_back(kPACE);
+ congestion_feedback.push_back(kPACE);
}
- congestion_control.push_back(kQBIC);
- congestion_control_.set(congestion_control, kQBIC);
+ congestion_feedback.push_back(kQBIC);
+ congestion_feedback_.set(congestion_feedback, kQBIC);
idle_connection_state_lifetime_seconds_.set(kDefaultTimeoutSecs,
kDefaultInitialTimeoutSecs);
// kKATO is optional. Return 0 if not negotiated.
@@ -490,16 +573,16 @@
}
void QuicConfig::EnablePacing(bool enable_pacing) {
- QuicTagVector congestion_control;
+ QuicTagVector congestion_feedback;
if (enable_pacing) {
- congestion_control.push_back(kPACE);
+ congestion_feedback.push_back(kPACE);
}
- congestion_control.push_back(kQBIC);
- congestion_control_.set(congestion_control, kQBIC);
+ congestion_feedback.push_back(kQBIC);
+ congestion_feedback_.set(congestion_feedback, kQBIC);
}
void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
- congestion_control_.ToHandshakeMessage(out);
+ congestion_feedback_.ToHandshakeMessage(out);
idle_connection_state_lifetime_seconds_.ToHandshakeMessage(out);
keepalive_timeout_seconds_.ToHandshakeMessage(out);
max_streams_per_connection_.ToHandshakeMessage(out);
@@ -507,6 +590,7 @@
initial_round_trip_time_us_.ToHandshakeMessage(out);
loss_detection_.ToHandshakeMessage(out);
initial_flow_control_window_bytes_.ToHandshakeMessage(out);
+ congestion_options_.ToHandshakeMessage(out);
}
QuicErrorCode QuicConfig::ProcessPeerHello(
@@ -517,7 +601,7 @@
QuicErrorCode error = QUIC_NO_ERROR;
if (error == QUIC_NO_ERROR) {
- error = congestion_control_.ProcessPeerHello(
+ error = congestion_feedback_.ProcessPeerHello(
peer_hello, hello_type, error_details);
}
if (error == QUIC_NO_ERROR) {
@@ -548,6 +632,10 @@
error = loss_detection_.ProcessPeerHello(
peer_hello, hello_type, error_details);
}
+ if (error == QUIC_NO_ERROR) {
+ error = congestion_options_.ProcessPeerHello(
+ peer_hello, hello_type, error_details);
+ }
return error;
}
diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h
index 88ad8b6..4d65097 100644
--- a/net/quic/quic_config.h
+++ b/net/quic/quic_config.h
@@ -215,6 +215,42 @@
bool has_receive_value_;
};
+// Stores tag from CHLO or SHLO messages that are not negotiated.
+class NET_EXPORT_PRIVATE QuicFixedTagVector : public QuicConfigValue {
+ public:
+ QuicFixedTagVector(QuicTag name, QuicConfigPresence presence);
+ virtual ~QuicFixedTagVector();
+
+ bool HasSendValues() const;
+
+ QuicTagVector GetSendValues() const;
+
+ void SetSendValues(const QuicTagVector& values);
+
+ bool HasReceivedValues() const;
+
+ QuicTagVector GetReceivedValues() const;
+
+ void SetReceivedValues(const QuicTagVector& values);
+
+ // If has_send_value is true, serialises |tag_vector_| and |send_value_| to
+ // |out|.
+ virtual void ToHandshakeMessage(CryptoHandshakeMessage* out) const OVERRIDE;
+
+ // Sets |receive_values_| to the corresponding value from |client_hello_| if
+ // it exists.
+ virtual QuicErrorCode ProcessPeerHello(
+ const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ std::string* error_details) OVERRIDE;
+
+ private:
+ QuicTagVector send_values_;
+ bool has_send_values_;
+ QuicTagVector receive_values_;
+ bool has_receive_values_;
+};
+
// QuicConfig contains non-crypto configuration options that are negotiated in
// the crypto handshake.
class NET_EXPORT_PRIVATE QuicConfig {
@@ -222,10 +258,16 @@
QuicConfig();
~QuicConfig();
- void set_congestion_control(const QuicTagVector& congestion_control,
- QuicTag default_congestion_control);
+ void set_congestion_feedback(const QuicTagVector& congestion_feedback,
+ QuicTag default_congestion_feedback);
- QuicTag congestion_control() const;
+ QuicTag congestion_feedback() const;
+
+ void SetCongestionOptionsToSend(const QuicTagVector& congestion_options);
+
+ bool HasReceivedCongestionOptions() const;
+
+ QuicTagVector ReceivedCongestionOptions() const;
void SetLossDetectionToSend(QuicTag loss_detection);
@@ -294,7 +336,9 @@
friend class test::QuicConfigPeer;
// Congestion control feedback type.
- QuicNegotiableTag congestion_control_;
+ QuicNegotiableTag congestion_feedback_;
+ // Congestion control option.
+ QuicFixedTagVector congestion_options_;
// Loss detection feedback type.
QuicFixedTag loss_detection_;
// Idle connection state lifetime
diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc
index 9ca449d..63299e5 100644
--- a/net/quic/quic_config_test.cc
+++ b/net/quic/quic_config_test.cc
@@ -69,12 +69,12 @@
EXPECT_EQ(kQBIC, out[1]);
}
-TEST_F(QuicConfigTest, ProcessPeerHello) {
+TEST_F(QuicConfigTest, ProcessClientHello) {
QuicConfig client_config;
QuicTagVector cgst;
cgst.push_back(kINAR);
cgst.push_back(kQBIC);
- client_config.set_congestion_control(cgst, kQBIC);
+ client_config.set_congestion_feedback(cgst, kQBIC);
client_config.set_idle_connection_state_lifetime(
QuicTime::Delta::FromSeconds(2 * kDefaultTimeoutSecs),
QuicTime::Delta::FromSeconds(kDefaultTimeoutSecs));
@@ -82,6 +82,9 @@
2 * kDefaultMaxStreamsPerConnection, kDefaultMaxStreamsPerConnection);
client_config.SetInitialRoundTripTimeUsToSend(
10 * base::Time::kMicrosecondsPerMillisecond);
+ QuicTagVector copt;
+ copt.push_back(kTBBR);
+ client_config.SetCongestionOptionsToSend(copt);
CryptoHandshakeMessage msg;
client_config.ToHandshakeMessage(&msg);
string error_details;
@@ -89,7 +92,7 @@
config_.ProcessPeerHello(msg, CLIENT, &error_details);
EXPECT_EQ(QUIC_NO_ERROR, error);
EXPECT_TRUE(config_.negotiated());
- EXPECT_EQ(kQBIC, config_.congestion_control());
+ EXPECT_EQ(kQBIC, config_.congestion_feedback());
EXPECT_EQ(QuicTime::Delta::FromSeconds(kDefaultTimeoutSecs),
config_.idle_connection_state_lifetime());
EXPECT_EQ(kDefaultMaxStreamsPerConnection,
@@ -98,13 +101,16 @@
EXPECT_EQ(10 * base::Time::kMicrosecondsPerMillisecond,
config_.ReceivedInitialRoundTripTimeUs());
EXPECT_FALSE(config_.HasReceivedLossDetection());
+ EXPECT_TRUE(config_.HasReceivedCongestionOptions());
+ EXPECT_EQ(1u, config_.ReceivedCongestionOptions().size());
+ EXPECT_EQ(config_.ReceivedCongestionOptions()[0], kTBBR);
}
TEST_F(QuicConfigTest, ProcessServerHello) {
QuicConfig server_config;
QuicTagVector cgst;
cgst.push_back(kQBIC);
- server_config.set_congestion_control(cgst, kQBIC);
+ server_config.set_congestion_feedback(cgst, kQBIC);
server_config.set_idle_connection_state_lifetime(
QuicTime::Delta::FromSeconds(kDefaultTimeoutSecs / 2),
QuicTime::Delta::FromSeconds(kDefaultTimeoutSecs / 2));
@@ -121,7 +127,7 @@
config_.ProcessPeerHello(msg, SERVER, &error_details);
EXPECT_EQ(QUIC_NO_ERROR, error);
EXPECT_TRUE(config_.negotiated());
- EXPECT_EQ(kQBIC, config_.congestion_control());
+ EXPECT_EQ(kQBIC, config_.congestion_feedback());
EXPECT_EQ(QuicTime::Delta::FromSeconds(kDefaultTimeoutSecs / 2),
config_.idle_connection_state_lifetime());
EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2,
@@ -211,7 +217,7 @@
QuicTagVector cgst;
cgst.push_back(kQBIC);
cgst.push_back(kINAR);
- server_config.set_congestion_control(cgst, kQBIC);
+ server_config.set_congestion_feedback(cgst, kQBIC);
CryptoHandshakeMessage msg;
server_config.ToHandshakeMessage(&msg);
@@ -226,7 +232,7 @@
server_config.SetDefaults();
QuicTagVector cgst;
cgst.push_back(kINAR);
- server_config.set_congestion_control(cgst, kINAR);
+ server_config.set_congestion_feedback(cgst, kINAR);
CryptoHandshakeMessage msg;
string error_details;
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 8162c3c..2f8c845 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -949,15 +949,8 @@
// Now that we have received an ack, we might be able to send packets which
// are queued locally, or drain streams which are blocked.
- QuicTime::Delta delay = sent_packet_manager_.TimeUntilSend(
- time_of_last_received_packet_, NOT_RETRANSMISSION,
- HAS_RETRANSMITTABLE_DATA);
- if (delay.IsZero()) {
- send_alarm_->Cancel();
- WriteIfNotBlocked();
- } else if (!delay.IsInfinite()) {
- send_alarm_->Cancel();
- send_alarm_->Set(time_of_last_received_packet_.Add(delay));
+ if (CanWrite(HAS_RETRANSMITTABLE_DATA)) {
+ OnCanWrite();
}
}
@@ -1066,7 +1059,7 @@
stats_.estimated_bandwidth =
sent_packet_manager_.BandwidthEstimate().ToBytesPerSecond();
stats_.congestion_window = sent_packet_manager_.GetCongestionWindow();
- stats_.max_packet_size = options()->max_packet_length;
+ stats_.max_packet_size = packet_creator_.max_packet_length();
return stats_;
}
@@ -1145,7 +1138,7 @@
// 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.
- if (!CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA)) {
+ if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) {
return;
}
@@ -1159,7 +1152,7 @@
// blocked or the congestion manager to prohibit sending, so check again.
if (visitor_->WillingAndAbleToWrite() &&
!resume_writes_alarm_->IsSet() &&
- CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA)) {
+ CanWrite(HAS_RETRANSMITTABLE_DATA)) {
// 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 connections and events have had a chance to use the thread.
@@ -1196,8 +1189,8 @@
<< time_of_last_received_packet_.ToDebuggingValue();
if (is_server_ && encryption_level_ == ENCRYPTION_NONE &&
- last_size_ > options()->max_packet_length) {
- options()->max_packet_length = last_size_;
+ last_size_ > packet_creator_.max_packet_length()) {
+ packet_creator_.set_max_packet_length(last_size_);
}
return true;
}
@@ -1230,7 +1223,7 @@
const QuicSentPacketManager::PendingRetransmission pending =
sent_packet_manager_.NextPendingRetransmission();
if (GetPacketType(&pending.retransmittable_frames) == NORMAL &&
- !CanWrite(pending.transmission_type, HAS_RETRANSMITTABLE_DATA)) {
+ !CanWrite(HAS_RETRANSMITTABLE_DATA)) {
break;
}
@@ -1253,7 +1246,8 @@
pending.sequence_number, serialized_packet.sequence_number);
}
sent_packet_manager_.OnRetransmittedPacket(
- pending.sequence_number, serialized_packet.sequence_number);
+ pending.sequence_number,
+ serialized_packet.sequence_number);
SendOrQueuePacket(pending.retransmittable_frames.encryption_level(),
serialized_packet,
@@ -1288,35 +1282,25 @@
return true;
}
- return CanWrite(transmission_type, retransmittable);
+ return CanWrite(retransmittable);
}
-bool QuicConnection::CanWrite(TransmissionType transmission_type,
- HasRetransmittableData retransmittable) {
+bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) {
if (writer_->IsWriteBlocked()) {
visitor_->OnWriteBlocked();
return false;
}
- // TODO(rch): consider removing this check so that if an ACK comes in
- // before the alarm goes it, we might be able send out a packet.
- // This check assumes that if the send alarm is set, it applies equally to all
- // types of transmissions.
- if (send_alarm_->IsSet()) {
- DVLOG(1) << "Send alarm set. Not sending.";
- return false;
- }
-
+ send_alarm_->Cancel();
QuicTime now = clock_->Now();
QuicTime::Delta delay = sent_packet_manager_.TimeUntilSend(
- now, transmission_type, retransmittable);
+ now, retransmittable);
if (delay.IsInfinite()) {
return false;
}
// If the scheduler requires a delay, then we can not send this packet now.
if (!delay.IsZero()) {
- send_alarm_->Cancel();
send_alarm_->Set(now.Add(delay));
DVLOG(1) << "Delaying sending.";
return false;
@@ -1339,8 +1323,7 @@
// This ensures packets are sent in sequence number order.
// TODO(ianswett): The congestion control should have been consulted before
// serializing the packet, so this could be turned into a LOG_IF(DFATAL).
- if (packet.type == NORMAL && !CanWrite(packet.transmission_type,
- packet.retransmittable)) {
+ if (packet.type == NORMAL && !CanWrite(packet.retransmittable)) {
return false;
}
@@ -1375,9 +1358,10 @@
encrypted_deleter.reset(encrypted);
}
- LOG_IF(DFATAL, encrypted->length() > options()->max_packet_length)
+ LOG_IF(DFATAL, encrypted->length() >
+ packet_creator_.max_packet_length())
<< "Writing an encrypted packet larger than max_packet_length:"
- << options()->max_packet_length << " encrypted length: "
+ << packet_creator_.max_packet_length() << " encrypted length: "
<< encrypted->length();
DVLOG(1) << ENDPOINT << "Sending packet " << sequence_number
<< " : " << (packet.packet->is_fec_packet() ? "FEC " :
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 2f91bb4..9e93715 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -40,6 +40,7 @@
#include "net/quic/quic_received_packet_manager.h"
#include "net/quic/quic_sent_entropy_manager.h"
#include "net/quic/quic_sent_packet_manager.h"
+#include "net/quic/quic_types.h"
namespace net {
@@ -111,10 +112,11 @@
// Interface which gets callbacks from the QuicConnection at interesting
// points. Implementations must not mutate the state of the connection
// as a result of these callbacks.
-class NET_EXPORT_PRIVATE QuicConnectionDebugVisitorInterface
- : public QuicPacketGenerator::DebugDelegateInterface {
+class NET_EXPORT_PRIVATE QuicConnectionDebugVisitor
+ : public QuicPacketGenerator::DebugDelegate,
+ public QuicSentPacketManager::DebugDelegate {
public:
- virtual ~QuicConnectionDebugVisitorInterface() {}
+ virtual ~QuicConnectionDebugVisitor() {}
// Called when a packet has been sent.
virtual void OnPacketSent(QuicPacketSequenceNumber sequence_number,
@@ -344,17 +346,22 @@
void set_visitor(QuicConnectionVisitorInterface* visitor) {
visitor_ = visitor;
}
- void set_debug_visitor(QuicConnectionDebugVisitorInterface* debug_visitor) {
+ void set_debug_visitor(QuicConnectionDebugVisitor* debug_visitor) {
debug_visitor_ = debug_visitor;
packet_generator_.set_debug_delegate(debug_visitor);
+ sent_packet_manager_.set_debug_delegate(debug_visitor);
}
const IPEndPoint& self_address() const { return self_address_; }
const IPEndPoint& peer_address() const { return peer_address_; }
QuicConnectionId connection_id() const { return connection_id_; }
const QuicClock* clock() const { return clock_; }
QuicRandom* random_generator() const { return random_generator_; }
-
- QuicPacketCreator::Options* options() { return packet_creator_.options(); }
+ size_t max_packet_length() const {
+ return packet_creator_.max_packet_length();
+ }
+ void set_max_packet_length(size_t length) {
+ return packet_creator_.set_max_packet_length(length);
+ }
bool connected() const { return connected_; }
@@ -455,8 +462,7 @@
return sent_packet_manager_;
}
- bool CanWrite(TransmissionType transmission_type,
- HasRetransmittableData retransmittable);
+ bool CanWrite(HasRetransmittableData retransmittable);
// Stores current batch state for connection, puts the connection
// into batch mode, and destruction restores the stored batch state.
@@ -695,7 +701,7 @@
scoped_ptr<QuicAlarm> ping_alarm_;
QuicConnectionVisitorInterface* visitor_;
- QuicConnectionDebugVisitorInterface* debug_visitor_;
+ QuicConnectionDebugVisitor* debug_visitor_;
QuicPacketCreator packet_creator_;
QuicPacketGenerator packet_generator_;
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index 8baa1b8..c50cb9e 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -20,7 +20,7 @@
// This class is a debug visitor of a QuicConnection which logs
// events to |net_log|.
class NET_EXPORT_PRIVATE QuicConnectionLogger
- : public QuicConnectionDebugVisitorInterface {
+ : public QuicConnectionDebugVisitor {
public:
explicit QuicConnectionLogger(const BoundNetLog& net_log);
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 603680f..6707c4a 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -556,7 +556,7 @@
// Used for testing packets revived from FEC packets.
class FecQuicConnectionDebugVisitor
- : public QuicConnectionDebugVisitorInterface {
+ : public QuicConnectionDebugVisitor {
public:
virtual void OnRevivedPacket(const QuicPacketHeader& header,
StringPiece data) OVERRIDE {
@@ -577,7 +577,7 @@
QuicConnectionTest()
: connection_id_(42),
framer_(SupportedVersions(version()), QuicTime::Zero(), false),
- creator_(connection_id_, &framer_, &random_generator_, false),
+ peer_creator_(connection_id_, &framer_, &random_generator_, false),
send_algorithm_(new StrictMock<MockSendAlgorithm>),
loss_algorithm_(new MockLossAlgorithm()),
helper_(new TestConnectionHelper(&clock_, &random_generator_)),
@@ -652,9 +652,10 @@
QuicPacketEntropyHash ProcessFramePacket(QuicFrame frame) {
QuicFrames frames;
frames.push_back(QuicFrame(frame));
- QuicPacketCreatorPeer::SetSendVersionInPacket(&creator_,
+ QuicPacketCreatorPeer::SetSendVersionInPacket(&peer_creator_,
connection_.is_server());
- SerializedPacket serialized_packet = creator_.SerializeAllFrames(frames);
+ SerializedPacket serialized_packet =
+ peer_creator_.SerializeAllFrames(frames);
scoped_ptr<QuicPacket> packet(serialized_packet.packet);
scoped_ptr<QuicEncryptedPacket> encrypted(
framer_.EncryptPacket(ENCRYPTION_NONE,
@@ -816,7 +817,7 @@
QuicFrame frame(&frame1_);
frames.push_back(frame);
QuicPacket* packet =
- framer_.BuildUnsizedDataPacket(header_, frames).packet;
+ BuildUnsizedDataPacket(&framer_, header_, frames).packet;
EXPECT_TRUE(packet != NULL);
return packet;
}
@@ -839,7 +840,7 @@
QuicFrame frame(&qccf);
frames.push_back(frame);
QuicPacket* packet =
- framer_.BuildUnsizedDataPacket(header_, frames).packet;
+ BuildUnsizedDataPacket(&framer_, header_, frames).packet;
EXPECT_TRUE(packet != NULL);
return packet;
}
@@ -913,9 +914,21 @@
EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
}
+ void CongestionBlockWrites() {
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, _, _)).WillRepeatedly(
+ testing::Return(QuicTime::Delta::FromSeconds(1)));
+ }
+
+ void CongestionUnblockWrites() {
+ EXPECT_CALL(*send_algorithm_,
+ TimeUntilSend(_, _, _)).WillRepeatedly(
+ testing::Return(QuicTime::Delta::Zero()));
+ }
+
QuicConnectionId connection_id_;
QuicFramer framer_;
- QuicPacketCreator creator_;
+ QuicPacketCreator peer_creator_;
MockEntropyCalculator entropy_calculator_;
MockSendAlgorithm* send_algorithm_;
@@ -1016,7 +1029,7 @@
// packet the peer will not retransmit. It indicates this by sending 'least
// awaiting' is 4. The connection should then realize 1 will not be
// retransmitted, and will remove it from the missing list.
- creator_.set_sequence_number(5);
+ peer_creator_.set_sequence_number(5);
QuicAckFrame frame = InitAckFrame(1, 4);
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _));
ProcessAckPacket(&frame);
@@ -1109,7 +1122,7 @@
TimeUntilSend(_, _, _)).WillRepeatedly(
testing::Return(QuicTime::Delta::Zero()));
// Skip a packet and then record an ack.
- creator_.set_sequence_number(2);
+ peer_creator_.set_sequence_number(2);
QuicAckFrame frame = InitAckFrame(0, 3);
ProcessAckPacket(&frame);
}
@@ -1205,7 +1218,7 @@
SendStreamDataToPeer(1, "eep", 6, !kFin, NULL);
// Start out saying the least unacked is 2.
- creator_.set_sequence_number(5);
+ peer_creator_.set_sequence_number(5);
if (version() > QUIC_VERSION_15) {
QuicStopWaitingFrame frame = InitStopWaitingFrame(2);
ProcessStopWaitingPacket(&frame);
@@ -1216,7 +1229,7 @@
// Change it to 1, but lower the sequence number to fake out-of-order packets.
// This should be fine.
- creator_.set_sequence_number(1);
+ peer_creator_.set_sequence_number(1);
// The scheduler will not process out of order acks, but all packet processing
// causes the connection to try to write.
EXPECT_CALL(visitor_, OnCanWrite());
@@ -1231,7 +1244,7 @@
// 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(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- creator_.set_sequence_number(7);
+ peer_creator_.set_sequence_number(7);
if (version() > QUIC_VERSION_15) {
EXPECT_CALL(visitor_,
OnConnectionClosed(QUIC_INVALID_STOP_WAITING_DATA, false));
@@ -1277,17 +1290,19 @@
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
- creator_.set_sequence_number(1);
+ peer_creator_.set_sequence_number(1);
QuicAckFrame frame1 = InitAckFrame(0, 1);
ProcessAckPacket(&frame1);
}
TEST_P(QuicConnectionTest, SendingDifferentSequenceNumberLengthsBandwidth) {
QuicPacketSequenceNumber last_packet;
+ QuicPacketCreator* creator =
+ QuicConnectionPeer::GetPacketCreator(&connection_);
SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet);
EXPECT_EQ(1u, last_packet);
EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
- connection_.options()->send_sequence_number_length);
+ creator->next_sequence_number_length());
EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
writer_->header().public_header.sequence_number_length);
@@ -1297,7 +1312,7 @@
SendStreamDataToPeer(1, "bar", 3, !kFin, &last_packet);
EXPECT_EQ(2u, last_packet);
EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
- connection_.options()->send_sequence_number_length);
+ creator->next_sequence_number_length());
// The 1 packet lag is due to the sequence number length being recalculated in
// QuicConnection after a packet is sent.
EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
@@ -1309,7 +1324,7 @@
SendStreamDataToPeer(1, "foo", 6, !kFin, &last_packet);
EXPECT_EQ(3u, last_packet);
EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
- connection_.options()->send_sequence_number_length);
+ creator->next_sequence_number_length());
EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
writer_->header().public_header.sequence_number_length);
@@ -1319,7 +1334,7 @@
SendStreamDataToPeer(1, "bar", 9, !kFin, &last_packet);
EXPECT_EQ(4u, last_packet);
EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
- connection_.options()->send_sequence_number_length);
+ creator->next_sequence_number_length());
EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
writer_->header().public_header.sequence_number_length);
@@ -1329,52 +1344,51 @@
SendStreamDataToPeer(1, "foo", 12, !kFin, &last_packet);
EXPECT_EQ(5u, last_packet);
EXPECT_EQ(PACKET_6BYTE_SEQUENCE_NUMBER,
- connection_.options()->send_sequence_number_length);
+ creator->next_sequence_number_length());
EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
writer_->header().public_header.sequence_number_length);
}
TEST_P(QuicConnectionTest, SendingDifferentSequenceNumberLengthsUnackedDelta) {
QuicPacketSequenceNumber last_packet;
+ QuicPacketCreator* creator =
+ QuicConnectionPeer::GetPacketCreator(&connection_);
SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet);
EXPECT_EQ(1u, last_packet);
EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
- connection_.options()->send_sequence_number_length);
+ creator->next_sequence_number_length());
EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
writer_->header().public_header.sequence_number_length);
- QuicConnectionPeer::GetPacketCreator(&connection_)->set_sequence_number(100);
+ creator->set_sequence_number(100);
SendStreamDataToPeer(1, "bar", 3, !kFin, &last_packet);
EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
- connection_.options()->send_sequence_number_length);
+ creator->next_sequence_number_length());
EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
writer_->header().public_header.sequence_number_length);
- QuicConnectionPeer::GetPacketCreator(&connection_)->set_sequence_number(
- 100 * 256);
+ creator->set_sequence_number(100 * 256);
SendStreamDataToPeer(1, "foo", 6, !kFin, &last_packet);
EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
- connection_.options()->send_sequence_number_length);
+ creator->next_sequence_number_length());
EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
writer_->header().public_header.sequence_number_length);
- QuicConnectionPeer::GetPacketCreator(&connection_)->set_sequence_number(
- 100 * 256 * 256);
+ creator->set_sequence_number(100 * 256 * 256);
SendStreamDataToPeer(1, "bar", 9, !kFin, &last_packet);
EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
- connection_.options()->send_sequence_number_length);
+ creator->next_sequence_number_length());
EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
writer_->header().public_header.sequence_number_length);
- QuicConnectionPeer::GetPacketCreator(&connection_)->set_sequence_number(
- 100 * 256 * 256 * 256);
+ creator->set_sequence_number(100 * 256 * 256 * 256);
SendStreamDataToPeer(1, "foo", 12, !kFin, &last_packet);
EXPECT_EQ(PACKET_6BYTE_SEQUENCE_NUMBER,
- connection_.options()->send_sequence_number_length);
+ creator->next_sequence_number_length());
EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
writer_->header().public_header.sequence_number_length);
}
@@ -1432,18 +1446,21 @@
TEST_P(QuicConnectionTest, FECSending) {
// All packets carry version info till version is negotiated.
+ QuicPacketCreator* creator =
+ QuicConnectionPeer::GetPacketCreator(&connection_);
size_t payload_length;
// GetPacketLengthForOneStream() assumes a stream offset of 0 in determining
// packet length. The size of the offset field in a stream frame is 0 for
- // offset 0, and 2 for non-zero offsets up through 16K. Increase
+ // offset 0, and 2 for non-zero offsets up through 64K. Increase
// max_packet_length by 2 so that subsequent packets containing subsequent
// stream frames with non-zero offets will fit within the packet length.
- connection_.options()->max_packet_length = 2 + GetPacketLengthForOneStream(
+ size_t length = 2 + GetPacketLengthForOneStream(
connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
IN_FEC_GROUP, &payload_length);
+ creator->set_max_packet_length(length);
+
// And send FEC every two packets.
- EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(
- QuicConnectionPeer::GetPacketCreator(&connection_), 2));
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(creator, 2));
// Send 4 data packets and 2 FEC packets.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6);
@@ -1451,25 +1468,28 @@
const string payload(payload_length * 4 + 2, 'a');
connection_.SendStreamDataWithString(1, payload, 0, !kFin, NULL);
// Expect the FEC group to be closed after SendStreamDataWithString.
- EXPECT_FALSE(creator_.ShouldSendFec(true));
+ EXPECT_FALSE(creator->ShouldSendFec(true));
+ EXPECT_TRUE(creator->IsFecProtected());
}
TEST_P(QuicConnectionTest, FECQueueing) {
// All packets carry version info till version is negotiated.
size_t payload_length;
- connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(
- connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
- IN_FEC_GROUP, &payload_length);
+ QuicPacketCreator* creator =
+ QuicConnectionPeer::GetPacketCreator(&connection_);
+ size_t length = GetPacketLengthForOneStream(
+ connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
+ IN_FEC_GROUP, &payload_length);
+ creator->set_max_packet_length(length);
// And send FEC every two packets.
- EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(
- QuicConnectionPeer::GetPacketCreator(&connection_), 2));
+ EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(creator, 2));
EXPECT_EQ(0u, connection_.NumQueuedPackets());
BlockOnNextWrite();
const string payload(payload_length, 'a');
connection_.SendStreamDataWithString(1, payload, 0, !kFin, NULL);
- EXPECT_FALSE(creator_.ShouldSendFec(true));
+ EXPECT_FALSE(creator->ShouldSendFec(true));
+ EXPECT_TRUE(creator->IsFecProtected());
// Expect the first data packet and the fec packet to be queued.
EXPECT_EQ(2u, connection_.NumQueuedPackets());
}
@@ -1560,9 +1580,7 @@
}
TEST_P(QuicConnectionTest, FramePacking) {
- // Block the connection.
- connection_.GetSendAlarm()->Set(
- clock_.ApproximateNow().Add(QuicTime::Delta::FromSeconds(1)));
+ CongestionBlockWrites();
// Send an ack and two stream frames in 1 packet by queueing them.
connection_.SendAck();
@@ -1573,7 +1591,7 @@
&TestConnection::SendStreamData5))));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- // Unblock the connection.
+ CongestionUnblockWrites();
connection_.GetSendAlarm()->Fire();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
EXPECT_FALSE(connection_.HasQueuedData());
@@ -1587,15 +1605,13 @@
EXPECT_EQ(3u, writer_->frame_count());
}
EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_EQ(2u, writer_->stream_frames().size());
+ ASSERT_EQ(2u, writer_->stream_frames().size());
EXPECT_EQ(kClientDataStreamId1, writer_->stream_frames()[0].stream_id);
EXPECT_EQ(kClientDataStreamId2, writer_->stream_frames()[1].stream_id);
}
TEST_P(QuicConnectionTest, FramePackingNonCryptoThenCrypto) {
- // Block the connection.
- connection_.GetSendAlarm()->Set(
- clock_.ApproximateNow().Add(QuicTime::Delta::FromSeconds(1)));
+ CongestionBlockWrites();
// Send an ack and two stream frames (one non-crypto, then one crypto) in 2
// packets by queueing them.
@@ -1607,21 +1623,19 @@
&TestConnection::SendCryptoStreamData))));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
- // Unblock the connection.
+ CongestionUnblockWrites();
connection_.GetSendAlarm()->Fire();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
EXPECT_FALSE(connection_.HasQueuedData());
// Parse the last packet and ensure it's the crypto stream frame.
EXPECT_EQ(1u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->stream_frames().size());
+ ASSERT_EQ(1u, writer_->stream_frames().size());
EXPECT_EQ(kCryptoStreamId, writer_->stream_frames()[0].stream_id);
}
TEST_P(QuicConnectionTest, FramePackingCryptoThenNonCrypto) {
- // Block the connection.
- connection_.GetSendAlarm()->Set(
- clock_.ApproximateNow().Add(QuicTime::Delta::FromSeconds(1)));
+ CongestionBlockWrites();
// Send an ack and two stream frames (one crypto, then one non-crypto) in 3
// packets by queueing them.
@@ -1633,28 +1647,23 @@
&TestConnection::SendStreamData3))));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(3);
- // Unblock the connection.
+ CongestionUnblockWrites();
connection_.GetSendAlarm()->Fire();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
EXPECT_FALSE(connection_.HasQueuedData());
// Parse the last packet and ensure it's the stream frame from stream 3.
EXPECT_EQ(1u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->stream_frames().size());
+ ASSERT_EQ(1u, writer_->stream_frames().size());
EXPECT_EQ(kClientDataStreamId1, writer_->stream_frames()[0].stream_id);
}
TEST_P(QuicConnectionTest, FramePackingFEC) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
// Enable fec.
EXPECT_TRUE(QuicPacketCreatorPeer::SwitchFecProtectionOn(
QuicConnectionPeer::GetPacketCreator(&connection_), 6));
- // Block the connection.
- connection_.GetSendAlarm()->Set(
- clock_.ApproximateNow().Add(QuicTime::Delta::FromSeconds(1)));
+ CongestionBlockWrites();
// Send an ack and two stream frames in 1 packet by queueing them.
connection_.SendAck();
@@ -1665,7 +1674,7 @@
&TestConnection::SendStreamData5))));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
- // Unblock the connection.
+ CongestionUnblockWrites();
connection_.GetSendAlarm()->Fire();
EXPECT_EQ(0u, connection_.NumQueuedPackets());
EXPECT_FALSE(connection_.HasQueuedData());
@@ -1690,7 +1699,7 @@
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
// Process an ack to cause the visitor's OnCanWrite to be invoked.
- creator_.set_sequence_number(2);
+ peer_creator_.set_sequence_number(2);
QuicAckFrame ack_one = InitAckFrame(0, 0);
ProcessAckPacket(&ack_one);
@@ -2099,9 +2108,6 @@
}
TEST_P(QuicConnectionTest, ReviveMissingPacketAfterFecPacket) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Don't send missing packet 1.
@@ -2111,9 +2117,6 @@
}
TEST_P(QuicConnectionTest, ReviveMissingPacketWithVaryingSeqNumLengths) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Set up a debug visitor to the connection.
@@ -2143,9 +2146,6 @@
}
TEST_P(QuicConnectionTest, ReviveMissingPacketWithVaryingConnectionIdLengths) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Set up a debug visitor to the connection.
@@ -2175,9 +2175,6 @@
}
TEST_P(QuicConnectionTest, ReviveMissingPacketAfterDataPacketThenFecPacket) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessFecProtectedPacket(1, false, kEntropyFlag);
@@ -2188,9 +2185,6 @@
}
TEST_P(QuicConnectionTest, ReviveMissingPacketAfterDataPacketsThenFecPacket) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessFecProtectedPacket(1, false, !kEntropyFlag);
@@ -2203,9 +2197,6 @@
}
TEST_P(QuicConnectionTest, ReviveMissingPacketAfterDataPacket) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Don't send missing packet 1.
@@ -2217,9 +2208,6 @@
}
TEST_P(QuicConnectionTest, ReviveMissingPacketAfterDataPackets) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessFecProtectedPacket(1, false, !kEntropyFlag);
@@ -2548,7 +2536,7 @@
ASSERT_EQ(1u, connection_.NumFecGroups());
// Now send non-fec protected ack packet and close the group.
- creator_.set_sequence_number(4);
+ peer_creator_.set_sequence_number(4);
if (version() > QUIC_VERSION_15) {
QuicStopWaitingFrame frame = InitStopWaitingFrame(5);
ProcessStopWaitingPacket(&frame);
@@ -2585,9 +2573,6 @@
}
TEST_P(QuicConnectionTest, DontUpdateQuicCongestionFeedbackFrameForRevived) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
SendAckPacketToPeer();
// Process an FEC packet, and revive the missing data packet
@@ -2759,8 +2744,7 @@
}
TEST_P(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _))
- .WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
+ CongestionUnblockWrites();
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _));
connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
@@ -2769,17 +2753,13 @@
// Test that if we send a retransmit with a delay, it ends up queued in the
// sent packet manager, but not yet serialized.
EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
- EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _, _)).WillOnce(
- testing::Return(QuicTime::Delta::FromMicroseconds(1)));
+ CongestionBlockWrites();
connection_.GetRetransmissionAlarm()->Fire();
EXPECT_EQ(0u, 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(_, _, _)).Times(3).
- WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
+ CongestionUnblockWrites();
// Ensure the scheduler is notified this is a retransmit.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
@@ -2854,9 +2834,7 @@
// TODO(ianswett): This test is unrealistic, because we would not serialize
// new data if the send algorithm said not to.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
- EXPECT_CALL(*send_algorithm_,
- TimeUntilSend(_, _, _)).WillOnce(
- testing::Return(QuicTime::Delta::FromMicroseconds(10)));
+ CongestionBlockWrites();
connection_.SendPacket(
ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -2870,10 +2848,11 @@
TEST_P(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
// All packets carry version info till version is negotiated.
size_t payload_length;
- connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(
- connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
- NOT_IN_FEC_GROUP, &payload_length);
+ size_t length = GetPacketLengthForOneStream(
+ connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
+ NOT_IN_FEC_GROUP, &payload_length);
+ QuicConnectionPeer::GetPacketCreator(&connection_)->set_max_packet_length(
+ length);
// Queue the first packet.
EXPECT_CALL(*send_algorithm_,
@@ -2894,9 +2873,11 @@
// offset 0, and 2 for non-zero offsets up through 16K. Increase
// max_packet_length by 2 so that subsequent packets containing subsequent
// stream frames with non-zero offets will fit within the packet length.
- connection_.options()->max_packet_length = 2 + GetPacketLengthForOneStream(
+ size_t length = 2 + GetPacketLengthForOneStream(
connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
NOT_IN_FEC_GROUP, &payload_length);
+ QuicConnectionPeer::GetPacketCreator(&connection_)->set_max_packet_length(
+ length);
// Queue the first packet.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(7);
@@ -3160,7 +3141,7 @@
TEST_P(QuicConnectionTest, MissingPacketsBeforeLeastUnacked) {
// Set the sequence number of the ack packet to be least unacked (4).
- creator_.set_sequence_number(3);
+ peer_creator_.set_sequence_number(3);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
if (version() > QUIC_VERSION_15) {
QuicStopWaitingFrame frame = InitStopWaitingFrame(4);
@@ -3183,9 +3164,6 @@
}
TEST_P(QuicConnectionTest, ReceivedEntropyHashCalculationHalfFEC) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
// FEC packets should not change the entropy hash calculation.
EXPECT_CALL(visitor_, OnStreamFrames(_)).Times(AtLeast(1));
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -3204,7 +3182,7 @@
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.
- creator_.set_sequence_number(5);
+ peer_creator_.set_sequence_number(5);
QuicPacketEntropyHash six_packet_entropy_hash = 0;
QuicPacketEntropyHash kRandomEntropyHash = 129u;
if (version() > QUIC_VERSION_15) {
@@ -3232,7 +3210,7 @@
ProcessDataPacket(5, 1, !kEntropyFlag);
ProcessDataPacket(22, 1, kEntropyFlag);
EXPECT_EQ(66u, outgoing_ack()->received_info.entropy_hash);
- creator_.set_sequence_number(22);
+ peer_creator_.set_sequence_number(22);
QuicPacketEntropyHash kRandomEntropyHash = 85u;
// Current packet is the least unacked packet.
QuicPacketEntropyHash ack_entropy_hash;
@@ -3278,7 +3256,7 @@
}
TEST_P(QuicConnectionTest, CheckSentEntropyHash) {
- creator_.set_sequence_number(1);
+ peer_creator_.set_sequence_number(1);
SequenceNumberSet missing_packets;
QuicPacketEntropyHash entropy_hash = 0;
QuicPacketSequenceNumber max_sequence_number = 51;
@@ -3323,7 +3301,7 @@
QuicFrame frame(&frame1_);
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ BuildUnsizedDataPacket(&framer_, header, frames).packet);
scoped_ptr<QuicEncryptedPacket> encrypted(
framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet));
@@ -3361,7 +3339,7 @@
QuicFrame frame(&frame1_);
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ BuildUnsizedDataPacket(&framer_, header, frames).packet);
scoped_ptr<QuicEncryptedPacket> encrypted(
framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet));
@@ -3406,7 +3384,7 @@
QuicFrame frame(&frame1_);
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ BuildUnsizedDataPacket(&framer_, header, frames).packet);
scoped_ptr<QuicEncryptedPacket> encrypted(
framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet));
@@ -3451,7 +3429,7 @@
QuicFrame frame(&frame1_);
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ BuildUnsizedDataPacket(&framer_, header, frames).packet);
encrypted.reset(framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet));
EXPECT_CALL(visitor_, OnStreamFrames(_)).Times(1);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -3532,9 +3510,6 @@
}
TEST_P(QuicConnectionTest, CheckReceiveStats) {
- if (version() < QUIC_VERSION_15) {
- return;
- }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
size_t received_bytes = 0;
@@ -3596,7 +3571,7 @@
frames.push_back(stream_frame);
frames.push_back(close_frame);
scoped_ptr<QuicPacket> packet(
- framer_.BuildUnsizedDataPacket(header_, frames).packet);
+ BuildUnsizedDataPacket(&framer_, header_, frames).packet);
EXPECT_TRUE(NULL != packet.get());
scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
ENCRYPTION_NONE, 1, *packet));
@@ -3886,7 +3861,7 @@
ack_header.fec_group = 1;
QuicPacket* packet =
- framer_.BuildUnsizedDataPacket(ack_header, frames).packet;
+ BuildUnsizedDataPacket(&framer_, ack_header, frames).packet;
// Take the packet which contains the ACK frame, and construct and deliver an
// FEC packet which allows the ACK packet to be recovered.
@@ -3894,7 +3869,7 @@
}
class MockQuicConnectionDebugVisitor
- : public QuicConnectionDebugVisitorInterface {
+ : public QuicConnectionDebugVisitor {
public:
MOCK_METHOD1(OnFrameAddedToPacket,
void(const QuicFrame&));
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index d684a49..dcc4182 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -132,7 +132,7 @@
// Pad the inchoate client hello to fill up a packet.
const size_t kFramingOverhead = 50; // A rough estimate.
const size_t max_packet_size =
- session()->connection()->options()->max_packet_length;
+ session()->connection()->max_packet_length();
if (max_packet_size <= kFramingOverhead) {
DLOG(DFATAL) << "max_packet_length (" << max_packet_size
<< ") has no room for framing overhead.";
@@ -237,7 +237,7 @@
verify_ok_ = false;
- ProofVerifier::Status status = verifier->VerifyProof(
+ QuicAsyncStatus status = verifier->VerifyProof(
server_id_.host(),
cached->server_config(),
cached->certs(),
@@ -248,14 +248,14 @@
proof_verify_callback);
switch (status) {
- case ProofVerifier::PENDING:
+ case QUIC_PENDING:
proof_verify_callback_ = proof_verify_callback;
DVLOG(1) << "Doing VerifyProof";
return;
- case ProofVerifier::FAILURE:
+ case QUIC_FAILURE:
delete proof_verify_callback;
break;
- case ProofVerifier::SUCCESS:
+ case QUIC_SUCCESS:
delete proof_verify_callback;
verify_ok_ = true;
break;
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 14ff3fd..3515d32 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -93,7 +93,7 @@
const QuicConfig* config = session_->config();
EXPECT_EQ(FLAGS_enable_quic_pacing ? kPACE : kQBIC,
- config->congestion_control());
+ config->congestion_feedback());
EXPECT_EQ(kDefaultTimeoutSecs,
config->idle_connection_state_lifetime().ToSeconds());
EXPECT_EQ(kDefaultMaxStreamsPerConnection,
diff --git a/net/quic/quic_data_stream_test.cc b/net/quic/quic_data_stream_test.cc
index 6799131..04b7c4e 100644
--- a/net/quic/quic_data_stream_test.cc
+++ b/net/quic/quic_data_stream_test.cc
@@ -497,7 +497,8 @@
string body;
GenerateBody(&body, kWindow + 1);
QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
- EXPECT_CALL(*connection_, SendConnectionClose(QUIC_FLOW_CONTROL_ERROR));
+ EXPECT_CALL(*connection_,
+ SendConnectionClose(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA));
stream_->OnStreamFrame(frame);
}
@@ -534,7 +535,8 @@
EXPECT_LT(body.size(), kStreamWindow);
QuicStreamFrame frame(kClientDataStreamId1, false, 0, MakeIOVector(body));
- EXPECT_CALL(*connection_, SendConnectionClose(QUIC_FLOW_CONTROL_ERROR));
+ EXPECT_CALL(*connection_,
+ SendConnectionClose(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA));
stream_->OnStreamFrame(frame);
}
diff --git a/net/quic/quic_flow_controller.cc b/net/quic/quic_flow_controller.cc
index 412f250..6ca3520 100644
--- a/net/quic/quic_flow_controller.cc
+++ b/net/quic/quic_flow_controller.cc
@@ -13,31 +13,32 @@
#define ENDPOINT (is_server_ ? "Server: " : " Client: ")
-QuicFlowController::QuicFlowController(QuicVersion version,
+QuicFlowController::QuicFlowController(QuicConnection* connection,
QuicStreamId id,
bool is_server,
uint64 send_window_offset,
uint64 receive_window_offset,
uint64 max_receive_window)
- : id_(id),
- is_enabled_(true),
- is_server_(is_server),
- bytes_consumed_(0),
- bytes_buffered_(0),
- bytes_sent_(0),
- send_window_offset_(send_window_offset),
- receive_window_offset_(receive_window_offset),
- max_receive_window_(max_receive_window),
- last_blocked_send_window_offset_(0) {
+ : connection_(connection),
+ id_(id),
+ is_enabled_(true),
+ is_server_(is_server),
+ bytes_consumed_(0),
+ highest_received_byte_offset_(0),
+ bytes_sent_(0),
+ send_window_offset_(send_window_offset),
+ receive_window_offset_(receive_window_offset),
+ max_receive_window_(max_receive_window),
+ last_blocked_send_window_offset_(0) {
DVLOG(1) << ENDPOINT << "Created flow controller for stream " << id_
<< ", setting initial receive window offset to: "
<< receive_window_offset_
<< ", max receive window to: "
<< max_receive_window_
<< ", setting send window offset to: " << send_window_offset_;
- if (version < QUIC_VERSION_17) {
+ if (connection_->version() < QUIC_VERSION_17) {
DVLOG(1) << ENDPOINT << "Disabling QuicFlowController for stream " << id_
- << ", QUIC version " << version;
+ << ", QUIC version " << connection_->version();
Disable();
}
}
@@ -49,31 +50,25 @@
bytes_consumed_ += bytes_consumed;
DVLOG(1) << ENDPOINT << "Stream " << id_ << " consumed: " << bytes_consumed_;
+
+ MaybeSendWindowUpdate();
}
-void QuicFlowController::AddBytesBuffered(uint64 bytes_buffered) {
+bool QuicFlowController::UpdateHighestReceivedOffset(uint64 new_offset) {
if (!IsEnabled()) {
- return;
+ return false;
}
- bytes_buffered_ += bytes_buffered;
- DVLOG(1) << ENDPOINT << "Stream " << id_ << " buffered: " << bytes_buffered_;
-}
-
-void QuicFlowController::RemoveBytesBuffered(uint64 bytes_buffered) {
- if (!IsEnabled()) {
- return;
+ // Only update if offset has increased.
+ if (new_offset <= highest_received_byte_offset_) {
+ return false;
}
- if (bytes_buffered_ < bytes_buffered) {
- LOG(DFATAL) << "Trying to remove " << bytes_buffered << " bytes, when only "
- << bytes_buffered_ << " bytes are buffered";
- bytes_buffered_ = 0;
- return;
- }
-
- bytes_buffered_ -= bytes_buffered;
- DVLOG(1) << ENDPOINT << "Stream " << id_ << " buffered: " << bytes_buffered_;
+ DVLOG(1) << ENDPOINT << "Stream " << id_
+ << " highest byte offset increased from: "
+ << highest_received_byte_offset_ << " to " << new_offset;
+ highest_received_byte_offset_ = new_offset;
+ return true;
}
void QuicFlowController::AddBytesSent(uint64 bytes_sent) {
@@ -86,6 +81,9 @@
<< bytes_sent << " bytes, when bytes_sent = " << bytes_sent_
<< ", and send_window_offset_ = " << send_window_offset_;
bytes_sent_ = send_window_offset_;
+
+ // This is an error on our side, close the connection as soon as possible.
+ connection_->SendConnectionClose(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA);
return;
}
@@ -98,18 +96,18 @@
return false;
}
- if (receive_window_offset_ < TotalReceivedBytes()) {
- LOG(ERROR)
- << ENDPOINT << "Flow control violation on stream " << id_
- << ", receive window: " << receive_window_offset_
- << ", bytes received: " << TotalReceivedBytes();
-
+ if (highest_received_byte_offset_ > receive_window_offset_) {
+ LOG(ERROR) << ENDPOINT << "Flow control violation on stream "
+ << id_ << ", receive window offset: "
+ << receive_window_offset_
+ << ", highest received byte offset: "
+ << highest_received_byte_offset_;
return true;
}
return false;
}
-void QuicFlowController::MaybeSendWindowUpdate(QuicConnection* connection) {
+void QuicFlowController::MaybeSendWindowUpdate() {
if (!IsEnabled()) {
return;
}
@@ -117,6 +115,7 @@
// Send WindowUpdate to increase receive window if
// (receive window offset - consumed bytes) < (max window / 2).
// This is behaviour copied from SPDY.
+ DCHECK_LT(bytes_consumed_, receive_window_offset_);
size_t consumed_window = receive_window_offset_ - bytes_consumed_;
size_t threshold = (max_receive_window_ / 2);
@@ -132,11 +131,11 @@
<< ". New receive window offset is: " << receive_window_offset_;
// Inform the peer of our new receive window.
- connection->SendWindowUpdate(id_, receive_window_offset_);
+ connection_->SendWindowUpdate(id_, receive_window_offset_);
}
}
-void QuicFlowController::MaybeSendBlocked(QuicConnection* connection) {
+void QuicFlowController::MaybeSendBlocked() {
if (!IsEnabled()) {
return;
}
@@ -149,7 +148,7 @@
<< ", send limit: " << send_window_offset_;
// The entire send_window has been consumed, we are now flow control
// blocked.
- connection->SendBlocked(id_);
+ connection_->SendBlocked(id_);
// Keep track of when we last sent a BLOCKED frame so that we only send one
// at a given send offset.
@@ -201,8 +200,4 @@
return send_window_offset_ - bytes_sent_;
}
-uint64 QuicFlowController::TotalReceivedBytes() const {
- return bytes_consumed_ + bytes_buffered_;
-}
-
} // namespace net
diff --git a/net/quic/quic_flow_controller.h b/net/quic/quic_flow_controller.h
index 3125b81..e5f5494 100644
--- a/net/quic/quic_flow_controller.h
+++ b/net/quic/quic_flow_controller.h
@@ -25,7 +25,7 @@
// can send WINDOW_UPDATE or BLOCKED frames when needed.
class NET_EXPORT_PRIVATE QuicFlowController {
public:
- QuicFlowController(QuicVersion version,
+ QuicFlowController(QuicConnection* connection,
QuicStreamId id,
bool is_server,
uint64 send_window_offset,
@@ -33,13 +33,14 @@
uint64 max_receive_window);
~QuicFlowController() {}
- // Called when bytes are received from the peer, and buffered.
- void AddBytesBuffered(uint64 bytes_buffered);
+ // Called when we see a new highest received byte offset from the peer, either
+ // via a data frame or a RST.
+ // Returns true if this call changes highest_received_byte_offset_, and false
+ // in the case where |new_offset| is <= highest_received_byte_offset_.
+ bool UpdateHighestReceivedOffset(uint64 new_offset);
- // Called when bytes currently buffered locally, are removed from the buffer.
- void RemoveBytesBuffered(uint64 bytes_buffered);
-
- // Called when bytes received from the peer are consumed locally.
+ // Called when bytes received from the peer are consumed locally. This may
+ // trigger the sending of a WINDOW_UPDATE frame using |connection|.
void AddBytesConsumed(uint64 bytes_consumed);
// Called when bytes are sent to the peer.
@@ -53,11 +54,8 @@
// Returns the current available send window.
uint64 SendWindowSize() const;
- // Send a BLOCKED frame on |connection| if appropriate.
- void MaybeSendBlocked(QuicConnection* connection);
-
- // Send a WINDOW_UPDATE frame on |connection| if appropriate.
- void MaybeSendWindowUpdate(QuicConnection* connection);
+ // Send a BLOCKED frame if appropriate.
+ void MaybeSendBlocked();
// Disable flow control.
void Disable();
@@ -71,11 +69,22 @@
// Returns true if flow control receive limits have been violated by the peer.
bool FlowControlViolation();
+ uint64 bytes_consumed() const { return bytes_consumed_; }
+
+ uint64 highest_received_byte_offset() const {
+ return highest_received_byte_offset_;
+ }
+
private:
friend class test::QuicFlowControllerPeer;
- // Total received bytes is the sum of bytes buffered, and bytes consumed.
- uint64 TotalReceivedBytes() const;
+ // Send a WINDOW_UPDATE frame if appropriate.
+ void MaybeSendWindowUpdate();
+
+ // The parent connection, used to send connection close on flow control
+ // violation, and WINDOW_UPDATE and BLOCKED frames when appropriate.
+ // Not owned.
+ QuicConnection* connection_;
// ID of stream this flow controller belongs to. This can be 0 if this is a
// connection level flow controller.
@@ -91,8 +100,9 @@
// locally.
uint64 bytes_consumed_;
- // Tracks number of bytes received from the peer, and buffered locally.
- uint64 bytes_buffered_;
+ // The highest byte offset we have seen from the peer. This could be the
+ // highest offset in a data frame, or a final value in a RST.
+ uint64 highest_received_byte_offset_;
// Tracks number of bytes sent to the peer.
uint64 bytes_sent_;
diff --git a/net/quic/quic_flow_controller_test.cc b/net/quic/quic_flow_controller_test.cc
index f0bf629..e40dc94 100644
--- a/net/quic/quic_flow_controller_test.cc
+++ b/net/quic/quic_flow_controller_test.cc
@@ -7,6 +7,7 @@
#include "base/strings/stringprintf.h"
#include "net/quic/quic_flags.h"
#include "net/quic/quic_utils.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_flow_controller_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/test/gtest_util.h"
@@ -23,28 +24,26 @@
public:
QuicFlowControllerTest()
: stream_id_(1234),
- send_window_(100),
- receive_window_(200),
- max_receive_window_(200),
- version_(QuicVersionMax()),
+ send_window_(kInitialFlowControlWindowForTest),
+ receive_window_(kInitialFlowControlWindowForTest),
+ max_receive_window_(kInitialFlowControlWindowForTest),
+ connection_(false),
old_flag_(&FLAGS_enable_quic_stream_flow_control_2, true) {
}
void Initialize() {
- flow_controller_.reset(new QuicFlowController(version_, stream_id_, false,
- send_window_, receive_window_,
- max_receive_window_));
+ flow_controller_.reset(new QuicFlowController(
+ &connection_, stream_id_, false, send_window_,
+ receive_window_, max_receive_window_));
}
- void set_version(QuicVersion version) { version_ = version; }
-
protected:
QuicStreamId stream_id_;
uint64 send_window_;
uint64 receive_window_;
uint64 max_receive_window_;
- QuicVersion version_;
scoped_ptr<QuicFlowController> flow_controller_;
+ MockConnection connection_;
ValueRestore<bool> old_flag_;
};
@@ -67,9 +66,8 @@
EXPECT_EQ(0u, flow_controller_->SendWindowSize());
// BLOCKED frame should get sent.
- MockConnection connection(false);
- EXPECT_CALL(connection, SendBlocked(stream_id_)).Times(1);
- flow_controller_->MaybeSendBlocked(&connection);
+ EXPECT_CALL(connection_, SendBlocked(stream_id_)).Times(1);
+ flow_controller_->MaybeSendBlocked();
// Update the send window, and verify this has unblocked.
EXPECT_TRUE(flow_controller_->UpdateSendWindowOffset(2 * send_window_));
@@ -81,6 +79,8 @@
EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
// Try to send more bytes, violating flow control.
+ EXPECT_CALL(connection_,
+ SendConnectionClose(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA));
EXPECT_DFATAL(
flow_controller_->AddBytesSent(send_window_ * 10),
StringPrintf("Trying to send an extra %d bytes",
@@ -95,30 +95,39 @@
EXPECT_TRUE(flow_controller_->IsEnabled());
EXPECT_FALSE(flow_controller_->IsBlocked());
EXPECT_FALSE(flow_controller_->FlowControlViolation());
-
- // Buffer some bytes, not enough to fill window.
- flow_controller_->AddBytesBuffered(receive_window_ / 2);
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(receive_window_ / 2,
+ EXPECT_EQ(kInitialFlowControlWindowForTest,
QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
- // Consume enough bytes to send a WINDOW_UPDATE frame.
- flow_controller_->RemoveBytesBuffered(receive_window_ / 2);
- flow_controller_->AddBytesConsumed(1 + receive_window_ / 2);
+ // Receive some bytes, updating highest received offset, but not enough to
+ // fill flow control receive window.
+ EXPECT_TRUE(
+ flow_controller_->UpdateHighestReceivedOffset(1 + receive_window_ / 2));
EXPECT_FALSE(flow_controller_->FlowControlViolation());
EXPECT_EQ((receive_window_ / 2) - 1,
QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
- MockConnection connection(false);
- EXPECT_CALL(connection, SendWindowUpdate(stream_id_, _)).Times(1);
- flow_controller_->MaybeSendWindowUpdate(&connection);
+ // Consume enough bytes to send a WINDOW_UPDATE frame.
+ EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, _)).Times(1);
+
+ flow_controller_->AddBytesConsumed(1 + receive_window_ / 2);
+
+ // Result is that once again we have a fully open receive window.
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
}
TEST_F(QuicFlowControllerTest,
DisabledWhenQuicVersionDoesNotSupportFlowControl) {
- set_version(QUIC_VERSION_16);
+ // Only support version 16: no flow control.
+ QuicVersionVector supported_versions;
+ supported_versions.push_back(QUIC_VERSION_16);
+ QuicConnectionPeer::SetSupportedVersions(&connection_, supported_versions);
+
Initialize();
+ MockConnection connection(false);
+
// Should not be enabled, and should not report as blocked.
EXPECT_FALSE(flow_controller_->IsEnabled());
EXPECT_FALSE(flow_controller_->IsBlocked());
@@ -132,8 +141,7 @@
flow_controller_.get()));
flow_controller_->AddBytesSent(123);
flow_controller_->AddBytesConsumed(456);
- flow_controller_->AddBytesBuffered(789);
- flow_controller_->RemoveBytesBuffered(321);
+ flow_controller_->UpdateHighestReceivedOffset(789);
EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
EXPECT_EQ(send_window_,
QuicFlowControllerPeer::SendWindowOffset(flow_controller_.get()));
@@ -149,15 +157,14 @@
EXPECT_EQ(send_window_,
QuicFlowControllerPeer::SendWindowOffset(flow_controller_.get()));
- // Should never send WINDOW_UPDATE or BLOCKED frames, even if the internal
- // state implies that it should.
- MockConnection connection(false);
+ // The connection should never send WINDOW_UPDATE or BLOCKED frames, even if
+ // the internal state implies that it should.
// If the flow controller was enabled, then a send window size of 0 would
// trigger a BLOCKED frame to be sent.
EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
- EXPECT_CALL(connection, SendBlocked(_)).Times(0);
- flow_controller_->MaybeSendBlocked(&connection);
+ EXPECT_CALL(connection_, SendBlocked(_)).Times(0);
+ flow_controller_->MaybeSendBlocked();
// If the flow controller was enabled, then a WINDOW_UPDATE would be sent if
// (receive window) < (max receive window / 2)
@@ -165,8 +172,8 @@
max_receive_window_ / 10);
EXPECT_TRUE(QuicFlowControllerPeer::ReceiveWindowSize(
flow_controller_.get()) < (max_receive_window_ / 2));
- EXPECT_CALL(connection, SendWindowUpdate(_, _)).Times(0);
- flow_controller_->MaybeSendWindowUpdate(&connection);
+ EXPECT_CALL(connection_, SendWindowUpdate(_, _)).Times(0);
+ flow_controller_->AddBytesConsumed(0);
// Should not be enabled, and should not report as blocked.
EXPECT_FALSE(flow_controller_->IsEnabled());
@@ -190,18 +197,17 @@
EXPECT_EQ(0u, flow_controller_->SendWindowSize());
// Expect that 2 BLOCKED frames should get sent in total.
- MockConnection connection(false);
- EXPECT_CALL(connection, SendBlocked(stream_id_)).Times(2);
+ EXPECT_CALL(connection_, SendBlocked(stream_id_)).Times(2);
// BLOCKED frame should get sent.
- flow_controller_->MaybeSendBlocked(&connection);
+ flow_controller_->MaybeSendBlocked();
// BLOCKED frame should not get sent again until our send offset changes.
- flow_controller_->MaybeSendBlocked(&connection);
- flow_controller_->MaybeSendBlocked(&connection);
- flow_controller_->MaybeSendBlocked(&connection);
- flow_controller_->MaybeSendBlocked(&connection);
- flow_controller_->MaybeSendBlocked(&connection);
+ flow_controller_->MaybeSendBlocked();
+ flow_controller_->MaybeSendBlocked();
+ flow_controller_->MaybeSendBlocked();
+ flow_controller_->MaybeSendBlocked();
+ flow_controller_->MaybeSendBlocked();
// Update the send window, then send enough bytes to block again.
EXPECT_TRUE(flow_controller_->UpdateSendWindowOffset(2 * send_window_));
@@ -212,7 +218,7 @@
EXPECT_EQ(0u, flow_controller_->SendWindowSize());
// BLOCKED frame should get sent as send offset has changed.
- flow_controller_->MaybeSendBlocked(&connection);
+ flow_controller_->MaybeSendBlocked();
}
} // namespace test
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 8ff2ee7..e44bd2d 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -332,26 +332,6 @@
return header.entropy_flag << (header.packet_sequence_number % 8);
}
-// Test only.
-SerializedPacket QuicFramer::BuildUnsizedDataPacket(
- const QuicPacketHeader& header,
- const QuicFrames& frames) {
- const size_t max_plaintext_size = GetMaxPlaintextSize(kMaxPacketSize);
- size_t packet_size = GetPacketHeaderSize(header);
- for (size_t i = 0; i < frames.size(); ++i) {
- DCHECK_LE(packet_size, max_plaintext_size);
- bool first_frame = i == 0;
- bool last_frame = i == frames.size() - 1;
- const size_t frame_size = GetSerializedFrameLength(
- frames[i], max_plaintext_size - packet_size, first_frame, last_frame,
- header.is_in_fec_group,
- header.public_header.sequence_number_length);
- DCHECK(frame_size);
- packet_size += frame_size;
- }
- return BuildDataPacket(header, frames, packet_size);
-}
-
SerializedPacket QuicFramer::BuildDataPacket(
const QuicPacketHeader& header,
const QuicFrames& frames,
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index a7e8a08..e947eb4 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -306,13 +306,6 @@
QuicSequenceNumberLength sequence_number_length);
// 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.
- SerializedPacket BuildUnsizedDataPacket(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 BuildDataPacket(const QuicPacketHeader& header,
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index 5dd3e35..fd206e1 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -494,6 +494,11 @@
<< " wire_sequence_number: " << wire_sequence_number;
}
+ QuicPacket* BuildDataPacket(const QuicPacketHeader& header,
+ const QuicFrames& frames) {
+ return BuildUnsizedDataPacket(&framer_, header, frames).packet;
+ }
+
test::TestEncrypter* encrypter_;
test::TestDecrypter* decrypter_;
QuicVersion version_;
@@ -2148,8 +2153,7 @@
// Verify that the packet re-serializes identically.
QuicFrames frames;
frames.push_back(QuicFrame(frame));
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(*visitor_.header_, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2210,8 +2214,7 @@
// Verify that the packet re-serializes identically.
QuicFrames frames;
frames.push_back(QuicFrame(frame));
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(*visitor_.header_, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2285,8 +2288,7 @@
// Verify that the packet re-serializes identically.
QuicFrames frames;
frames.push_back(QuicFrame(frame));
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(*visitor_.header_, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2367,8 +2369,7 @@
// Verify that the packet re-serializes identically.
QuicFrames frames;
frames.push_back(QuicFrame(frame));
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(*visitor_.header_, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -3245,8 +3246,7 @@
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1);
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -3292,8 +3292,7 @@
PACKET_4BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1);
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -3339,8 +3338,7 @@
PACKET_2BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1);
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -3386,8 +3384,7 @@
PACKET_1BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1);
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -3440,8 +3437,7 @@
'r', 'l', 'd', '!',
};
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -3496,8 +3492,7 @@
'r', 'l', 'd', '!',
};
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -3552,8 +3547,7 @@
};
QuicFramerPeer::SetIsServer(&framer_, false);
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -3642,8 +3636,7 @@
0x00,
};
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -3713,8 +3706,7 @@
0x00,
};
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -3946,8 +3938,7 @@
0x03, 0x04,
};
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -4016,8 +4007,7 @@
0x02, 0x00, 0x00, 0x00,
};
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -4066,8 +4056,7 @@
0x00, 0x00,
};
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -4113,8 +4102,7 @@
0x01, 0x02, 0x03, 0x04,
};
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -4141,7 +4129,7 @@
scoped_ptr<QuicPacket> data;
EXPECT_DFATAL(
- data.reset(framer_.BuildUnsizedDataPacket(header, frames).packet),
+ data.reset(BuildDataPacket(header, frames)),
"AppendCongestionFeedbackFrame failed");
ASSERT_TRUE(data == NULL);
}
@@ -4195,8 +4183,7 @@
QuicFrames frames;
frames.push_back(QuicFrame(&rst_frame));
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -4246,8 +4233,7 @@
'n',
};
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -4300,8 +4286,7 @@
'n',
};
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -4347,8 +4332,7 @@
0x44, 0x33, 0x22, 0x11,
};
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet", data->data(),
@@ -4390,8 +4374,7 @@
0x04, 0x03, 0x02, 0x01,
};
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet", data->data(),
@@ -4431,8 +4414,7 @@
};
if (version_ > QUIC_VERSION_17) {
- scoped_ptr<QuicPacket> data(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet", data->data(),
@@ -4441,7 +4423,7 @@
} else {
string expected_error =
"Attempt to add a PingFrame in " + QuicVersionToString(version_);
- EXPECT_DFATAL(framer_.BuildUnsizedDataPacket(header, frames),
+ EXPECT_DFATAL(BuildDataPacket(header, frames),
expected_error);
return;
}
@@ -4770,8 +4752,7 @@
QuicFrames frames;
frames.push_back(frame);
- scoped_ptr<QuicPacket> raw_ack_packet(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> raw_ack_packet(BuildDataPacket(header, frames));
ASSERT_TRUE(raw_ack_packet != NULL);
scoped_ptr<QuicEncryptedPacket> ack_packet(
@@ -4819,8 +4800,7 @@
QuicFrames frames;
frames.push_back(frame);
- scoped_ptr<QuicPacket> raw_ack_packet(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ scoped_ptr<QuicPacket> raw_ack_packet(BuildDataPacket(header, frames));
ASSERT_TRUE(raw_ack_packet != NULL);
scoped_ptr<QuicEncryptedPacket> ack_packet(
@@ -4838,8 +4818,7 @@
frames.push_back(frame);
size_t original_raw_length = raw_ack_packet->length();
- raw_ack_packet.reset(
- framer_.BuildUnsizedDataPacket(header, frames).packet);
+ raw_ack_packet.reset(BuildDataPacket(header, frames));
ASSERT_TRUE(raw_ack_packet != NULL);
EXPECT_EQ(original_raw_length, raw_ack_packet->length());
ASSERT_TRUE(raw_ack_packet != NULL);
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 9fc78d9..66261d4 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -214,6 +214,8 @@
false, PRIVACY_MODE_DISABLED),
DefaultQuicConfig(),
kInitialFlowControlWindowForTest, &crypto_config_,
+ base::MessageLoop::current()->
+ message_loop_proxy().get(),
NULL));
session_->GetCryptoStream()->CryptoConnect();
EXPECT_TRUE(session_->IsCryptoHandshakeConfirmed());
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index cb67569..af6fb7b 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -831,6 +831,11 @@
AddHangingNonAlternateProtocolSocketData();
+ // Second Alternate-protocol job which will race with the TCP job.
+ StaticSocketDataProvider quic_data2(quic_reads, arraysize(quic_reads),
+ NULL, 0);
+ socket_factory_.AddSocketDataProvider(&quic_data2);
+
// Final job that will proceed when the QUIC job fails.
MockRead http_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n\r\n"),
@@ -855,6 +860,34 @@
EXPECT_TRUE(quic_data.at_write_eof());
}
+TEST_P(QuicNetworkTransactionTest, HangingZeroRttFallback) {
+ // Alternate-protocol job
+ MockRead quic_reads[] = {
+ MockRead(ASYNC, ERR_IO_PENDING),
+ };
+ StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads),
+ NULL, 0);
+ socket_factory_.AddSocketDataProvider(&quic_data);
+
+ // Main job that will proceed when the QUIC job fails.
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n\r\n"),
+ MockRead("hello from http"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)
+ };
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads),
+ NULL, 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+
+ CreateSessionWithNextProtos();
+
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+
+ SendRequestAndExpectHttpResponse("hello from http");
+}
+
TEST_P(QuicNetworkTransactionTest, BrokenAlternateProtocolOnConnectFailure) {
// Alternate-protocol job will fail before creating a QUIC session.
StaticSocketDataProvider quic_data(NULL, 0, NULL, 0);
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index 4b64ae5..f7d2d14 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -68,7 +68,11 @@
fec_group_number_(0),
is_server_(is_server),
send_version_in_packet_(!is_server),
- sequence_number_length_(options_.send_sequence_number_length),
+ max_packet_length_(kDefaultMaxPacketSize),
+ max_packets_per_fec_group_(0),
+ connection_id_length_(PACKET_8BYTE_CONNECTION_ID),
+ next_sequence_number_length_(PACKET_1BYTE_SEQUENCE_NUMBER),
+ sequence_number_length_(next_sequence_number_length_),
packet_size_(0) {
framer_->set_fec_builder(this);
}
@@ -87,7 +91,7 @@
bool QuicPacketCreator::ShouldSendFec(bool force_close) const {
return fec_group_.get() != NULL && fec_group_->NumReceivedPackets() > 0 &&
(force_close || fec_group_->NumReceivedPackets() >=
- options_.max_packets_per_fec_group);
+ max_packets_per_fec_group_);
}
void QuicPacketCreator::StartFecProtectingPackets() {
@@ -123,18 +127,7 @@
}
bool QuicPacketCreator::IsFecEnabled() const {
- return options_.max_packets_per_fec_group > 0;
-}
-
-size_t QuicPacketCreator::max_packets_per_fec_group() const {
- return options_.max_packets_per_fec_group;
-}
-
-void QuicPacketCreator::set_max_packets_per_fec_group(
- size_t max_packets_per_fec_group) {
- // To turn off FEC protection, use StopFecProtectingPackets().
- DCHECK_NE(0u, max_packets_per_fec_group);
- options_.max_packets_per_fec_group = max_packets_per_fec_group;
+ return max_packets_per_fec_group_ > 0;
}
InFecGroup QuicPacketCreator::MaybeUpdateLengthsAndStartFec() {
@@ -147,8 +140,9 @@
// Don't change creator state if there are frames queued.
return fec_group_.get() == NULL ? NOT_IN_FEC_GROUP : IN_FEC_GROUP;
}
- // TODO(jri): Add max_packet_length and send_connection_id_length here too.
- sequence_number_length_ = options_.send_sequence_number_length;
+
+ // Update sequence number length only on packet and FEC group boundaries.
+ sequence_number_length_ = next_sequence_number_length_;
if (!should_fec_protect_) {
return NOT_IN_FEC_GROUP;
@@ -179,12 +173,12 @@
// Since the packet creator will not change sequence number length mid FEC
// group, include the size of an FEC group to be safe.
const QuicPacketSequenceNumber current_delta =
- options_.max_packets_per_fec_group + sequence_number_ + 1
+ max_packets_per_fec_group_ + sequence_number_ + 1
- least_packet_awaited_by_peer;
const uint64 congestion_window_packets =
- congestion_window / options_.max_packet_length;
+ congestion_window / max_packet_length_;
const uint64 delta = max(current_delta, congestion_window_packets);
- options_.send_sequence_number_length =
+ next_sequence_number_length_ =
QuicFramer::GetMinSequenceNumberLength(delta * 4);
}
@@ -219,8 +213,7 @@
QuicStreamOffset offset,
bool fin,
QuicFrame* frame) {
- DCHECK_GT(options_.max_packet_length,
- StreamFramePacketOverhead(
+ DCHECK_GT(max_packet_length_, StreamFramePacketOverhead(
framer_->version(), PACKET_8BYTE_CONNECTION_ID, kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, offset, IN_FEC_GROUP));
@@ -277,19 +270,19 @@
QuicSequenceNumberLength original_length) {
DCHECK(fec_group_.get() == NULL);
const QuicSequenceNumberLength saved_length = sequence_number_length_;
- const QuicSequenceNumberLength saved_options_length =
- options_.send_sequence_number_length;
+ const QuicSequenceNumberLength saved_next_length =
+ next_sequence_number_length_;
const bool saved_should_fec_protect = should_fec_protect_;
// Temporarily set the sequence number length and stop FEC protection.
sequence_number_length_ = original_length;
- options_.send_sequence_number_length = original_length;
+ next_sequence_number_length_ = original_length;
should_fec_protect_ = false;
// Serialize the packet and restore the FEC and sequence number length state.
SerializedPacket serialized_packet = SerializeAllFrames(frames);
sequence_number_length_ = saved_length;
- options_.send_sequence_number_length = saved_options_length;
+ next_sequence_number_length_ = saved_next_length;
should_fec_protect_ = saved_should_fec_protect;
return serialized_packet;
@@ -330,26 +323,23 @@
size_t QuicPacketCreator::BytesFree() const {
const size_t max_plaintext_size =
- framer_->GetMaxPlaintextSize(options_.max_packet_length);
+ framer_->GetMaxPlaintextSize(max_packet_length_);
DCHECK_GE(max_plaintext_size, PacketSize());
return max_plaintext_size - min(max_plaintext_size, PacketSize()
+ ExpansionOnNewFrame());
}
size_t QuicPacketCreator::PacketSize() const {
- if (queued_frames_.empty()) {
- // Only adjust the sequence number length when the FEC group is not open,
- // to ensure no packets in a group are too large.
- if (fec_group_.get() == NULL ||
- fec_group_->NumReceivedPackets() == 0) {
- sequence_number_length_ = options_.send_sequence_number_length;
- }
- packet_size_ = GetPacketHeaderSize(options_.send_connection_id_length,
- send_version_in_packet_,
- sequence_number_length_,
- should_fec_protect_ ? IN_FEC_GROUP :
- NOT_IN_FEC_GROUP);
+ if (!queued_frames_.empty()) {
+ return packet_size_;
}
+ if (fec_group_.get() == NULL) {
+ // Update sequence number length on packet and FEC boundary.
+ sequence_number_length_ = next_sequence_number_length_;
+ }
+ packet_size_ = GetPacketHeaderSize(
+ connection_id_length_, send_version_in_packet_, sequence_number_length_,
+ should_fec_protect_ ? IN_FEC_GROUP : NOT_IN_FEC_GROUP);
return packet_size_;
}
@@ -367,7 +357,7 @@
MaybeAddPadding();
size_t max_plaintext_size =
- framer_->GetMaxPlaintextSize(options_.max_packet_length);
+ framer_->GetMaxPlaintextSize(max_packet_length_);
DCHECK_GE(max_plaintext_size, packet_size_);
// ACK Frames will be truncated only if they're the only frame in the packet,
// and if packet_size_ was set to max_plaintext_size. If truncation occurred,
@@ -384,7 +374,6 @@
if (!possibly_truncated) {
DCHECK_EQ(packet_size_, serialized.packet->length());
}
-
packet_size_ = 0;
queued_frames_.clear();
serialized.retransmittable_frames = queued_retransmittable_frames_.release();
@@ -409,7 +398,7 @@
packet_size_ = 0;
LOG_IF(DFATAL, !serialized.packet)
<< "Failed to serialize fec packet for group:" << fec_data.fec_group;
- DCHECK_GE(options_.max_packet_length, serialized.packet->length());
+ DCHECK_GE(max_packet_length_, serialized.packet->length());
return serialized;
}
@@ -431,7 +420,7 @@
QuicEncryptedPacket* encrypted =
framer_->BuildVersionNegotiationPacket(header, supported_versions);
DCHECK(encrypted);
- DCHECK_GE(options_.max_packet_length, encrypted->length());
+ DCHECK_GE(max_packet_length_, encrypted->length());
return encrypted;
}
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index 36ab5df..0e19887 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -29,22 +29,6 @@
class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
public:
- // Options for controlling how packets are created.
- struct Options {
- Options()
- : max_packet_length(kDefaultMaxPacketSize),
- max_packets_per_fec_group(0),
- send_connection_id_length(PACKET_8BYTE_CONNECTION_ID),
- send_sequence_number_length(PACKET_1BYTE_SEQUENCE_NUMBER) {}
-
- size_t max_packet_length;
- // 0 indicates fec is disabled.
- size_t max_packets_per_fec_group;
- // Length of connection_id to send over the wire.
- QuicConnectionIdLength send_connection_id_length;
- QuicSequenceNumberLength send_sequence_number_length;
- };
-
// QuicRandom* required for packet entropy.
QuicPacketCreator(QuicConnectionId connection_id,
QuicFramer* framer,
@@ -63,21 +47,15 @@
void StartFecProtectingPackets();
// Turn off FEC protection for subsequently created packets. If the creator
- // has any open fec group, call will fail. It is the caller's responsibility
+ // has any open FEC group, call will fail. It is the caller's responsibility
// to flush out FEC packets in generation, and to verify with ShouldSendFec()
// that there is no open FEC group.
void StopFecProtectingPackets();
// Checks if it's time to send an FEC packet. |force_close| forces this to
- // return true if an fec group is open.
+ // return true if an FEC group is open.
bool ShouldSendFec(bool force_close) const;
- // Returns current max number of packets covered by an FEC group.
- size_t max_packets_per_fec_group() const;
-
- // Sets creator's max number of packets covered by an FEC group.
- void set_max_packets_per_fec_group(size_t max_packets_per_fec_group);
-
// Makes the framer not serialize the protocol version in sent packets.
void StopSendingVersion();
@@ -213,8 +191,39 @@
sequence_number_ = s;
}
- Options* options() {
- return &options_;
+ QuicConnectionIdLength connection_id_length() const {
+ return connection_id_length_;
+ }
+
+ QuicSequenceNumberLength next_sequence_number_length() const {
+ return next_sequence_number_length_;
+ }
+
+ void set_next_sequence_number_length(QuicSequenceNumberLength length) {
+ next_sequence_number_length_ = length;
+ }
+
+ size_t max_packet_length() const {
+ return max_packet_length_;
+ }
+
+ void set_max_packet_length(size_t length) {
+ // |max_packet_length_| should not be changed mid-packet or mid-FEC group.
+ DCHECK(fec_group_.get() == NULL && queued_frames_.empty());
+ max_packet_length_ = length;
+ }
+
+ // Returns current max number of packets covered by an FEC group.
+ size_t max_packets_per_fec_group() const {
+ return max_packets_per_fec_group_;
+ }
+
+ // Sets creator's max number of packets covered by an FEC group.
+ void set_max_packets_per_fec_group(
+ size_t max_packets_per_fec_group) {
+ // To turn off FEC protection, use StopFecProtectingPackets().
+ DCHECK_NE(0u, max_packets_per_fec_group);
+ max_packets_per_fec_group_ = max_packets_per_fec_group;
}
private:
@@ -222,9 +231,12 @@
static bool ShouldRetransmit(const QuicFrame& frame);
- // Updates sequence number length on a packet or FEC group boundary.
- // Also starts an FEC group if FEC protection is on and there is not already
- // an FEC group open.
+ // Updates sequence number and max packet lengths on a packet or FEC group
+ // boundary.
+ void MaybeUpdateLengths();
+
+ // Updates lengths and also starts an FEC group if FEC protection is on and
+ // there is not already an FEC group open.
InFecGroup MaybeUpdateLengthsAndStartFec();
void FillPacketHeader(QuicFecGroupNumber fec_group,
@@ -240,7 +252,6 @@
// padding frame.
void MaybeAddPadding();
- Options options_;
QuicConnectionId connection_id_;
EncryptionLevel encryption_level_;
QuicFramer* framer_;
@@ -255,9 +266,20 @@
// Controls whether protocol version should be included while serializing the
// packet.
bool send_version_in_packet_;
- // The sequence number length for the current packet and the current FEC group
- // if FEC is enabled.
- // Mutable so PacketSize() can adjust it when the packet is empty.
+ // Maximum length including headers and encryption (UDP payload length.)
+ size_t max_packet_length_;
+ // 0 indicates FEC is disabled.
+ size_t max_packets_per_fec_group_;
+ // Length of connection_id to send over the wire.
+ QuicConnectionIdLength connection_id_length_;
+ // Staging variable to hold next packet sequence number length. When sequence
+ // number length is to be changed, this variable holds the new length until
+ // a packet or FEC group boundary, when the creator's sequence_number_length_
+ // can be changed to this new value.
+ QuicSequenceNumberLength next_sequence_number_length_;
+ // Sequence number length for the current packet and for the current FEC group
+ // when FEC is enabled. Mutable so PacketSize() can adjust it when the packet
+ // is empty.
mutable QuicSequenceNumberLength sequence_number_length_;
// packet_size_ is mutable because it's just a cache of the current size.
// packet_size should never be read directly, use PacketSize() instead.
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index 57bf2f4..d4b7f44 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -100,18 +100,17 @@
// Returns the number of bytes consumed by the header of packet, including
// the version.
size_t GetPacketHeaderOverhead(InFecGroup is_in_fec_group) {
- return GetPacketHeaderSize(creator_.options()->send_connection_id_length,
+ return GetPacketHeaderSize(creator_.connection_id_length(),
kIncludeVersion,
- creator_.options()->send_sequence_number_length,
+ creator_.next_sequence_number_length(),
is_in_fec_group);
}
// Returns the number of bytes of overhead that will be added to a packet
// of maximum length.
size_t GetEncryptionOverhead() {
- return creator_.options()->max_packet_length -
- client_framer_.GetMaxPlaintextSize(
- creator_.options()->max_packet_length);
+ return creator_.max_packet_length() - client_framer_.GetMaxPlaintextSize(
+ creator_.max_packet_length());
}
// Returns the number of bytes consumed by the non-data fields of a stream
@@ -216,8 +215,7 @@
TEST_P(QuicPacketCreatorTest, SerializeChangingSequenceNumberLength) {
frames_.push_back(QuicFrame(new QuicAckFrame(MakeAckFrame(0u, 0u))));
creator_.AddSavedFrame(frames_[0]);
- creator_.options()->send_sequence_number_length =
- PACKET_4BYTE_SEQUENCE_NUMBER;
+ creator_.set_next_sequence_number_length(PACKET_4BYTE_SEQUENCE_NUMBER);
SerializedPacket serialized = creator_.SerializePacket();
// The sequence number length will not change mid-packet.
EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER, serialized.sequence_number_length);
@@ -270,8 +268,7 @@
creator_.AddSavedFrame(ack_frame);
// Now change sequence number length.
- creator_.options()->send_sequence_number_length =
- PACKET_4BYTE_SEQUENCE_NUMBER;
+ creator_.set_next_sequence_number_length(PACKET_4BYTE_SEQUENCE_NUMBER);
// Add a STOP_WAITING frame since it contains a packet sequence number,
// whose length should be 1.
@@ -351,8 +348,7 @@
// Generate Packet 1.
creator_.AddSavedFrame(frames_[0]);
// Change the sequence number length mid-FEC group and it should not change.
- creator_.options()->send_sequence_number_length =
- PACKET_4BYTE_SEQUENCE_NUMBER;
+ creator_.set_next_sequence_number_length(PACKET_4BYTE_SEQUENCE_NUMBER);
SerializedPacket serialized = creator_.SerializePacket();
EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER, serialized.sequence_number_length);
@@ -424,15 +420,14 @@
// If the original packet sequence number length, the current sequence number
// length, and the configured send sequence number length are different, the
// retransmit must sent with the original length and the others do not change.
- creator_.options()->send_sequence_number_length =
- PACKET_4BYTE_SEQUENCE_NUMBER;
+ creator_.set_next_sequence_number_length(PACKET_4BYTE_SEQUENCE_NUMBER);
QuicPacketCreatorPeer::SetSequenceNumberLength(&creator_,
PACKET_2BYTE_SEQUENCE_NUMBER);
frames_.push_back(QuicFrame(new QuicStreamFrame(0u, false, 0u, IOVector())));
SerializedPacket serialized =
creator_.ReserializeAllFrames(frames_, PACKET_1BYTE_SEQUENCE_NUMBER);
EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
- creator_.options()->send_sequence_number_length);
+ creator_.next_sequence_number_length());
EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
QuicPacketCreatorPeer::GetSequenceNumberLength(&creator_));
EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER, serialized.sequence_number_length);
@@ -582,7 +577,7 @@
const size_t overhead = GetPacketHeaderOverhead(NOT_IN_FEC_GROUP)
+ GetEncryptionOverhead();
for (size_t i = overhead; i < overhead + 100; ++i) {
- creator_.options()->max_packet_length = i;
+ creator_.set_max_packet_length(i);
const bool should_have_room = i > overhead + GetStreamFrameOverhead(
NOT_IN_FEC_GROUP);
ASSERT_EQ(should_have_room, creator_.HasRoomForStreamFrame(
@@ -740,49 +735,49 @@
TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) {
EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
- creator_.options()->send_sequence_number_length);
+ creator_.next_sequence_number_length());
creator_.set_sequence_number(64);
creator_.UpdateSequenceNumberLength(2, 10000);
EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
- creator_.options()->send_sequence_number_length);
+ creator_.next_sequence_number_length());
creator_.set_sequence_number(64 * 256);
creator_.UpdateSequenceNumberLength(2, 10000);
EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
- creator_.options()->send_sequence_number_length);
+ creator_.next_sequence_number_length());
creator_.set_sequence_number(64 * 256 * 256);
creator_.UpdateSequenceNumberLength(2, 10000);
EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
- creator_.options()->send_sequence_number_length);
+ creator_.next_sequence_number_length());
creator_.set_sequence_number(GG_UINT64_C(64) * 256 * 256 * 256 * 256);
creator_.UpdateSequenceNumberLength(2, 10000);
EXPECT_EQ(PACKET_6BYTE_SEQUENCE_NUMBER,
- creator_.options()->send_sequence_number_length);
+ creator_.next_sequence_number_length());
}
TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthBandwidth) {
EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
- creator_.options()->send_sequence_number_length);
+ creator_.next_sequence_number_length());
creator_.UpdateSequenceNumberLength(1, 10000);
EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
- creator_.options()->send_sequence_number_length);
+ creator_.next_sequence_number_length());
creator_.UpdateSequenceNumberLength(1, 10000 * 256);
EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
- creator_.options()->send_sequence_number_length);
+ creator_.next_sequence_number_length());
creator_.UpdateSequenceNumberLength(1, 10000 * 256 * 256);
EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
- creator_.options()->send_sequence_number_length);
+ creator_.next_sequence_number_length());
creator_.UpdateSequenceNumberLength(
1, GG_UINT64_C(1000) * 256 * 256 * 256 * 256);
EXPECT_EQ(PACKET_6BYTE_SEQUENCE_NUMBER,
- creator_.options()->send_sequence_number_length);
+ creator_.next_sequence_number_length());
}
TEST_P(QuicPacketCreatorTest, CreateStreamFrameWithNotifier) {
@@ -833,10 +828,10 @@
}
// A string larger than fits into a frame.
size_t payload_length;
- creator_.options()->max_packet_length = GetPacketLengthForOneStream(
+ creator_.set_max_packet_length(GetPacketLengthForOneStream(
client_framer_.version(),
QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
- PACKET_1BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP, &payload_length);
+ PACKET_1BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP, &payload_length));
QuicFrame frame;
const string too_long_payload(payload_length * 2, 'a');
size_t consumed = creator_.CreateStreamFrame(
@@ -852,11 +847,11 @@
creator_.StopSendingVersion();
}
const size_t max_plaintext_size =
- client_framer_.GetMaxPlaintextSize(creator_.options()->max_packet_length);
+ client_framer_.GetMaxPlaintextSize(creator_.max_packet_length());
EXPECT_FALSE(creator_.HasPendingFrames());
EXPECT_EQ(max_plaintext_size -
GetPacketHeaderSize(
- creator_.options()->send_connection_id_length,
+ creator_.connection_id_length(),
QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
PACKET_1BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
creator_.BytesFree());
@@ -900,7 +895,7 @@
EXPECT_FALSE(creator_.HasPendingFrames());
EXPECT_EQ(max_plaintext_size -
GetPacketHeaderSize(
- creator_.options()->send_connection_id_length,
+ creator_.connection_id_length(),
QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
PACKET_1BYTE_SEQUENCE_NUMBER,
NOT_IN_FEC_GROUP),
@@ -911,9 +906,9 @@
if (!GetParam().version_serialization) {
creator_.StopSendingVersion();
}
- creator_.options()->max_packet_length = kMaxPacketSize;
+ creator_.set_max_packet_length(kMaxPacketSize);
const size_t max_plaintext_size =
- client_framer_.GetMaxPlaintextSize(creator_.options()->max_packet_length);
+ client_framer_.GetMaxPlaintextSize(creator_.max_packet_length());
// Serialized length of ack frame with 2000 nack ranges should be limited by
// the number of nack ranges that can be fit in an ack frame.
@@ -955,9 +950,10 @@
if (!GetParam().version_serialization) {
creator_.StopSendingVersion();
}
- creator_.options()->max_packet_length = 500u;
+ creator_.set_max_packet_length(500u);
+
const size_t max_plaintext_size =
- client_framer_.GetMaxPlaintextSize(creator_.options()->max_packet_length);
+ client_framer_.GetMaxPlaintextSize(creator_.max_packet_length());
EXPECT_EQ(max_plaintext_size - creator_.PacketSize(), creator_.BytesFree());
// Serialized length of ack frame with 2000 nack ranges should be limited by
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index 785c940..b91ccc6 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -16,7 +16,7 @@
class QuicAckNotifier;
QuicPacketGenerator::QuicPacketGenerator(DelegateInterface* delegate,
- DebugDelegateInterface* debug_delegate,
+ DebugDelegate* debug_delegate,
QuicPacketCreator* creator)
: delegate_(delegate),
debug_delegate_(debug_delegate),
diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h
index 12caf34..957477a 100644
--- a/net/quic/quic_packet_generator.h
+++ b/net/quic/quic_packet_generator.h
@@ -54,6 +54,7 @@
#define NET_QUIC_QUIC_PACKET_GENERATOR_H_
#include "net/quic/quic_packet_creator.h"
+#include "net/quic/quic_types.h"
namespace net {
@@ -78,16 +79,16 @@
// Interface which gets callbacks from the QuicPacketGenerator at interesting
// points. Implementations must not mutate the state of the generator
// as a result of these callbacks.
- class NET_EXPORT_PRIVATE DebugDelegateInterface {
+ class NET_EXPORT_PRIVATE DebugDelegate {
public:
- virtual ~DebugDelegateInterface() {}
+ virtual ~DebugDelegate() {}
// Called when a frame has been added to the current packet.
virtual void OnFrameAddedToPacket(const QuicFrame& frame) {}
};
QuicPacketGenerator(DelegateInterface* delegate,
- DebugDelegateInterface* debug_delegate,
+ DebugDelegate* debug_delegate,
QuicPacketCreator* creator);
virtual ~QuicPacketGenerator();
@@ -131,7 +132,7 @@
bool HasQueuedFrames() const;
- void set_debug_delegate(DebugDelegateInterface* debug_delegate) {
+ void set_debug_delegate(DebugDelegate* debug_delegate) {
debug_delegate_ = debug_delegate;
}
@@ -152,7 +153,7 @@
void SerializeAndSendPacket();
DelegateInterface* delegate_;
- DebugDelegateInterface* debug_delegate_;
+ DebugDelegate* debug_delegate_;
QuicPacketCreator* packet_creator_;
QuicFrames queued_control_frames_;
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index 16f9748..c06f6f6 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -231,7 +231,7 @@
scoped_ptr<char[]> data_array_;
};
-class MockDebugDelegate : public QuicPacketGenerator::DebugDelegateInterface {
+class MockDebugDelegate : public QuicPacketGenerator::DebugDelegate {
public:
MOCK_METHOD1(OnFrameAddedToPacket,
void(const QuicFrame&));
@@ -503,11 +503,11 @@
TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
// Set the packet size be enough for two stream frames with 0 stream offset,
// but not enough for a stream frame of 0 offset and one with non-zero offset.
- creator_.options()->max_packet_length =
+ size_t length =
NullEncrypter().GetCiphertextSize(0) +
- GetPacketHeaderSize(creator_.options()->send_connection_id_length,
+ GetPacketHeaderSize(creator_.connection_id_length(),
true,
- creator_.options()->send_sequence_number_length,
+ creator_.next_sequence_number_length(),
NOT_IN_FEC_GROUP) +
// Add an extra 3 bytes for the payload and 1 byte so BytesFree is larger
// than the GetMinStreamFrameSize.
@@ -515,6 +515,7 @@
NOT_IN_FEC_GROUP) + 3 +
QuicFramer::GetMinStreamFrameSize(framer_.version(), 1, 0, true,
NOT_IN_FEC_GROUP) + 1;
+ creator_.set_max_packet_length(length);
delegate_.SetCanWriteAnything();
{
InSequence dummy;
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index df3bfa5..cd73694 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -144,6 +144,11 @@
static_cast<uint32>(d) << 24;
}
+bool ContainsQuicTag(const QuicTagVector& tag_vector, QuicTag tag) {
+ return std::find(tag_vector.begin(), tag_vector.end(), tag)
+ != tag_vector.end();
+}
+
QuicVersionVector QuicSupportedVersions() {
QuicVersionVector supported_versions;
for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
@@ -746,6 +751,7 @@
sent_time(QuicTime::Zero()),
bytes_sent(0),
nack_count(0),
+ transmission_type(NOT_RETRANSMISSION),
all_transmissions(NULL),
in_flight(false) { }
@@ -758,6 +764,7 @@
sent_time(QuicTime::Zero()),
bytes_sent(0),
nack_count(0),
+ transmission_type(NOT_RETRANSMISSION),
all_transmissions(new SequenceNumberSet),
in_flight(false) {
all_transmissions->insert(sequence_number);
@@ -767,38 +774,17 @@
RetransmittableFrames* retransmittable_frames,
QuicPacketSequenceNumber sequence_number,
QuicSequenceNumberLength sequence_number_length,
+ TransmissionType transmission_type,
SequenceNumberSet* all_transmissions)
: retransmittable_frames(retransmittable_frames),
sequence_number_length(sequence_number_length),
sent_time(QuicTime::Zero()),
bytes_sent(0),
nack_count(0),
+ transmission_type(transmission_type),
all_transmissions(all_transmissions),
in_flight(false) {
all_transmissions->insert(sequence_number);
}
-QuicConsumedData::QuicConsumedData(size_t bytes_consumed,
- bool fin_consumed)
- : bytes_consumed(bytes_consumed),
- fin_consumed(fin_consumed) {
-}
-
-ostream& operator<<(ostream& os, const QuicConsumedData& s) {
- os << "bytes_consumed: " << s.bytes_consumed
- << " fin_consumed: " << s.fin_consumed;
- return os;
-}
-
-WriteResult::WriteResult()
- : status(WRITE_STATUS_ERROR),
- bytes_written(0) {
-}
-
-WriteResult::WriteResult(WriteStatus status,
- int bytes_written_or_error_code)
- : status(status),
- bytes_written(bytes_written_or_error_code) {
-}
-
} // namespace net
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 6fb423a..76b31f4 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -318,6 +318,9 @@
// MakeQuicTag('C', 'H', 'L', 'O');
NET_EXPORT_PRIVATE QuicTag MakeQuicTag(char a, char b, char c, char d);
+// Returns true if the tag vector contains the specified tag.
+bool ContainsQuicTag(const QuicTagVector& tag_vector, QuicTag tag);
+
// Size in bytes of the data or fec packet header.
NET_EXPORT_PRIVATE size_t GetPacketHeaderSize(const QuicPacketHeader& header);
@@ -451,8 +454,12 @@
QUIC_INVALID_STREAM_FRAME = 50,
// We received invalid data on the headers stream.
QUIC_INVALID_HEADERS_STREAM_DATA = 56,
- // The peer violated the flow control protocol.
- QUIC_FLOW_CONTROL_ERROR = 59,
+ // The peer received too much data, violating flow control.
+ QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA = 59,
+ // The peer sent too much data, violating flow control.
+ QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA = 63,
+ // The peer received an invalid flow control window.
+ QUIC_FLOW_CONTROL_INVALID_WINDOW = 64,
// The connection has been IP pooled into an existing connection.
QUIC_CONNECTION_IP_POOLED = 62,
@@ -510,7 +517,7 @@
QUIC_VERSION_NEGOTIATION_MISMATCH = 55,
// No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 63,
+ QUIC_LAST_ERROR = 65,
};
struct NET_EXPORT_PRIVATE QuicPacketPublicHeader {
@@ -1027,6 +1034,7 @@
TransmissionInfo(RetransmittableFrames* retransmittable_frames,
QuicPacketSequenceNumber sequence_number,
QuicSequenceNumberLength sequence_number_length,
+ TransmissionType transmission_type,
SequenceNumberSet* all_transmissions);
RetransmittableFrames* retransmittable_frames;
@@ -1036,6 +1044,8 @@
// Zero when the packet is serialized, non-zero once it's sent.
QuicByteCount bytes_sent;
size_t nack_count;
+ // Reason why this packet was transmitted.
+ TransmissionType transmission_type;
// Stores the sequence numbers of all transmissions of this packet.
// Can never be null.
SequenceNumberSet* all_transmissions;
@@ -1043,43 +1053,6 @@
bool in_flight;
};
-// A struct for functions which consume data payloads and fins.
-struct NET_EXPORT_PRIVATE QuicConsumedData {
- QuicConsumedData(size_t bytes_consumed, bool fin_consumed);
-
- // By default, gtest prints the raw bytes of an object. The bool data
- // member causes this object to have padding bytes, which causes the
- // default gtest object printer to read uninitialize memory. So we need
- // to teach gtest how to print this object.
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(
- std::ostream& os, const QuicConsumedData& s);
-
- // How many bytes were consumed.
- size_t bytes_consumed;
-
- // True if an incoming fin was consumed.
- bool fin_consumed;
-};
-
-enum WriteStatus {
- WRITE_STATUS_OK,
- WRITE_STATUS_BLOCKED,
- WRITE_STATUS_ERROR,
-};
-
-// A struct used to return the result of write calls including either the number
-// of bytes written or the error code, depending upon the status.
-struct NET_EXPORT_PRIVATE WriteResult {
- WriteResult(WriteStatus status, int bytes_written_or_error_code);
- WriteResult();
-
- WriteStatus status;
- union {
- int bytes_written; // only valid when status is OK
- int error_code; // only valid when status is ERROR
- };
-};
-
} // namespace net
#endif // NET_QUIC_QUIC_PROTOCOL_H_
diff --git a/net/quic/quic_reliable_client_stream.cc b/net/quic/quic_reliable_client_stream.cc
index 6445ff2..4eb74d6 100644
--- a/net/quic/quic_reliable_client_stream.cc
+++ b/net/quic/quic_reliable_client_stream.cc
@@ -93,8 +93,7 @@
}
bool QuicReliableClientStream::CanWrite(const CompletionCallback& callback) {
- bool can_write = session()->connection()->CanWrite(
- NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+ bool can_write = session()->connection()->CanWrite(HAS_RETRANSMITTABLE_DATA);
if (!can_write) {
session()->MarkWriteBlocked(id(), EffectivePriority());
DCHECK(callback_.is_null());
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index eaf66bd..8c41b9c 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -62,6 +62,7 @@
is_server_(is_server),
clock_(clock),
stats_(stats),
+ debug_delegate_(NULL),
send_algorithm_(
SendAlgorithmInterface::Create(clock, &rtt_stats_, type, stats)),
loss_algorithm_(LossDetectionInterface::Create(loss_type)),
@@ -69,6 +70,7 @@
consecutive_rto_count_(0),
consecutive_tlp_count_(0),
consecutive_crypto_retransmission_count_(0),
+ pending_tlp_transmission_(false),
max_tail_loss_probes_(kDefaultMaxTailLossProbes),
using_pacing_(false) {
}
@@ -82,7 +84,13 @@
rtt_stats_.set_initial_rtt_us(min(kMaxInitialRoundTripTimeUs,
config.ReceivedInitialRoundTripTimeUs()));
}
- if (config.congestion_control() == kPACE) {
+ // TODO(ianswett): BBR is currently a server only feature.
+ if (config.HasReceivedCongestionOptions() &&
+ ContainsQuicTag(config.ReceivedCongestionOptions(), kTBBR)) {
+ send_algorithm_.reset(
+ SendAlgorithmInterface::Create(clock_, &rtt_stats_, kTCPBBR, stats_));
+ }
+ if (config.congestion_feedback() == kPACE) {
MaybeEnablePacing();
}
if (config.HasReceivedLossDetection() &&
@@ -106,9 +114,17 @@
void QuicSentPacketManager::OnRetransmittedPacket(
QuicPacketSequenceNumber old_sequence_number,
QuicPacketSequenceNumber new_sequence_number) {
- DCHECK(ContainsKey(pending_retransmissions_, old_sequence_number));
-
- pending_retransmissions_.erase(old_sequence_number);
+ TransmissionType transmission_type;
+ PendingRetransmissionMap::iterator it =
+ pending_retransmissions_.find(old_sequence_number);
+ if (it != pending_retransmissions_.end()) {
+ transmission_type = it->second;
+ pending_retransmissions_.erase(it);
+ } else {
+ DLOG(DFATAL) << "Expected sequence number to be in "
+ "pending_retransmissions_. sequence_number: " << old_sequence_number;
+ transmission_type = NOT_RETRANSMISSION;
+ }
// A notifier may be waiting to hear about ACKs for the original sequence
// number. Inform them that the sequence number has changed.
@@ -116,7 +132,8 @@
new_sequence_number);
unacked_packets_.OnRetransmittedPacket(old_sequence_number,
- new_sequence_number);
+ new_sequence_number,
+ transmission_type);
}
void QuicSentPacketManager::OnIncomingAck(
@@ -269,6 +286,27 @@
pending_retransmissions_[sequence_number] = transmission_type;
}
+void QuicSentPacketManager::RecordSpuriousRetransmissions(
+ const SequenceNumberSet& all_transmissions,
+ QuicPacketSequenceNumber acked_sequence_number) {
+ for (SequenceNumberSet::const_iterator
+ it = all_transmissions.upper_bound(acked_sequence_number),
+ end = all_transmissions.end();
+ it != end;
+ ++it) {
+ const TransmissionInfo& retransmit_info =
+ unacked_packets_.GetTransmissionInfo(*it);
+
+ stats_->bytes_spuriously_retransmitted += retransmit_info.bytes_sent;
+ ++stats_->packets_spuriously_retransmitted;
+ if (debug_delegate_ != NULL) {
+ debug_delegate_->OnSpuriousPacketRetransmition(
+ retransmit_info.transmission_type,
+ retransmit_info.bytes_sent);
+ }
+ }
+}
+
bool QuicSentPacketManager::HasPendingRetransmissions() const {
return !pending_retransmissions_.empty();
}
@@ -341,19 +379,22 @@
// Remove the most recent packet, if it is pending retransmission.
pending_retransmissions_.erase(newest_transmission);
+ // Notify observers about the ACKed packet.
+ {
+ // The AckNotifierManager needs to be notified about the most recent
+ // transmission, since that's the one only one it tracks.
+ ack_notifier_manager_.OnPacketAcked(newest_transmission,
+ delta_largest_observed);
+ if (newest_transmission != sequence_number) {
+ RecordSpuriousRetransmissions(*transmission_info.all_transmissions,
+ sequence_number);
+ }
+ }
+
// Two cases for MarkPacketHandled:
// 1) Handle the most recent or a crypto packet, so remove all transmissions.
// 2) Handle old transmission, keep all other pending transmissions,
// but disassociate them from one another.
- if (newest_transmission != sequence_number) {
- stats_->bytes_spuriously_retransmitted += transmission_info.bytes_sent;
- ++stats_->packets_spuriously_retransmitted;
- }
-
- // The AckNotifierManager needs to be notified about the most recent
- // transmission, since that's the one only one it tracks.
- ack_notifier_manager_.OnPacketAcked(newest_transmission,
- delta_largest_observed);
// If it's a crypto handshake packet, discard it and all retransmissions,
// since they won't be acked now that one has been processed.
@@ -396,6 +437,7 @@
HasRetransmittableData has_retransmittable_data) {
DCHECK_LT(0u, sequence_number);
LOG_IF(DFATAL, bytes == 0) << "Cannot send empty packets.";
+ pending_tlp_transmission_ = false;
// In rare circumstances, the packet could be serialized, sent, and then acked
// before OnPacketSent is called.
if (!unacked_packets_.IsUnacked(sequence_number)) {
@@ -446,6 +488,7 @@
// If no tail loss probe can be sent, because there are no retransmittable
// packets, execute a conventional RTO to abandon old packets.
++stats_->tlp_count;
+ pending_tlp_transmission_ = true;
RetransmitOldestPacket();
return;
case RTO_MODE:
@@ -497,12 +540,8 @@
}
void QuicSentPacketManager::RetransmitAllPackets() {
- // Abandon all retransmittable packets and packets older than the
- // retransmission delay.
-
- DVLOG(1) << "OnRetransmissionTimeout() fired with "
+ DVLOG(1) << "RetransmitAllPackets() called with "
<< unacked_packets_.GetNumUnackedPackets() << " unacked packets.";
-
// Request retransmission of all retransmittable packets when the RTO
// fires, and let the congestion manager decide how many to send
// immediately and the remaining packets will be queued.
@@ -605,11 +644,10 @@
QuicTime::Delta QuicSentPacketManager::TimeUntilSend(
QuicTime now,
- TransmissionType transmission_type,
HasRetransmittableData retransmittable) {
// The TLP logic is entirely contained within QuicSentPacketManager, so the
// send algorithm does not need to be consulted.
- if (transmission_type == TLP_RETRANSMISSION) {
+ if (pending_tlp_transmission_) {
return QuicTime::Delta::Zero();
}
return send_algorithm_->TimeUntilSend(
@@ -731,10 +769,11 @@
return;
}
+ // Set up a pacing sender with a 5 millisecond alarm granularity.
using_pacing_ = true;
send_algorithm_.reset(
new PacingSender(send_algorithm_.release(),
- QuicTime::Delta::FromMicroseconds(1)));
+ QuicTime::Delta::FromMilliseconds(5)));
}
} // namespace net
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index d65e361..395d212 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -41,6 +41,19 @@
// previous transmission is acked, the data will not be retransmitted.
class NET_EXPORT_PRIVATE QuicSentPacketManager {
public:
+ // Interface which gets callbacks from the QuicSentPacketManager at
+ // interesting points. Implementations must not mutate the state of
+ // the packet manager or connection as a result of these callbacks.
+ class NET_EXPORT_PRIVATE DebugDelegate {
+ public:
+ virtual ~DebugDelegate() {}
+
+ // Called when a spurious retransmission is detected.
+ virtual void OnSpuriousPacketRetransmition(
+ TransmissionType transmission_type,
+ QuicByteCount byte_size) {}
+ };
+
// Struct to store the pending retransmission information.
struct PendingRetransmission {
PendingRetransmission(QuicPacketSequenceNumber sequence_number,
@@ -133,7 +146,6 @@
// Note 2: Send algorithms may or may not use |retransmit| in their
// calculations.
virtual QuicTime::Delta TimeUntilSend(QuicTime now,
- TransmissionType transmission_type,
HasRetransmittableData retransmittable);
// Returns amount of time for delayed ack timer.
@@ -160,6 +172,10 @@
bool using_pacing() const { return using_pacing_; }
+ void set_debug_delegate(DebugDelegate* debug_delegate) {
+ debug_delegate_ = debug_delegate;
+ }
+
private:
friend class test::QuicConnectionPeer;
friend class test::QuicSentPacketManagerPeer;
@@ -240,6 +256,11 @@
void MarkForRetransmission(QuicPacketSequenceNumber sequence_number,
TransmissionType transmission_type);
+ // Notify observers about spurious retransmits.
+ void RecordSpuriousRetransmissions(
+ const SequenceNumberSet& all_transmissions,
+ QuicPacketSequenceNumber acked_sequence_number);
+
// Newly serialized retransmittable and fec packets are added to this map,
// which contains owning pointers to any contained frames. If a packet is
// retransmitted, this map will contain entries for both the old and the new
@@ -263,6 +284,7 @@
const QuicClock* clock_;
QuicConnectionStats* stats_;
+ DebugDelegate* debug_delegate_;
RttStats rtt_stats_;
scoped_ptr<SendAlgorithmInterface> send_algorithm_;
scoped_ptr<LossDetectionInterface> loss_algorithm_;
@@ -274,6 +296,8 @@
size_t consecutive_tlp_count_;
// Number of times the crypto handshake has been retransmitted.
size_t consecutive_crypto_retransmission_count_;
+ // Whether a tlp packet can be sent even if the send algorithm says not to.
+ bool pending_tlp_transmission_;
// Maximum number of tail loss probes to send before firing an RTO.
size_t max_tail_loss_probes_;
bool using_pacing_;
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index b3c1fdc..ef13a22 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -32,6 +32,13 @@
return std::tr1::get<0>(arg).first == std::tr1::get<1>(arg);
}
+class MockDebugDelegate : public QuicSentPacketManager::DebugDelegate {
+ public:
+ MOCK_METHOD2(OnSpuriousPacketRetransmition,
+ void(TransmissionType transmission_type,
+ QuicByteCount byte_size));
+};
+
class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
protected:
QuicSentPacketManagerTest()
@@ -129,7 +136,8 @@
EXPECT_EQ(old_sequence_number, next_retransmission.sequence_number);
EXPECT_EQ(TLP_RETRANSMISSION,
next_retransmission.transmission_type);
- manager_.OnRetransmittedPacket(old_sequence_number, new_sequence_number);
+ manager_.OnRetransmittedPacket(old_sequence_number,
+ new_sequence_number);
EXPECT_TRUE(QuicSentPacketManagerPeer::IsRetransmission(
&manager_, new_sequence_number));
}
@@ -232,8 +240,8 @@
.Times(1).WillOnce(Return(true));
const QuicSentPacketManager::PendingRetransmission pending =
manager_.NextPendingRetransmission();
- manager_.OnRetransmittedPacket(
- pending.sequence_number, retransmission_sequence_number);
+ manager_.OnRetransmittedPacket(pending.sequence_number,
+ retransmission_sequence_number);
manager_.OnPacketSent(retransmission_sequence_number, clock_.Now(),
kDefaultLength, pending.transmission_type,
HAS_RETRANSMITTABLE_DATA);
@@ -428,6 +436,11 @@
}
TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) {
+ StrictMock<MockDebugDelegate> debug_delegate;
+ EXPECT_CALL(debug_delegate, OnSpuriousPacketRetransmition(
+ TLP_RETRANSMISSION, kDefaultLength)).Times(2);
+ manager_.set_debug_delegate(&debug_delegate);
+
SendDataPacket(1);
RetransmitAndSendPacket(1, 2);
RetransmitAndSendPacket(2, 3);
@@ -465,7 +478,7 @@
VerifyUnackedPackets(NULL, 0);
EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
- EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted);
+ EXPECT_EQ(2u, stats_.packets_spuriously_retransmitted);
}
TEST_F(QuicSentPacketManagerTest, LoseButDontRetransmitRevivedPacket) {
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 9b28103..e0bddfe 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -118,8 +118,8 @@
max_flow_control_receive_window_bytes_ = kDefaultFlowControlSendWindow;
}
flow_controller_.reset(new QuicFlowController(
- connection_->supported_versions().front(), 0, is_server(),
- kDefaultFlowControlSendWindow, max_flow_control_receive_window_bytes_,
+ connection_.get(), 0, is_server(), kDefaultFlowControlSendWindow,
+ max_flow_control_receive_window_bytes_,
max_flow_control_receive_window_bytes_));
connection_->set_visitor(visitor_shim_.get());
@@ -422,7 +422,7 @@
<< "Peer sent us an invalid flow control send window: "
<< new_flow_control_send_window
<< ", below default: " << kDefaultFlowControlSendWindow;
- connection_->SendConnectionClose(QUIC_FLOW_CONTROL_ERROR);
+ connection_->SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW);
return;
}
DataStreamMap::iterator it = stream_map_.begin();
@@ -643,6 +643,15 @@
if (version < QUIC_VERSION_19) {
flow_controller_->Disable();
}
+
+ // Inform all streams about the negotiated version. They may have been created
+ // with a different version.
+ for (DataStreamMap::iterator it = stream_map_.begin();
+ it != stream_map_.end(); ++it) {
+ if (version < QUIC_VERSION_17) {
+ it->second->flow_controller()->Disable();
+ }
+ }
}
} // namespace net
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index d23b684..b9ce0de 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -175,8 +175,6 @@
return connection_->connection_id();
}
- QuicPacketCreator::Options* options() { return connection()->options(); }
-
// Returns the number of currently open streams, including those which have
// been implicitly created, but excluding the reserved headers and crypto
// streams.
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index 92c3cab..b70be5a 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -168,6 +168,8 @@
return WritevData(id, IOVector(), 0, true, NULL);
}
+ using QuicSession::PostProcessAfterData;
+
private:
StrictMock<TestCryptoStream> crypto_stream_;
@@ -661,7 +663,8 @@
session_.config()->ProcessPeerHello(msg, CLIENT, &error_details);
EXPECT_EQ(QUIC_NO_ERROR, error);
- EXPECT_CALL(*connection_, SendConnectionClose(QUIC_FLOW_CONTROL_ERROR));
+ EXPECT_CALL(*connection_,
+ SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW));
session_.OnConfigNegotiated();
}
@@ -676,6 +679,101 @@
session.max_flow_control_receive_window_bytes());
}
+TEST_P(QuicSessionTest, ConnectionFlowControlAccountingRstOutOfOrder) {
+ FLAGS_enable_quic_stream_flow_control_2 = true;
+ FLAGS_enable_quic_connection_flow_control = true;
+ if (version() < QUIC_VERSION_19) {
+ return;
+ }
+
+ // Test that when we receive an out of order stream RST we correctly adjust
+ // our connection level flow control receive window.
+ // On close, the stream should mark as consumed all bytes between the highest
+ // byte consumed so far and the final byte offset from the RST frame.
+ TestStream* stream = session_.CreateOutgoingDataStream();
+
+ const QuicStreamOffset kByteOffset = 1 + kInitialFlowControlWindowForTest / 2;
+ // Expect no stream WINDOW_UPDATE frames, as stream read side closed.
+ EXPECT_CALL(*connection_, SendWindowUpdate(stream->id(), _)).Times(0);
+ // We do expect a connection level WINDOW_UPDATE when the stream is reset.
+ EXPECT_CALL(*connection_,
+ SendWindowUpdate(
+ 0, kInitialFlowControlWindowForTest + kByteOffset)).Times(1);
+
+ QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED,
+ kByteOffset);
+ session_.OnRstStream(rst_frame);
+ session_.PostProcessAfterData();
+ EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed());
+}
+
+TEST_P(QuicSessionTest, ConnectionFlowControlAccountingFinAndLocalReset) {
+ FLAGS_enable_quic_stream_flow_control_2 = true;
+ FLAGS_enable_quic_connection_flow_control = true;
+ if (version() < QUIC_VERSION_19) {
+ return;
+ }
+
+ // Test the situation where we receive a FIN on a stream, and before we fully
+ // consume all the data from the sequencer buffer we locally RST the stream.
+ // The bytes between highest consumed byte, and the final byte offset that we
+ // determined when the FIN arrived, should be marked as consumed at the
+ // connection level flow controller when the stream is reset.
+ TestStream* stream = session_.CreateOutgoingDataStream();
+
+ const QuicStreamOffset kByteOffset = 1 + kInitialFlowControlWindowForTest / 2;
+ QuicStreamFrame frame(stream->id(), true, kByteOffset, IOVector());
+ vector<QuicStreamFrame> frames;
+ frames.push_back(frame);
+ session_.OnStreamFrames(frames);
+ session_.PostProcessAfterData();
+
+ EXPECT_EQ(0u, stream->flow_controller()->bytes_consumed());
+ EXPECT_EQ(kByteOffset,
+ stream->flow_controller()->highest_received_byte_offset());
+
+ // Expect no stream WINDOW_UPDATE frames, as stream read side closed.
+ EXPECT_CALL(*connection_, SendWindowUpdate(stream->id(), _)).Times(0);
+ // We do expect a connection level WINDOW_UPDATE when the stream is reset.
+ EXPECT_CALL(*connection_,
+ SendWindowUpdate(
+ 0, kInitialFlowControlWindowForTest + kByteOffset)).Times(1);
+
+ // Reset stream locally.
+ stream->Reset(QUIC_STREAM_CANCELLED);
+
+ EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed());
+}
+
+TEST_P(QuicSessionTest, VersionNegotiationDisablesFlowControl) {
+ ValueRestore<bool> old_stream_flag(
+ &FLAGS_enable_quic_stream_flow_control_2, true);
+ ValueRestore<bool> old_connection_flag(
+ &FLAGS_enable_quic_connection_flow_control, true);
+ if (version() < QUIC_VERSION_19) {
+ return;
+ }
+
+ // Test that after successful version negotiation, flow control is disabled
+ // appropriately at both the connection and stream level.
+
+ // Initially both stream and connection flow control are enabled.
+ TestStream* stream = session_.CreateOutgoingDataStream();
+ EXPECT_TRUE(stream->flow_controller()->IsEnabled());
+ EXPECT_TRUE(session_.flow_controller()->IsEnabled());
+
+ // Version 17 implies that stream flow control is enabled, but connection
+ // level is disabled.
+ session_.OnSuccessfulVersionNegotiation(QUIC_VERSION_17);
+ EXPECT_FALSE(session_.flow_controller()->IsEnabled());
+ EXPECT_TRUE(stream->flow_controller()->IsEnabled());
+
+ // Version 16 means all flow control is disabled.
+ session_.OnSuccessfulVersionNegotiation(QUIC_VERSION_16);
+ EXPECT_FALSE(session_.flow_controller()->IsEnabled());
+ EXPECT_FALSE(stream->flow_controller()->IsEnabled());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 152d70b..52c7168 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -120,6 +120,13 @@
QuicServerInfo* server_info,
const BoundNetLog& net_log);
+ // Creates a new job to handle the resumption of for connecting an
+ // existing session.
+ Job(QuicStreamFactory* factory,
+ HostResolver* host_resolver,
+ QuicClientSession* session,
+ QuicServerId server_id);
+
~Job();
int Run(const CompletionCallback& callback);
@@ -130,6 +137,7 @@
int DoLoadServerInfo();
int DoLoadServerInfoComplete(int rv);
int DoConnect();
+ int DoResumeConnect();
int DoConnectComplete(int rv);
void OnIOComplete(int rv);
@@ -150,6 +158,7 @@
STATE_LOAD_SERVER_INFO,
STATE_LOAD_SERVER_INFO_COMPLETE,
STATE_CONNECT,
+ STATE_RESUME_CONNECT,
STATE_CONNECT_COMPLETE,
};
IoState io_state_;
@@ -178,7 +187,8 @@
base::StringPiece method,
QuicServerInfo* server_info,
const BoundNetLog& net_log)
- : factory_(factory),
+ : io_state_(STATE_RESOLVE_HOST),
+ factory_(factory),
host_resolver_(host_resolver),
server_id_(host_port_pair, is_https, privacy_mode),
is_post_(method == "POST"),
@@ -189,11 +199,24 @@
session_(NULL),
weak_factory_(this) {}
+QuicStreamFactory::Job::Job(QuicStreamFactory* factory,
+ HostResolver* host_resolver,
+ QuicClientSession* session,
+ QuicServerId server_id)
+ : io_state_(STATE_RESUME_CONNECT),
+ factory_(factory),
+ host_resolver_(host_resolver), // unused
+ server_id_(server_id),
+ is_post_(false), // unused
+ was_alternate_protocol_recently_broken_(false), // unused
+ net_log_(session->net_log()), // unused
+ session_(session),
+ weak_factory_(this) {}
+
QuicStreamFactory::Job::~Job() {
}
int QuicStreamFactory::Job::Run(const CompletionCallback& callback) {
- io_state_ = STATE_RESOLVE_HOST;
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
callback_ = callback;
@@ -224,6 +247,10 @@
CHECK_EQ(OK, rv);
rv = DoConnect();
break;
+ case STATE_RESUME_CONNECT:
+ CHECK_EQ(OK, rv);
+ rv = DoResumeConnect();
+ break;
case STATE_CONNECT_COMPLETE:
rv = DoConnectComplete(rv);
break;
@@ -326,6 +353,16 @@
return rv;
}
+int QuicStreamFactory::Job::DoResumeConnect() {
+ io_state_ = STATE_CONNECT_COMPLETE;
+
+ int rv = session_->ResumeCryptoConnect(
+ base::Bind(&QuicStreamFactory::Job::OnIOComplete,
+ base::Unretained(this)));
+
+ return rv;
+}
+
int QuicStreamFactory::Job::DoConnectComplete(int rv) {
if (rv != OK)
return rv;
@@ -401,6 +438,7 @@
QuicRandom* random_generator,
QuicClock* clock,
size_t max_packet_length,
+ const std::string& user_agent_id,
const QuicVersionVector& supported_versions,
bool enable_port_selection,
bool enable_pacing,
@@ -429,6 +467,7 @@
QuicTime::Delta::FromSeconds(30));
crypto_config_.SetDefaults();
+ crypto_config_.set_user_agent_id(user_agent_id);
crypto_config_.AddCanonicalSuffix(".c.youtube.com");
crypto_config_.AddCanonicalSuffix(".googlevideo.com");
crypto_config_.SetProofVerifier(new ProofVerifierChromium(cert_verifier));
@@ -603,6 +642,35 @@
all_sessions_.erase(session);
}
+void QuicStreamFactory::OnSessionConnectTimeout(
+ QuicClientSession* session) {
+ const AliasSet& aliases = session_aliases_[session];
+ for (AliasSet::const_iterator it = aliases.begin(); it != aliases.end();
+ ++it) {
+ DCHECK(active_sessions_.count(*it));
+ DCHECK_EQ(session, active_sessions_[*it]);
+ active_sessions_.erase(*it);
+ }
+
+ if (aliases.empty()) {
+ return;
+ }
+
+ const IpAliasKey ip_alias_key(session->connection()->peer_address(),
+ aliases.begin()->is_https());
+ ip_aliases_[ip_alias_key].erase(session);
+ if (ip_aliases_[ip_alias_key].empty()) {
+ ip_aliases_.erase(ip_alias_key);
+ }
+ QuicServerId server_id = *aliases.begin();
+ session_aliases_.erase(session);
+ Job* job = new Job(this, host_resolver_, session, server_id);
+ active_jobs_[server_id] = job;
+ int rv = job->Run(base::Bind(&QuicStreamFactory::OnJobComplete,
+ base::Unretained(this), job));
+ DCHECK_EQ(ERR_IO_PENDING, rv);
+}
+
void QuicStreamFactory::CancelRequest(QuicStreamRequest* request) {
DCHECK(ContainsKey(active_requests_, request));
Job* job = active_requests_[request];
@@ -749,7 +817,7 @@
new QuicConnection(connection_id, addr, helper_.get(), writer.get(),
false, supported_versions_);
writer->SetConnection(connection);
- connection->options()->max_packet_length = max_packet_length_;
+ connection->set_max_packet_length(max_packet_length_);
InitializeCachedStateInCryptoConfig(server_id, server_info);
@@ -769,7 +837,9 @@
*session = new QuicClientSession(
connection, socket.Pass(), writer.Pass(), this,
quic_crypto_client_stream_factory_, server_info.Pass(), server_id,
- config, kInitialReceiveWindowSize, &crypto_config_, net_log.net_log());
+ config, kInitialReceiveWindowSize, &crypto_config_,
+ base::MessageLoop::current()->message_loop_proxy().get(),
+ net_log.net_log());
all_sessions_[*session] = server_id; // owning pointer
return OK;
}
@@ -782,6 +852,7 @@
const QuicServerId& server_id,
QuicClientSession* session) {
DCHECK(!HasActiveSession(server_id));
+ UMA_HISTOGRAM_COUNTS("Net.QuicActiveSessions", active_sessions_.size());
active_sessions_[server_id] = session;
session_aliases_[session].insert(server_id);
const IpAliasKey ip_alias_key(session->connection()->peer_address(),
@@ -834,16 +905,39 @@
UMA_HISTOGRAM_COUNTS("Net.QuicHandshakeNotConfirmedNumPacketsReceived",
stats.packets_received);
- if (session_was_active) {
- // TODO(rch): In the special case where the session has received no
- // packets from the peer, we should consider blacklisting this
- // differently so that we still race TCP but we don't consider the
- // session connected until the handshake has been confirmed.
- HistogramBrokenAlternateProtocolLocation(
- BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY);
- http_server_properties_->SetBrokenAlternateProtocol(
- server_id.host_port_pair());
- }
+ if (!session_was_active)
+ return;
+
+ const HostPortPair& server = server_id.host_port_pair();
+ // Don't try to change the alternate-protocol state, if the
+ // alternate-protocol state is unknown.
+ if (!http_server_properties_->HasAlternateProtocol(server))
+ return;
+
+ // TODO(rch): In the special case where the session has received no
+ // packets from the peer, we should consider blacklisting this
+ // differently so that we still race TCP but we don't consider the
+ // session connected until the handshake has been confirmed.
+ HistogramBrokenAlternateProtocolLocation(
+ BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY);
+ PortAlternateProtocolPair alternate =
+ http_server_properties_->GetAlternateProtocol(server);
+ DCHECK_EQ(QUIC, alternate.protocol);
+
+ // Since the session was active, there's no longer an
+ // HttpStreamFactoryImpl::Job running which can mark it broken, unless the
+ // TCP job also fails. So to avoid not using QUIC when we otherwise could,
+ // we mark it as broken, and then immediately re-enable it. This leaves
+ // QUIC as "recently broken" which means that 0-RTT will be disabled but
+ // we'll still race.
+ http_server_properties_->SetBrokenAlternateProtocol(server);
+ http_server_properties_->ClearAlternateProtocol(server);
+ http_server_properties_->SetAlternateProtocol(
+ server, alternate.port, alternate.protocol);
+ DCHECK_EQ(QUIC,
+ http_server_properties_->GetAlternateProtocol(server).protocol);
+ DCHECK(http_server_properties_->WasAlternateProtocolRecentlyBroken(
+ server));
}
} // namespace net
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index 97da453..cc79285 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -95,6 +95,7 @@
QuicRandom* random_generator,
QuicClock* clock,
size_t max_packet_length,
+ const std::string& user_agent_id,
const QuicVersionVector& supported_versions,
bool enable_port_selection,
bool enable_pacing,
@@ -125,6 +126,9 @@
// Called by a session after it shuts down.
void OnSessionClosed(QuicClientSession* session);
+ // Called by a session whose connection has timed out.
+ void OnSessionConnectTimeout(QuicClientSession* session);
+
// Cancels a pending request.
void CancelRequest(QuicStreamRequest* request);
@@ -158,6 +162,10 @@
bool enable_port_selection() const { return enable_port_selection_; }
+ bool has_quic_server_info_factory() {
+ return quic_server_info_factory_ != NULL;
+ }
+
void set_quic_server_info_factory(
QuicServerInfoFactory* quic_server_info_factory) {
DCHECK(!quic_server_info_factory_);
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 8189989..f50c387 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -90,10 +90,9 @@
clock_(new MockClock()),
cert_verifier_(CertVerifier::CreateDefault()),
factory_(&host_resolver_, &socket_factory_,
- base::WeakPtr<HttpServerProperties>(),
- cert_verifier_.get(),
- &crypto_client_stream_factory_,
- &random_generator_, clock_, kDefaultMaxPacketSize,
+ base::WeakPtr<HttpServerProperties>(), cert_verifier_.get(),
+ &crypto_client_stream_factory_, &random_generator_, clock_,
+ kDefaultMaxPacketSize, std::string(),
SupportedVersions(GetParam()), true, true, true),
host_port_pair_(kDefaultServerHostName, kDefaultServerPort),
is_https_(false),
diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc
index 61b4f7c..d0b6933 100644
--- a/net/quic/quic_stream_sequencer.cc
+++ b/net/quic/quic_stream_sequencer.cc
@@ -68,7 +68,6 @@
}
num_bytes_consumed_ += bytes_consumed;
stream_->AddBytesConsumed(bytes_consumed);
- stream_->MaybeSendWindowUpdate();
if (MaybeCloseStream()) {
return true;
@@ -95,7 +94,6 @@
byte_offset, string(static_cast<char*>(iov.iov_base), iov.iov_len)));
byte_offset += iov.iov_len;
num_bytes_buffered_ += iov.iov_len;
- stream_->AddBytesBuffered(iov.iov_len);
}
return true;
}
@@ -248,8 +246,6 @@
num_bytes_buffered_ -= bytes_consumed;
stream_->AddBytesConsumed(bytes_consumed);
- stream_->RemoveBytesBuffered(bytes_consumed);
- stream_->MaybeSendWindowUpdate();
}
} // namespace net
diff --git a/net/quic/quic_types.cc b/net/quic/quic_types.cc
new file mode 100644
index 0000000..cdfb36d
--- /dev/null
+++ b/net/quic/quic_types.cc
@@ -0,0 +1,34 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_types.h"
+
+using std::ostream;
+
+namespace net {
+
+QuicConsumedData::QuicConsumedData(size_t bytes_consumed,
+ bool fin_consumed)
+ : bytes_consumed(bytes_consumed),
+ fin_consumed(fin_consumed) {
+}
+
+ostream& operator<<(ostream& os, const QuicConsumedData& s) {
+ os << "bytes_consumed: " << s.bytes_consumed
+ << " fin_consumed: " << s.fin_consumed;
+ return os;
+}
+
+WriteResult::WriteResult()
+ : status(WRITE_STATUS_ERROR),
+ bytes_written(0) {
+}
+
+WriteResult::WriteResult(WriteStatus status,
+ int bytes_written_or_error_code)
+ : status(status),
+ bytes_written(bytes_written_or_error_code) {
+}
+
+} // namespace net
diff --git a/net/quic/quic_types.h b/net/quic/quic_types.h
new file mode 100644
index 0000000..01415bc
--- /dev/null
+++ b/net/quic/quic_types.h
@@ -0,0 +1,69 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_TYPES_H_
+#define NET_QUIC_QUIC_TYPES_H_
+
+// This header defines some basic types that don't depend on quic_protocol.h,
+// so that classes not directly related to the protocol wire format can avoid
+// including quic_protocol.h.
+
+#include <stddef.h>
+#include <ostream>
+
+#include "net/base/net_export.h"
+
+namespace net {
+
+// A struct for functions which consume data payloads and fins.
+struct NET_EXPORT_PRIVATE QuicConsumedData {
+ QuicConsumedData(size_t bytes_consumed, bool fin_consumed);
+
+ // By default, gtest prints the raw bytes of an object. The bool data
+ // member causes this object to have padding bytes, which causes the
+ // default gtest object printer to read uninitialize memory. So we need
+ // to teach gtest how to print this object.
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os, const QuicConsumedData& s);
+
+ // How many bytes were consumed.
+ size_t bytes_consumed;
+
+ // True if an incoming fin was consumed.
+ bool fin_consumed;
+};
+
+// QuicAsyncStatus enumerates the possible results of an asynchronous
+// operation.
+enum QuicAsyncStatus {
+ QUIC_SUCCESS = 0,
+ QUIC_FAILURE = 1,
+ // QUIC_PENDING results from an operation that will occur asynchonously. When
+ // the operation is complete, a callback's |Run| method will be called.
+ QUIC_PENDING = 2,
+};
+
+// TODO(wtc): see if WriteStatus can be replaced by QuicAsyncStatus.
+enum WriteStatus {
+ WRITE_STATUS_OK,
+ WRITE_STATUS_BLOCKED,
+ WRITE_STATUS_ERROR,
+};
+
+// A struct used to return the result of write calls including either the number
+// of bytes written or the error code, depending upon the status.
+struct NET_EXPORT_PRIVATE WriteResult {
+ WriteResult(WriteStatus status, int bytes_written_or_error_code);
+ WriteResult();
+
+ WriteStatus status;
+ union {
+ int bytes_written; // only valid when status is WRITE_STATUS_OK
+ int error_code; // only valid when status is WRITE_STATUS_ERROR
+ };
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_TYPES_H_
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc
index b230485..e9dd136 100644
--- a/net/quic/quic_unacked_packet_map.cc
+++ b/net/quic/quic_unacked_packet_map.cc
@@ -57,7 +57,8 @@
void QuicUnackedPacketMap::OnRetransmittedPacket(
QuicPacketSequenceNumber old_sequence_number,
- QuicPacketSequenceNumber new_sequence_number) {
+ QuicPacketSequenceNumber new_sequence_number,
+ TransmissionType transmission_type) {
DCHECK(ContainsKey(unacked_packets_, old_sequence_number));
DCHECK(unacked_packets_.empty() ||
unacked_packets_.rbegin()->first < new_sequence_number);
@@ -77,6 +78,7 @@
TransmissionInfo(frames,
new_sequence_number,
transmission_info->sequence_number_length,
+ transmission_type,
transmission_info->all_transmissions);
}
diff --git a/net/quic/quic_unacked_packet_map.h b/net/quic/quic_unacked_packet_map.h
index 0263422..ae72548 100644
--- a/net/quic/quic_unacked_packet_map.h
+++ b/net/quic/quic_unacked_packet_map.h
@@ -27,7 +27,8 @@
// retransmittable data associated with it. |new_sequence_number| will
// be both unacked and associated with retransmittable data.
void OnRetransmittedPacket(QuicPacketSequenceNumber old_sequence_number,
- QuicPacketSequenceNumber new_sequence_number);
+ QuicPacketSequenceNumber new_sequence_number,
+ TransmissionType transmission_type);
// Returns true if the packet |sequence_number| is unacked.
bool IsUnacked(QuicPacketSequenceNumber sequence_number) const;
diff --git a/net/quic/quic_unacked_packet_map_test.cc b/net/quic/quic_unacked_packet_map_test.cc
index 0ff0cf0..c5264fd 100644
--- a/net/quic/quic_unacked_packet_map_test.cc
+++ b/net/quic/quic_unacked_packet_map_test.cc
@@ -130,7 +130,7 @@
// transmission being acked.
unacked_packets_.AddPacket(CreateRetransmittablePacket(1));
unacked_packets_.SetSent(1, now_, kDefaultLength, true);
- unacked_packets_.OnRetransmittedPacket(1, 2);
+ unacked_packets_.OnRetransmittedPacket(1, 2, LOSS_RETRANSMISSION);
unacked_packets_.SetSent(2, now_, kDefaultLength, true);
QuicPacketSequenceNumber unacked[] = { 1, 2 };
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index 3abc226..ae4bb2e 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -202,7 +202,9 @@
RETURN_STRING_LITERAL(QUIC_PACKET_READ_ERROR);
RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_FRAME);
RETURN_STRING_LITERAL(QUIC_INVALID_HEADERS_STREAM_DATA);
- RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_ERROR);
+ RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA);
+ RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA);
+ RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_INVALID_WINDOW);
RETURN_STRING_LITERAL(QUIC_CONNECTION_IP_POOLED);
RETURN_STRING_LITERAL(QUIC_PROOF_INVALID);
RETURN_STRING_LITERAL(QUIC_CRYPTO_DUPLICATE_TAG);
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index aefdb41..b73185b 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -124,7 +124,7 @@
rst_sent_(false),
is_server_(session_->is_server()),
flow_controller_(
- session_->connection()->version(),
+ session_->connection(),
id_,
is_server_,
session_->config()->HasReceivedInitialFlowControlWindowBytes() ?
@@ -151,23 +151,22 @@
}
// This count include duplicate data received.
- stream_bytes_read_ += frame.data.TotalBufferSize();
+ size_t frame_payload_size = frame.data.TotalBufferSize();
+ stream_bytes_read_ += frame_payload_size;
- bool accepted = sequencer_.OnStreamFrame(frame);
-
- if (flow_controller_.FlowControlViolation() ||
- connection_flow_controller_->FlowControlViolation()) {
- session_->connection()->SendConnectionClose(QUIC_FLOW_CONTROL_ERROR);
- return false;
+ // Flow control is interested in tracking highest received offset.
+ if (MaybeIncreaseHighestReceivedOffset(frame.offset + frame_payload_size)) {
+ // As the highest received offset has changed, we should check to see if
+ // this is a violation of flow control.
+ if (flow_controller_.FlowControlViolation() ||
+ connection_flow_controller_->FlowControlViolation()) {
+ session_->connection()->SendConnectionClose(
+ QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA);
+ return false;
+ }
}
- MaybeSendWindowUpdate();
- return accepted;
-}
-
-void ReliableQuicStream::MaybeSendWindowUpdate() {
- flow_controller_.MaybeSendWindowUpdate(session()->connection());
- connection_flow_controller_->MaybeSendWindowUpdate(session()->connection());
+ return sequencer_.OnStreamFrame(frame);
}
int ReliableQuicStream::num_frames_received() const {
@@ -179,6 +178,8 @@
}
void ReliableQuicStream::OnStreamReset(const QuicRstStreamFrame& frame) {
+ MaybeIncreaseHighestReceivedOffset(frame.byte_offset);
+
stream_error_ = frame.error_code;
CloseWriteSide();
CloseReadSide();
@@ -298,8 +299,8 @@
}
void ReliableQuicStream::MaybeSendBlocked() {
- flow_controller_.MaybeSendBlocked(session()->connection());
- connection_flow_controller_->MaybeSendBlocked(session()->connection());
+ flow_controller_.MaybeSendBlocked();
+ connection_flow_controller_->MaybeSendBlocked();
// If we are connection level flow control blocked, then add the stream
// to the write blocked list. It will be given a chance to write when a
// connection level WINDOW_UPDATE arrives.
@@ -417,6 +418,14 @@
stream_bytes_written_);
rst_sent_ = true;
}
+
+ // We are closing the stream and will not process any further incoming bytes.
+ // As there may be more bytes in flight and we need to ensure that both
+ // endpoints have the same connection level flow control state, mark all
+ // unreceived or buffered bytes as consumed.
+ uint64 bytes_to_consume = flow_controller_.highest_received_byte_offset() -
+ flow_controller_.bytes_consumed();
+ AddBytesConsumed(bytes_to_consume);
}
void ReliableQuicStream::OnWindowUpdateFrame(
@@ -436,18 +445,21 @@
}
}
-void ReliableQuicStream::AddBytesBuffered(uint64 bytes) {
+bool ReliableQuicStream::MaybeIncreaseHighestReceivedOffset(uint64 new_offset) {
if (flow_controller_.IsEnabled()) {
- flow_controller_.AddBytesBuffered(bytes);
- connection_flow_controller_->AddBytesBuffered(bytes);
+ uint64 increment =
+ new_offset - flow_controller_.highest_received_byte_offset();
+ if (flow_controller_.UpdateHighestReceivedOffset(new_offset)) {
+ // If |new_offset| increased the stream flow controller's highest received
+ // offset, then we need to increase the connection flow controller's value
+ // by the incremental difference.
+ connection_flow_controller_->UpdateHighestReceivedOffset(
+ connection_flow_controller_->highest_received_byte_offset() +
+ increment);
+ return true;
+ }
}
-}
-
-void ReliableQuicStream::RemoveBytesBuffered(uint64 bytes) {
- if (flow_controller_.IsEnabled()) {
- flow_controller_.RemoveBytesBuffered(bytes);
- connection_flow_controller_->RemoveBytesBuffered(bytes);
- }
+ return false;
}
void ReliableQuicStream::AddBytesSent(uint64 bytes) {
@@ -459,7 +471,11 @@
void ReliableQuicStream::AddBytesConsumed(uint64 bytes) {
if (flow_controller_.IsEnabled()) {
- flow_controller_.AddBytesConsumed(bytes);
+ // Only adjust stream level flow controller if we are still reading.
+ if (!read_side_closed_) {
+ flow_controller_.AddBytesConsumed(bytes);
+ }
+
connection_flow_controller_->AddBytesConsumed(bytes);
}
}
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 90cdac4..9d8fe88 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -20,6 +20,7 @@
#include "net/quic/quic_flow_controller.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_stream_sequencer.h"
+#include "net/quic/quic_types.h"
namespace net {
@@ -92,24 +93,20 @@
// Adjust our flow control windows according to new offset in |frame|.
virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame);
- // If our receive window has dropped below the threshold, then send a
- // WINDOW_UPDATE frame. This is called whenever bytes are consumed from the
- // sequencer's buffer.
- void MaybeSendWindowUpdate();
-
int num_frames_received() const;
int num_duplicate_frames_received() const;
QuicFlowController* flow_controller() { return &flow_controller_; }
- // Called by the stream sequeuncer as bytes are added to the buffer.
- void AddBytesBuffered(uint64 bytes);
- // Called by the stream sequeuncer as bytes are removed from the buffer.
- void RemoveBytesBuffered(uint64 bytes);
+ // Called when we see a frame which could increase the highest offset.
+ // Returns true if the highest offset did increase.
+ bool MaybeIncreaseHighestReceivedOffset(uint64 new_offset);
// Called when bytese are sent to the peer.
void AddBytesSent(uint64 bytes);
- // Called by the stream sequeuncer as bytes are consumed from the buffer.
+ // Called by the stream sequencer as bytes are consumed from the buffer.
+ // If our receive window has dropped below the threshold, then send a
+ // WINDOW_UPDATE frame.
void AddBytesConsumed(uint64 bytes);
// Returns true if the stream is flow control blocked, by the stream flow
@@ -171,12 +168,6 @@
scoped_refptr<ProxyAckNotifierDelegate> delegate;
};
- // Calculates and returns available flow control send window.
- uint64 SendWindowSize() const;
-
- // Calculates and returns total number of bytes this stream has received.
- uint64 TotalReceivedBytes() const;
-
// Calls MaybeSendBlocked on our flow controller, and connection level flow
// controller. If we are flow control blocked, marks this stream as write
// blocked.
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index 9e212ce..5d1ea9d 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -11,6 +11,7 @@
#include "net/quic/quic_write_blocked_list.h"
#include "net/quic/spdy_utils.h"
#include "net/quic/test_tools/quic_config_peer.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_flow_controller_peer.h"
#include "net/quic/test_tools/quic_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
@@ -150,13 +151,14 @@
TEST_F(ReliableQuicStreamTest, WriteAllData) {
Initialize(kShouldProcessData);
- connection_->options()->max_packet_length =
- 1 + QuicPacketCreator::StreamFramePacketOverhead(
- connection_->version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER, 0u,
- NOT_IN_FEC_GROUP);
- EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(kDataLen, true)));
+ size_t length = 1 + QuicPacketCreator::StreamFramePacketOverhead(
+ connection_->version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, 0u, NOT_IN_FEC_GROUP);
+ QuicConnectionPeer::GetPacketCreator(connection_)->set_max_packet_length(
+ length);
+
+ EXPECT_CALL(*session_, WritevData(kHeadersStreamId, _, _, _, _)).WillOnce(
+ Return(QuicConsumedData(kDataLen, true)));
stream_->WriteOrBufferData(kData1, false, NULL);
EXPECT_FALSE(HasWriteBlockedStreams());
}
@@ -209,10 +211,12 @@
Initialize(kShouldProcessData);
EXPECT_FALSE(HasWriteBlockedStreams());
- connection_->options()->max_packet_length =
- 1 + QuicPacketCreator::StreamFramePacketOverhead(
- connection_->version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
- PACKET_6BYTE_SEQUENCE_NUMBER, 0u, NOT_IN_FEC_GROUP);
+ size_t length = 1 + QuicPacketCreator::StreamFramePacketOverhead(
+ connection_->version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, 0u, NOT_IN_FEC_GROUP);
+ QuicConnectionPeer::GetPacketCreator(connection_)->set_max_packet_length(
+ length);
+
EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).WillOnce(
Return(QuicConsumedData(kDataLen - 1, false)));
stream_->WriteOrBufferData(kData1, false, NULL);
@@ -553,6 +557,33 @@
proxy_delegate->OnAckNotification(10, 20, 30, 40, zero_);
}
+
+// Verify that when we receive a packet which violates flow control (i.e. sends
+// too much data on the stream) that the stream sequencer never sees this frame,
+// as we check for violation and close the connection early.
+TEST_F(ReliableQuicStreamTest,
+ StreamSequencerNeverSeesPacketsViolatingFlowControl) {
+ ValueRestore<bool> old_stream_flag(
+ &FLAGS_enable_quic_stream_flow_control_2, true);
+ ValueRestore<bool> old_connection_flag(
+ &FLAGS_enable_quic_connection_flow_control, true);
+
+ Initialize(kShouldProcessData);
+
+ // Receive a stream frame that violates flow control: the byte offset is
+ // higher than the receive window offset.
+ QuicStreamFrame frame(stream_->id(), false,
+ kInitialFlowControlWindowForTest + 1,
+ MakeIOVector("."));
+ EXPECT_GT(frame.offset, QuicFlowControllerPeer::ReceiveWindowOffset(
+ stream_->flow_controller()));
+
+ // Stream should not accept the frame, and the connection should be closed.
+ EXPECT_CALL(*connection_,
+ SendConnectionClose(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA));
+ EXPECT_FALSE(stream_->OnStreamFrame(frame));
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/mock_crypto_client_stream.cc b/net/quic/test_tools/mock_crypto_client_stream.cc
index 6710dcd..a4b3ab0 100644
--- a/net/quic/test_tools/mock_crypto_client_stream.cc
+++ b/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -83,7 +83,7 @@
QuicTagVector cgst;
cgst.push_back(kINAR);
cgst.push_back(kQBIC);
- session()->config()->set_congestion_control(cgst, kQBIC);
+ session()->config()->set_congestion_feedback(cgst, kQBIC);
session()->config()->set_idle_connection_state_lifetime(
QuicTime::Delta::FromSeconds(2 * kDefaultTimeoutSecs),
QuicTime::Delta::FromSeconds(kDefaultTimeoutSecs));
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc
index a8e1db5..9d7c83f 100644
--- a/net/quic/test_tools/quic_connection_peer.cc
+++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -215,5 +215,11 @@
return connection->connection_close_packet_.get();
}
+// static
+void QuicConnectionPeer::SetSupportedVersions(QuicConnection* connection,
+ QuicVersionVector versions) {
+ connection->framer_.SetSupportedVersions(versions);
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h
index 8c74c1a..cf0ea38 100644
--- a/net/quic/test_tools/quic_connection_peer.h
+++ b/net/quic/test_tools/quic_connection_peer.h
@@ -108,6 +108,9 @@
static QuicEncryptedPacket* GetConnectionClosePacket(
QuicConnection* connection);
+ static void SetSupportedVersions(QuicConnection* connection,
+ QuicVersionVector versions);
+
private:
DISALLOW_COPY_AND_ASSIGN(QuicConnectionPeer);
};
diff --git a/net/quic/test_tools/quic_flow_controller_peer.cc b/net/quic/test_tools/quic_flow_controller_peer.cc
index 80b5e2b..35882ed 100644
--- a/net/quic/test_tools/quic_flow_controller_peer.cc
+++ b/net/quic/test_tools/quic_flow_controller_peer.cc
@@ -54,7 +54,7 @@
uint64 QuicFlowControllerPeer::ReceiveWindowSize(
QuicFlowController* flow_controller) {
return flow_controller->receive_window_offset_ -
- flow_controller->TotalReceivedBytes();
+ flow_controller->highest_received_byte_offset_;
}
} // namespace test
diff --git a/net/quic/test_tools/quic_test_packet_maker.cc b/net/quic/test_tools/quic_test_packet_maker.cc
index 397f39f..7f0835f 100644
--- a/net/quic/test_tools/quic_test_packet_maker.cc
+++ b/net/quic/test_tools/quic_test_packet_maker.cc
@@ -84,7 +84,7 @@
QuicFramer framer(SupportedVersions(version_), QuicTime::Zero(), false);
scoped_ptr<QuicPacket> packet(
- framer.BuildUnsizedDataPacket(header, frames).packet);
+ BuildUnsizedDataPacket(&framer, header, frames).packet);
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
ENCRYPTION_NONE, header.packet_sequence_number, *packet));
}
@@ -143,7 +143,7 @@
}
scoped_ptr<QuicPacket> packet(
- framer.BuildUnsizedDataPacket(header, frames).packet);
+ BuildUnsizedDataPacket(&framer, header, frames).packet);
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
ENCRYPTION_NONE, header.packet_sequence_number, *packet));
}
@@ -227,7 +227,7 @@
QuicFrames frames;
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
- framer.BuildUnsizedDataPacket(header, frames).packet);
+ BuildUnsizedDataPacket(&framer, header, frames).packet);
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
ENCRYPTION_NONE, header.packet_sequence_number, *packet));
}
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 1f7759d..39458e1 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -63,6 +63,25 @@
return ack;
}
+SerializedPacket BuildUnsizedDataPacket(QuicFramer* framer,
+ const QuicPacketHeader& header,
+ const QuicFrames& frames) {
+ const size_t max_plaintext_size = framer->GetMaxPlaintextSize(kMaxPacketSize);
+ size_t packet_size = GetPacketHeaderSize(header);
+ for (size_t i = 0; i < frames.size(); ++i) {
+ DCHECK_LE(packet_size, max_plaintext_size);
+ bool first_frame = i == 0;
+ bool last_frame = i == frames.size() - 1;
+ const size_t frame_size = framer->GetSerializedFrameLength(
+ frames[i], max_plaintext_size - packet_size, first_frame, last_frame,
+ header.is_in_fec_group,
+ header.public_header.sequence_number_length);
+ DCHECK(frame_size);
+ packet_size += frame_size;
+ }
+ return framer->BuildDataPacket(header, frames, packet_size);
+}
+
MockFramerVisitor::MockFramerVisitor() {
// By default, we want to accept packets.
ON_CALL(*this, OnProtocolVersionMismatch(_))
@@ -391,6 +410,12 @@
return addr;
}
+IPAddressNumber Loopback6() {
+ IPAddressNumber addr;
+ CHECK(ParseIPLiteralToNumber("::1", &addr));
+ return addr;
+}
+
void GenerateBody(string* body, int length) {
body->clear();
body->reserve(length);
@@ -423,7 +448,7 @@
frames.push_back(frame);
QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(), false);
scoped_ptr<QuicPacket> packet(
- framer.BuildUnsizedDataPacket(header, frames).packet);
+ BuildUnsizedDataPacket(&framer, header, frames).packet);
EXPECT_TRUE(packet != NULL);
QuicEncryptedPacket* encrypted = framer.EncryptPacket(ENCRYPTION_NONE,
sequence_number,
@@ -500,7 +525,7 @@
QuicFrame frame(&stream_frame);
QuicFrames frames;
frames.push_back(frame);
- return quic_framer.BuildUnsizedDataPacket(header, frames).packet;
+ return BuildUnsizedDataPacket(&quic_framer, header, frames).packet;
}
QuicPacket* ConstructHandshakePacket(QuicConnectionId connection_id,
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 8bf069b..83d2837 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -49,6 +49,9 @@
// Returns an address for 127.0.0.1.
IPAddressNumber Loopback4();
+// Returns an address for ::1.
+IPAddressNumber Loopback6();
+
void GenerateBody(std::string* body, int length);
// Create an encrypted packet for testing.
@@ -93,6 +96,13 @@
QuicAckFrame MakeAckFrameWithNackRanges(size_t num_nack_ranges,
QuicPacketSequenceNumber least_unacked);
+// 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.
+SerializedPacket BuildUnsizedDataPacket(QuicFramer* framer,
+ const QuicPacketHeader& header,
+ const QuicFrames& frames);
+
template<typename SaveType>
class ValueRestore {
public:
@@ -419,9 +429,10 @@
bool(QuicTime, QuicByteCount, QuicPacketSequenceNumber,
QuicByteCount, HasRetransmittableData));
MOCK_METHOD1(OnRetransmissionTimeout, void(bool));
- MOCK_METHOD3(TimeUntilSend, QuicTime::Delta(QuicTime now,
- QuicByteCount bytes_in_flight,
- HasRetransmittableData));
+ MOCK_CONST_METHOD3(TimeUntilSend,
+ QuicTime::Delta(QuicTime now,
+ QuicByteCount bytes_in_flight,
+ HasRetransmittableData));
MOCK_CONST_METHOD0(BandwidthEstimate, QuicBandwidth(void));
MOCK_METHOD1(OnRttUpdated, void(QuicPacketSequenceNumber));
MOCK_CONST_METHOD0(RetransmissionDelay, QuicTime::Delta(void));