summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/net.gypi5
-rw-r--r--net/quic/congestion_control/fix_rate_sender.cc23
-rw-r--r--net/quic/congestion_control/fix_rate_sender.h6
-rw-r--r--net/quic/congestion_control/fix_rate_test.cc66
-rw-r--r--net/quic/congestion_control/leaky_bucket.cc10
-rw-r--r--net/quic/congestion_control/leaky_bucket.h2
-rw-r--r--net/quic/congestion_control/paced_sender.cc55
-rw-r--r--net/quic/congestion_control/paced_sender.h42
-rw-r--r--net/quic/congestion_control/paced_sender_test.cc78
-rw-r--r--net/quic/congestion_control/pacing_sender.cc15
-rw-r--r--net/quic/congestion_control/pacing_sender.h2
-rw-r--r--net/quic/congestion_control/send_algorithm_interface.h2
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.cc6
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.h6
-rw-r--r--net/quic/crypto/proof_test.cc8
-rw-r--r--net/quic/crypto/proof_verifier.h34
-rw-r--r--net/quic/crypto/proof_verifier_chromium.cc41
-rw-r--r--net/quic/crypto/proof_verifier_chromium.h17
-rw-r--r--net/quic/crypto/quic_crypto_server_config.cc12
-rw-r--r--net/quic/crypto/quic_crypto_server_config_test.cc14
-rw-r--r--net/quic/quic_connection.cc3
-rw-r--r--net/quic/quic_connection.h5
-rw-r--r--net/quic/quic_crypto_client_stream.cc8
-rw-r--r--net/quic/quic_data_stream_test.cc6
-rw-r--r--net/quic/quic_flow_controller.cc41
-rw-r--r--net/quic/quic_flow_controller.h22
-rw-r--r--net/quic/quic_flow_controller_test.cc79
-rw-r--r--net/quic/quic_packet_generator.h1
-rw-r--r--net/quic/quic_protocol.cc29
-rw-r--r--net/quic/quic_protocol.h52
-rw-r--r--net/quic/quic_sent_packet_manager.cc60
-rw-r--r--net/quic/quic_sent_packet_manager.h23
-rw-r--r--net/quic/quic_sent_packet_manager_test.cc21
-rw-r--r--net/quic/quic_session.cc15
-rw-r--r--net/quic/quic_session_test.cc100
-rw-r--r--net/quic/quic_types.cc34
-rw-r--r--net/quic/quic_types.h69
-rw-r--r--net/quic/quic_unacked_packet_map.cc4
-rw-r--r--net/quic/quic_unacked_packet_map.h3
-rw-r--r--net/quic/quic_unacked_packet_map_test.cc2
-rw-r--r--net/quic/quic_utils.cc4
-rw-r--r--net/quic/reliable_quic_stream.cc44
-rw-r--r--net/quic/reliable_quic_stream.h4
-rw-r--r--net/quic/reliable_quic_stream_test.cc27
-rw-r--r--net/quic/test_tools/quic_connection_peer.cc6
-rw-r--r--net/quic/test_tools/quic_connection_peer.h3
-rw-r--r--net/quic/test_tools/quic_test_utils.cc6
-rw-r--r--net/quic/test_tools/quic_test_utils.h10
-rw-r--r--net/tools/quic/quic_packet_writer_wrapper.cc2
-rw-r--r--net/tools/quic/quic_socket_utils.h3
-rw-r--r--net/tools/quic/test_tools/quic_test_client.cc23
51 files changed, 636 insertions, 517 deletions
diff --git a/net/net.gypi b/net/net.gypi
index 8577ac9..344f8a0 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -732,8 +732,6 @@
'quic/congestion_control/leaky_bucket.h',
'quic/congestion_control/loss_detection_interface.cc',
'quic/congestion_control/loss_detection_interface.h',
- 'quic/congestion_control/paced_sender.cc',
- 'quic/congestion_control/paced_sender.h',
'quic/congestion_control/pacing_sender.cc',
'quic/congestion_control/pacing_sender.h',
'quic/congestion_control/receive_algorithm_interface.cc',
@@ -914,6 +912,8 @@
'quic/quic_stream_sequencer.h',
'quic/quic_time.cc',
'quic/quic_time.h',
+ 'quic/quic_types.cc',
+ 'quic/quic_types.h',
'quic/quic_unacked_packet_map.cc',
'quic/quic_unacked_packet_map.h',
'quic/quic_utils.cc',
@@ -1401,7 +1401,6 @@
'quic/congestion_control/fix_rate_test.cc',
'quic/congestion_control/hybrid_slow_start_test.cc',
'quic/congestion_control/leaky_bucket_test.cc',
- 'quic/congestion_control/paced_sender_test.cc',
'quic/congestion_control/pacing_sender_test.cc',
'quic/congestion_control/rtt_stats_test.cc',
'quic/congestion_control/tcp_cubic_sender_test.cc',
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 @@ FixRateSender::FixRateSender(const RttStats* rtt_stats)
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 @@ void FixRateSender::OnIncomingQuicCongestionFeedbackFrame(
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 @@ bool FixRateSender::OnPacketSent(
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 @@ void FixRateSender::OnRetransmissionTimeout(bool packets_retransmitted) { }
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 @@ class NET_EXPORT_PRIVATE FixRateSender : public SendAlgorithmInterface {
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 @@ TEST_F(FixRateTest, SenderAPI) {
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 @@ void LeakyBucket::Add(QuicTime now, QuicByteCount bytes) {
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 @@ class NET_EXPORT_PRIVATE LeakyBucket {
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 96f6c62..97138f7 100644
--- a/net/quic/congestion_control/pacing_sender.cc
+++ b/net/quic/congestion_control/pacing_sender.cc
@@ -59,19 +59,20 @@ bool PacingSender::OnPacketSent(
// 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);
- // As long as we're making up time and not application limited,
- // continue to consider the packets delayed.
// 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;
- if (making_up_for_lost_time || application_limited) {
+ 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 {
- last_delayed_packet_sent_time_ = sent_time;
}
} else {
next_packet_send_time_ =
@@ -90,7 +91,7 @@ void PacingSender::OnRetransmissionTimeout(bool packets_retransmitted) {
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_) {
diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h
index f7c2622..c741771 100644
--- a/net/quic/congestion_control/pacing_sender.h
+++ b/net/quic/congestion_control/pacing_sender.h
@@ -47,7 +47,7 @@ class NET_EXPORT_PRIVATE PacingSender : public SendAlgorithmInterface {
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;
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 @@ class NET_EXPORT_PRIVATE SendAlgorithmInterface {
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 @@ bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/,
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 @@ QuicTime::Delta TcpCubicSender::TimeUntilSend(
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 @@ void TcpCubicSender::PrrOnPacketAcked(QuicByteCount acked_bytes) {
}
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 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
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 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
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 @@ class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface {
// 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/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 @@ void RunVerification(ProofVerifier* verifier,
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 @@ class NET_EXPORT_PRIVATE ProofVerifierCallback {
// 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 @@ class ProofVerifierChromium::Job {
// 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 @@ ProofVerifierChromium::Job::Job(ProofVerifierChromium* proof_verifier,
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 @@ ProofVerifierChromium::Status ProofVerifierChromium::Job::VerifyProof(
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 @@ ProofVerifierChromium::Status ProofVerifierChromium::Job::VerifyProof(
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 @@ ProofVerifierChromium::Status ProofVerifierChromium::Job::VerifyProof(
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 @@ ProofVerifierChromium::Status ProofVerifierChromium::Job::VerifyProof(
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 @@ ProofVerifierChromium::Status ProofVerifierChromium::Job::VerifyProof(
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 @@ ProofVerifierChromium::~ProofVerifierChromium() {
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 @@ ProofVerifierChromium::Status ProofVerifierChromium::VerifyProof(
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 @@ class NET_EXPORT_PRIVATE ProofVerifierChromium : public ProofVerifier {
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_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 @@ string QuicCryptoServerConfig::NewSourceAddressToken(const Config& config,
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 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken(
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 @@ TEST(QuicCryptoServerConfigTest, SourceAddressTokens) {
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_connection.cc b/net/quic/quic_connection.cc
index 04426d3..2f8c845 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -1246,7 +1246,8 @@ void QuicConnection::WritePendingRetransmissions() {
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,
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index c35e863..9e93715e 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 {
@@ -112,7 +113,8 @@ class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface {
// points. Implementations must not mutate the state of the connection
// as a result of these callbacks.
class NET_EXPORT_PRIVATE QuicConnectionDebugVisitor
- : public QuicPacketGenerator::DebugDelegate {
+ : public QuicPacketGenerator::DebugDelegate,
+ public QuicSentPacketManager::DebugDelegate {
public:
virtual ~QuicConnectionDebugVisitor() {}
@@ -347,6 +349,7 @@ class NET_EXPORT_PRIVATE QuicConnection
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_; }
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 9fa9367..dcc4182 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -237,7 +237,7 @@ void QuicCryptoClientStream::DoHandshakeLoop(
verify_ok_ = false;
- ProofVerifier::Status status = verifier->VerifyProof(
+ QuicAsyncStatus status = verifier->VerifyProof(
server_id_.host(),
cached->server_config(),
cached->certs(),
@@ -248,14 +248,14 @@ void QuicCryptoClientStream::DoHandshakeLoop(
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_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 @@ TEST_P(QuicDataStreamTest, StreamFlowControlViolation) {
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 @@ TEST_P(QuicDataStreamTest, ConnectionFlowControlViolation) {
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 a469fd5..6ca3520 100644
--- a/net/quic/quic_flow_controller.cc
+++ b/net/quic/quic_flow_controller.cc
@@ -13,31 +13,32 @@ namespace net {
#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),
- 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) {
+ : 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,6 +50,8 @@ void QuicFlowController::AddBytesConsumed(uint64 bytes_consumed) {
bytes_consumed_ += bytes_consumed;
DVLOG(1) << ENDPOINT << "Stream " << id_ << " consumed: " << bytes_consumed_;
+
+ MaybeSendWindowUpdate();
}
bool QuicFlowController::UpdateHighestReceivedOffset(uint64 new_offset) {
@@ -78,6 +81,9 @@ void QuicFlowController::AddBytesSent(uint64 bytes_sent) {
<< 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;
}
@@ -101,7 +107,7 @@ bool QuicFlowController::FlowControlViolation() {
return false;
}
-void QuicFlowController::MaybeSendWindowUpdate(QuicConnection* connection) {
+void QuicFlowController::MaybeSendWindowUpdate() {
if (!IsEnabled()) {
return;
}
@@ -109,6 +115,7 @@ void QuicFlowController::MaybeSendWindowUpdate(QuicConnection* connection) {
// 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);
@@ -124,11 +131,11 @@ void QuicFlowController::MaybeSendWindowUpdate(QuicConnection* connection) {
<< ". 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;
}
@@ -141,7 +148,7 @@ void QuicFlowController::MaybeSendBlocked(QuicConnection* connection) {
<< ", 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.
diff --git a/net/quic/quic_flow_controller.h b/net/quic/quic_flow_controller.h
index 596ef1a..e5f5494 100644
--- a/net/quic/quic_flow_controller.h
+++ b/net/quic/quic_flow_controller.h
@@ -25,7 +25,7 @@ const QuicStreamId kConnectionLevelId = 0;
// 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,
@@ -39,7 +39,8 @@ class NET_EXPORT_PRIVATE QuicFlowController {
// in the case where |new_offset| is <= highest_received_byte_offset_.
bool UpdateHighestReceivedOffset(uint64 new_offset);
- // 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 @@ class NET_EXPORT_PRIVATE QuicFlowController {
// 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,6 +69,8 @@ class NET_EXPORT_PRIVATE QuicFlowController {
// 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_;
}
@@ -78,6 +78,14 @@ class NET_EXPORT_PRIVATE QuicFlowController {
private:
friend class test::QuicFlowControllerPeer;
+ // 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.
QuicStreamId id_;
diff --git a/net/quic/quic_flow_controller_test.cc b/net/quic/quic_flow_controller_test.cc
index 7ef9bb4..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 @@ class QuicFlowControllerTest : public ::testing::Test {
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 @@ TEST_F(QuicFlowControllerTest, SendingBytes) {
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 @@ TEST_F(QuicFlowControllerTest, SendingBytes) {
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,8 +95,11 @@ TEST_F(QuicFlowControllerTest, ReceivingBytes) {
EXPECT_TRUE(flow_controller_->IsEnabled());
EXPECT_FALSE(flow_controller_->IsBlocked());
EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
- // Buffer some bytes, not enough to fill window.
+ // 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());
@@ -104,21 +107,27 @@ TEST_F(QuicFlowControllerTest, ReceivingBytes) {
QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
// 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((receive_window_ / 2) - 1,
+ EXPECT_EQ(kInitialFlowControlWindowForTest,
QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- MockConnection connection(false);
- EXPECT_CALL(connection, SendWindowUpdate(stream_id_, _)).Times(1);
- flow_controller_->MaybeSendWindowUpdate(&connection);
}
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());
@@ -148,15 +157,14 @@ TEST_F(QuicFlowControllerTest,
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)
@@ -164,8 +172,8 @@ TEST_F(QuicFlowControllerTest,
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());
@@ -189,18 +197,17 @@ TEST_F(QuicFlowControllerTest, OnlySendBlockedFrameOncePerOffset) {
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_));
@@ -211,7 +218,7 @@ TEST_F(QuicFlowControllerTest, OnlySendBlockedFrameOncePerOffset) {
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_packet_generator.h b/net/quic/quic_packet_generator.h
index d9de488..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 {
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 7502cdb..cd73694 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -144,7 +144,7 @@ uint32 MakeQuicTag(char a, char b, char c, char d) {
static_cast<uint32>(d) << 24;
}
-bool ContainsQuicTag(QuicTagVector tag_vector, QuicTag tag) {
+bool ContainsQuicTag(const QuicTagVector& tag_vector, QuicTag tag) {
return std::find(tag_vector.begin(), tag_vector.end(), tag)
!= tag_vector.end();
}
@@ -751,6 +751,7 @@ TransmissionInfo::TransmissionInfo()
sent_time(QuicTime::Zero()),
bytes_sent(0),
nack_count(0),
+ transmission_type(NOT_RETRANSMISSION),
all_transmissions(NULL),
in_flight(false) { }
@@ -763,6 +764,7 @@ TransmissionInfo::TransmissionInfo(
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);
@@ -772,38 +774,17 @@ TransmissionInfo::TransmissionInfo(
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 6dd8ef3..76b31f4 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -319,7 +319,7 @@ NET_EXPORT_PRIVATE std::string QuicVersionVectorToString(
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(QuicTagVector tag_vector, QuicTag 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);
@@ -454,8 +454,12 @@ enum QuicErrorCode {
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,
@@ -513,7 +517,7 @@ enum QuicErrorCode {
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 {
@@ -1030,6 +1034,7 @@ struct NET_EXPORT_PRIVATE TransmissionInfo {
TransmissionInfo(RetransmittableFrames* retransmittable_frames,
QuicPacketSequenceNumber sequence_number,
QuicSequenceNumberLength sequence_number_length,
+ TransmissionType transmission_type,
SequenceNumberSet* all_transmissions);
RetransmittableFrames* retransmittable_frames;
@@ -1039,6 +1044,8 @@ struct NET_EXPORT_PRIVATE TransmissionInfo {
// 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;
@@ -1046,43 +1053,6 @@ struct NET_EXPORT_PRIVATE TransmissionInfo {
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_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 286ef56..8c41b9c 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -62,6 +62,7 @@ QuicSentPacketManager::QuicSentPacketManager(bool is_server,
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)),
@@ -113,9 +114,17 @@ void QuicSentPacketManager::OnSerializedPacket(
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.
@@ -123,7 +132,8 @@ void QuicSentPacketManager::OnRetransmittedPacket(
new_sequence_number);
unacked_packets_.OnRetransmittedPacket(old_sequence_number,
- new_sequence_number);
+ new_sequence_number,
+ transmission_type);
}
void QuicSentPacketManager::OnIncomingAck(
@@ -276,6 +286,27 @@ void QuicSentPacketManager::MarkForRetransmission(
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();
}
@@ -348,19 +379,22 @@ QuicUnackedPacketMap::const_iterator QuicSentPacketManager::MarkPacketHandled(
// 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.
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index 5823942..395d212 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -41,6 +41,19 @@ struct QuicConnectionStats;
// 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,
@@ -159,6 +172,10 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
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;
@@ -239,6 +256,11 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
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
@@ -262,6 +284,7 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
const QuicClock* clock_;
QuicConnectionStats* stats_;
+ DebugDelegate* debug_delegate_;
RttStats rtt_stats_;
scoped_ptr<SendAlgorithmInterface> send_algorithm_;
scoped_ptr<LossDetectionInterface> loss_algorithm_;
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 @@ MATCHER(KeyEq, "") {
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 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
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 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
.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, RetransmitTwiceThenAckPreviousBeforeSend) {
}
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 @@ TEST_F(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) {
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 @@ QuicSession::QuicSession(QuicConnection* connection,
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 @@ void QuicSession::OnConfigNegotiated() {
<< "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 @@ void QuicSession::OnSuccessfulVersionNegotiation(const QuicVersion& version) {
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_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 @@ class TestSession : public QuicSession {
return WritevData(id, IOVector(), 0, true, NULL);
}
+ using QuicSession::PostProcessAfterData;
+
private:
StrictMock<TestCryptoStream> crypto_stream_;
@@ -661,7 +663,8 @@ TEST_P(QuicSessionTest, InvalidFlowControlWindowInHandshake) {
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 @@ TEST_P(QuicSessionTest, InvalidFlowControlWindow) {
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_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..01415bc3
--- /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::AddPacket(
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 @@ void QuicUnackedPacketMap::OnRetransmittedPacket(
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 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
// 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..c5264fd1 100644
--- a/net/quic/quic_unacked_packet_map_test.cc
+++ b/net/quic/quic_unacked_packet_map_test.cc
@@ -130,7 +130,7 @@ TEST_F(QuicUnackedPacketMapTest, RetransmittedPacket) {
// 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 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
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 64d8aae..b73185b 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -124,7 +124,7 @@ ReliableQuicStream::ReliableQuicStream(QuicStreamId id, QuicSession* session)
rst_sent_(false),
is_server_(session_->is_server()),
flow_controller_(
- session_->connection()->version(),
+ session_->connection(),
id_,
is_server_,
session_->config()->HasReceivedInitialFlowControlWindowBytes() ?
@@ -155,17 +155,18 @@ bool ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
stream_bytes_read_ += frame_payload_size;
// Flow control is interested in tracking highest received offset.
- MaybeIncreaseHighestReceivedOffset(frame.offset + 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;
+ 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;
+ }
}
- return accepted;
+ return sequencer_.OnStreamFrame(frame);
}
int ReliableQuicStream::num_frames_received() const {
@@ -298,8 +299,8 @@ void ReliableQuicStream::OnCanWrite() {
}
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 @@ void ReliableQuicStream::OnClose() {
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,7 +445,7 @@ void ReliableQuicStream::OnWindowUpdateFrame(
}
}
-void ReliableQuicStream::MaybeIncreaseHighestReceivedOffset(uint64 new_offset) {
+bool ReliableQuicStream::MaybeIncreaseHighestReceivedOffset(uint64 new_offset) {
if (flow_controller_.IsEnabled()) {
uint64 increment =
new_offset - flow_controller_.highest_received_byte_offset();
@@ -447,8 +456,10 @@ void ReliableQuicStream::MaybeIncreaseHighestReceivedOffset(uint64 new_offset) {
connection_flow_controller_->UpdateHighestReceivedOffset(
connection_flow_controller_->highest_received_byte_offset() +
increment);
+ return true;
}
}
+ return false;
}
void ReliableQuicStream::AddBytesSent(uint64 bytes) {
@@ -460,11 +471,12 @@ void ReliableQuicStream::AddBytesSent(uint64 bytes) {
void ReliableQuicStream::AddBytesConsumed(uint64 bytes) {
if (flow_controller_.IsEnabled()) {
- flow_controller_.AddBytesConsumed(bytes);
- flow_controller_.MaybeSendWindowUpdate(session()->connection());
+ // Only adjust stream level flow controller if we are still reading.
+ if (!read_side_closed_) {
+ flow_controller_.AddBytesConsumed(bytes);
+ }
connection_flow_controller_->AddBytesConsumed(bytes);
- connection_flow_controller_->MaybeSendWindowUpdate(session()->connection());
}
}
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 68ff6dd..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 {
@@ -99,7 +100,8 @@ class NET_EXPORT_PRIVATE ReliableQuicStream {
QuicFlowController* flow_controller() { return &flow_controller_; }
// Called when we see a frame which could increase the highest offset.
- void MaybeIncreaseHighestReceivedOffset(uint64 new_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 sequencer as bytes are consumed from the buffer.
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index 2fc4e9d..5d1ea9d 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -557,6 +557,33 @@ TEST_F(ReliableQuicStreamTest, WriteAndBufferDataWithAckNotiferOnlyFinRemains) {
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/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 @@ QuicEncryptedPacket* QuicConnectionPeer::GetConnectionClosePacket(
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..cf0ea38a 100644
--- a/net/quic/test_tools/quic_connection_peer.h
+++ b/net/quic/test_tools/quic_connection_peer.h
@@ -108,6 +108,9 @@ class QuicConnectionPeer {
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_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 30bf282..39458e1 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -410,6 +410,12 @@ IPAddressNumber Loopback4() {
return addr;
}
+IPAddressNumber Loopback6() {
+ IPAddressNumber addr;
+ CHECK(ParseIPLiteralToNumber("::1", &addr));
+ return addr;
+}
+
void GenerateBody(string* body, int length) {
body->clear();
body->reserve(length);
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 5367c76..83d2837 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -49,6 +49,9 @@ QuicVersion QuicVersionMin();
// 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.
@@ -426,9 +429,10 @@ class MockSendAlgorithm : public SendAlgorithmInterface {
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));
diff --git a/net/tools/quic/quic_packet_writer_wrapper.cc b/net/tools/quic/quic_packet_writer_wrapper.cc
index e4e8a40..3d1b03d 100644
--- a/net/tools/quic/quic_packet_writer_wrapper.cc
+++ b/net/tools/quic/quic_packet_writer_wrapper.cc
@@ -4,7 +4,7 @@
#include "net/tools/quic/quic_packet_writer_wrapper.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_types.h"
namespace net {
namespace tools {
diff --git a/net/tools/quic/quic_socket_utils.h b/net/tools/quic/quic_socket_utils.h
index de4f7af..697e955 100644
--- a/net/tools/quic/quic_socket_utils.h
+++ b/net/tools/quic/quic_socket_utils.h
@@ -11,8 +11,9 @@
#include <sys/socket.h>
#include <string>
+#include "base/basictypes.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_types.h"
namespace net {
namespace tools {
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 625cf1a..51f599d 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -38,17 +38,18 @@ namespace {
class RecordingProofVerifier : public ProofVerifier {
public:
// ProofVerifier interface.
- virtual Status VerifyProof(const string& hostname,
- const string& server_config,
- const vector<string>& certs,
- const string& signature,
- const ProofVerifyContext* context,
- string* error_details,
- scoped_ptr<ProofVerifyDetails>* details,
- ProofVerifierCallback* callback) OVERRIDE {
+ virtual QuicAsyncStatus VerifyProof(
+ const string& hostname,
+ const string& server_config,
+ const vector<string>& certs,
+ const string& signature,
+ const ProofVerifyContext* context,
+ string* error_details,
+ scoped_ptr<ProofVerifyDetails>* details,
+ ProofVerifierCallback* callback) OVERRIDE {
common_name_.clear();
if (certs.empty()) {
- return FAILURE;
+ return QUIC_FAILURE;
}
// Convert certs to X509Certificate.
@@ -59,11 +60,11 @@ class RecordingProofVerifier : public ProofVerifier {
scoped_refptr<net::X509Certificate> cert =
net::X509Certificate::CreateFromDERCertChain(cert_pieces);
if (!cert.get()) {
- return FAILURE;
+ return QUIC_FAILURE;
}
common_name_ = cert->subject().GetDisplayName();
- return SUCCESS;
+ return QUIC_SUCCESS;
}
const string& common_name() const { return common_name_; }