summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-05 03:23:22 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-05 03:23:22 +0000
commit730b35d7591e690f7740a4adbd36c35890cacf7f (patch)
treee1654aa74e9be4633978c49611413fa367fbc499
parent81b49cd7dfa640179eac2a253d948510d0787e18 (diff)
downloadchromium_src-730b35d7591e690f7740a4adbd36c35890cacf7f.zip
chromium_src-730b35d7591e690f7740a4adbd36c35890cacf7f.tar.gz
chromium_src-730b35d7591e690f7740a4adbd36c35890cacf7f.tar.bz2
Land Recent QUIC Changes.
Close the QUIC connection if we accidentally try to send too many bytes and hit flow control send limits. Also splits the error code QUIC_FLOW_CONTROL_ERROR into three errors for more helpful tracking of error sources: The peer received too much data, violating flow control. QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA The peer sent too much data, violating flow control. QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA The peer received an invalid flow control window. QUIC_FLOW_CONTROL_INVALID_WINDOW QUIC: close the connection if we accidentally try to send too many bytes and hit flow control send limits. Also adds more descriptive error codes. Merge internal change: 68490433 https://codereview.chromium.org/315713003/ Store a ptr to QuicConnection in QuicFlowController, rather than passing it as an argument to various QuicFlowController methods. No behavior change. Merge internal change: 68489619 https://codereview.chromium.org/316643004/ Disable stream flow control if negotiated version is < QUIC_VERSION_17. This protectes against the following: 1) client attempts 0RTT with QUIC_VERSION_18. 2) server only speaks QUIC_VERSION_16 3) client switches to QUIC_VERSION_16 but keeps doing stream flow control, while the server does not. This should never be something that happens as Chrome only ever speaks one version of QUIC at a time. QUIC: disable stream flow control if negotiated version is < QUIC_VERSION_17. Merge internal change: 68488680 https://codereview.chromium.org/312883003/ Check for flow control violation sooner when processing new frame. This means we don't waste time trying to read/process the contents of a frame which is invalid, and we remove the risk of bytes_consumed being > receive_window_offset. Prior to this change, we checked for flow control violation *after* the sequencer processed the frame, and if it arrived in order (but with too much data for flow control) it would still be consumed before we close the connection. QUIC: check for flow control violation sooner when processing new frame. Merge internal change: 68478945 https://codereview.chromium.org/310213002/ As promised in cl/68185060 (https://codereview.chromium.org/308363002/), move the call to MaybeSendWindowUpdate inside QuicFlowController::AddBytesConsumed. Users always want to call both of these, so make it impossible to forget. Move the call to MaybeSendWindowUpdate inside QuicFlowController::AddBytesConsumed Merge internal change: 68477157 https://codereview.chromium.org/311933003/ Make QUIC SendAlgorithmInterface's TimeUntilSend const to ensure TimeUntilSend can be invoked multiple times and return the same result. Merge internal change: 68456011 https://codereview.chromium.org/312763003/ Always use "ConvertIPv4NumberToIPv6Number" of addresses when constructing and verifying QUIC source address tokens. This is to fix a low rate of source address token verifications due to the normalized and "ConvertIPv4NumberToIPv6Number" version of the same ipv4 addresses looking different. Use "ConvertIPv4NumberToIPv6Number" of ipv4 addresses when computing and verifying QUIC source address tokens. Not flag protected. Merge internal change: 68409604 https://codereview.chromium.org/310153002/ QUIC: Change the tag_vector parameter of ContainsQuicTag to be a const reference. Merge internal change: 68399425 https://codereview.chromium.org/304273012/ Refactor to move comments and flip an if in QUIC's PacingSender in order to improve readability. Merge internal change: 68398155 https://codereview.chromium.org/311723002/ Export QUIC spurious retransmit counts by transmit type to varz. Not flag protected. Merge internal change: 68397671 https://codereview.chromium.org/315453002/ Remove QUIC's PacedSender, a test-only class used in FixRateSender, another test-only class. Merge internal change: 68374544 https://codereview.chromium.org/309183002/ When closing a QUIC stream, mark all unconsumed bytes as consumed. This includes all bytes currently buffered in the sequencer. If a stream has consumed N bytes, and has a highest received byte offset of M bytes, then on close it marks as consumed an additional M-N bytes. This ensures that the endpoints have consistent connection level flow control state. QUIC: when closing a stream, mark all bytes between highest consumed byte and highest byte offset as consumed, for consistent connection level flow control state. Merge internal change: 68270210 https://codereview.chromium.org/302373003/ Add quic_types.h and move the typedefs unrelated to the QUIC protocol specification from quic_protocol.h to quic_types.h. Add the QuicAsyncStatus enum type (to quic_types.h), which represents the return status of asynchronous operations. Replace ProofVerifier::Status with QuicAsyncStatus. Moved typedefs unrelated to the QUIC protocol specification from quic_protocol.h to the new quic_types.h header. Replaced ProofVerifier::Status with the new general-purpose QuicAsyncStatus enum type. Merge internal change: 68267420 https://codereview.chromium.org/309013006/ R=rch@chromium.org Review URL: https://codereview.chromium.org/312803005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274994 0039d316-1c4b-4281-b951-d872f2087c98
-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_; }