diff options
author | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-31 23:17:14 +0000 |
---|---|---|
committer | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-31 23:17:14 +0000 |
commit | c5cc9bd03a52d4c96d5e00efe4633ae965c4dcfd (patch) | |
tree | 8910a2ed2f88a1751e8ea7823b7b2bc3c64da124 /net/quic | |
parent | 45a4f1ff5da3196aa03cfbe3862f57a1e1eb029c (diff) | |
download | chromium_src-c5cc9bd03a52d4c96d5e00efe4633ae965c4dcfd.zip chromium_src-c5cc9bd03a52d4c96d5e00efe4633ae965c4dcfd.tar.gz chromium_src-c5cc9bd03a52d4c96d5e00efe4633ae965c4dcfd.tar.bz2 |
Land Recent QUIC Changes.
Add a QUIC flag to enable time based loss detection as the default.
Merge internal change: 63942432
(this CL was merged in https://codereview.chromium.org/217133004/
added FLAGS_quic_use_time_loss_detection to quic_flags.cc
and made the change to quic_connection.cc also).
Now that we have a default send window, no need to send WINDOW_UPDATE to
ensure streams are not flow control blocked
Merge internal change: 63887815
https://codereview.chromium.org/217003005/
Changing the max stream delta to allow for all open streams in a given
direction. Previously, we allowed 100 streams (200 even/odd stream ids)
but an insufficient delta of 100.
Allowing a slightly larger stream delta for QUIC.
Merge internal change: 63880428
https://codereview.chromium.org/212063006/
UDP proxy session for QUIC. This is not production ready. Major issues
include the sharding issue and the time wait list.
Merge internal change: 63878878
https://codereview.chromium.org/216943004/
Don't try and close a QUIC connection twice while processing a single
incoming packet.
Merge internal change: 63878490
https://codereview.chromium.org/217053004/
Added missing OVERRIDE.
Add the ability to negotiate the QUIC loss detection algorithm in the
crypto handshake.
Added FLAGS_quic_congestion_control_inter_arrival and
FLAGS_quic_use_time_loss_detection. They default to false.
Merge internal change: 63874474
https://codereview.chromium.org/217133004/
Send BLOCKED frame directly from ReliableQuicStream.
Merge internal change: 63808643
https://codereview.chromium.org/216423006/
Simplified ReliableQuicStream::IsFlowControlBlocked.
Merge internal change: 63807857
https://codereview.chromium.org/217103003/
Track the sent_time for ack packets so the RTT is updated when ack
packets are acked as the largest observed.
Merge internal change: 63806273
https://codereview.chromium.org/216423005/
R=rch@chromium.org
Review URL: https://codereview.chromium.org/217303003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@260695 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/quic')
32 files changed, 291 insertions, 108 deletions
diff --git a/net/quic/congestion_control/loss_detection_interface.cc b/net/quic/congestion_control/loss_detection_interface.cc index ddb5b43..035848c 100644 --- a/net/quic/congestion_control/loss_detection_interface.cc +++ b/net/quic/congestion_control/loss_detection_interface.cc @@ -5,12 +5,21 @@ #include "net/quic/congestion_control/loss_detection_interface.h" #include "net/quic/congestion_control/tcp_loss_algorithm.h" +#include "net/quic/congestion_control/time_loss_algorithm.h" namespace net { // Factory for loss detection algorithm. -LossDetectionInterface* LossDetectionInterface::Create() { - return new TCPLossAlgorithm(); +LossDetectionInterface* LossDetectionInterface::Create( + LossDetectionType loss_type) { + switch (loss_type) { + case kNack: + return new TCPLossAlgorithm(); + case kTime: + return new TimeLossAlgorithm(); + } + LOG(DFATAL) << "Unknown loss detection algorithm:" << loss_type; + return NULL; } } // namespace net diff --git a/net/quic/congestion_control/loss_detection_interface.h b/net/quic/congestion_control/loss_detection_interface.h index 21cc4f7..5aaa51d 100644 --- a/net/quic/congestion_control/loss_detection_interface.h +++ b/net/quic/congestion_control/loss_detection_interface.h @@ -19,10 +19,12 @@ class RttStats; class NET_EXPORT_PRIVATE LossDetectionInterface { public: // Creates a TCP loss detector. - static LossDetectionInterface* Create(); + static LossDetectionInterface* Create(LossDetectionType loss_type); virtual ~LossDetectionInterface() {} + virtual LossDetectionType GetLossDetectionType() const = 0; + // Called when a new ack arrives or the loss alarm fires. virtual SequenceNumberSet DetectLostPackets( const QuicUnackedPacketMap& unacked_packets, diff --git a/net/quic/congestion_control/tcp_loss_algorithm.cc b/net/quic/congestion_control/tcp_loss_algorithm.cc index d63742a..70198d6 100644 --- a/net/quic/congestion_control/tcp_loss_algorithm.cc +++ b/net/quic/congestion_control/tcp_loss_algorithm.cc @@ -23,6 +23,10 @@ static const double kEarlyRetransmitLossDelayMultiplier = 1.25; TCPLossAlgorithm::TCPLossAlgorithm() : loss_detection_timeout_(QuicTime::Zero()) { } +LossDetectionType TCPLossAlgorithm::GetLossDetectionType() const { + return kNack; +} + // Uses nack counts to decide when packets are lost. SequenceNumberSet TCPLossAlgorithm::DetectLostPackets( const QuicUnackedPacketMap& unacked_packets, diff --git a/net/quic/congestion_control/tcp_loss_algorithm.h b/net/quic/congestion_control/tcp_loss_algorithm.h index e8b2da1..06f6256 100644 --- a/net/quic/congestion_control/tcp_loss_algorithm.h +++ b/net/quic/congestion_control/tcp_loss_algorithm.h @@ -23,6 +23,8 @@ class NET_EXPORT_PRIVATE TCPLossAlgorithm : public LossDetectionInterface { TCPLossAlgorithm(); virtual ~TCPLossAlgorithm() {} + virtual LossDetectionType GetLossDetectionType() const OVERRIDE; + // Uses nack counts to decide when packets are lost. virtual SequenceNumberSet DetectLostPackets( const QuicUnackedPacketMap& unacked_packets, diff --git a/net/quic/congestion_control/tcp_loss_algorithm_test.cc b/net/quic/congestion_control/tcp_loss_algorithm_test.cc index bc9db2a..7d8cdee1 100644 --- a/net/quic/congestion_control/tcp_loss_algorithm_test.cc +++ b/net/quic/congestion_control/tcp_loss_algorithm_test.cc @@ -27,7 +27,7 @@ class TcpLossAlgorithmTest : public ::testing::Test { SerializedPacket packet(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, new RetransmittableFrames()); unacked_packets_.AddPacket(packet); - unacked_packets_.SetPending(sequence_number, clock_.Now(), 1000); + unacked_packets_.SetSent(sequence_number, clock_.Now(), 1000, true); } void VerifyLosses(QuicPacketSequenceNumber largest_observed, diff --git a/net/quic/congestion_control/time_loss_algorithm.cc b/net/quic/congestion_control/time_loss_algorithm.cc index dbdb52a..6cf1d81 100644 --- a/net/quic/congestion_control/time_loss_algorithm.cc +++ b/net/quic/congestion_control/time_loss_algorithm.cc @@ -23,6 +23,10 @@ static const double kLossDelayMultiplier = 1.25; TimeLossAlgorithm::TimeLossAlgorithm() : loss_detection_timeout_(QuicTime::Zero()) { } +LossDetectionType TimeLossAlgorithm::GetLossDetectionType() const { + return kTime; +} + SequenceNumberSet TimeLossAlgorithm::DetectLostPackets( const QuicUnackedPacketMap& unacked_packets, const QuicTime& time, diff --git a/net/quic/congestion_control/time_loss_algorithm.h b/net/quic/congestion_control/time_loss_algorithm.h index a5cecc1..5c6fc2a 100644 --- a/net/quic/congestion_control/time_loss_algorithm.h +++ b/net/quic/congestion_control/time_loss_algorithm.h @@ -23,6 +23,8 @@ class NET_EXPORT_PRIVATE TimeLossAlgorithm : public LossDetectionInterface { TimeLossAlgorithm(); virtual ~TimeLossAlgorithm() {} + virtual LossDetectionType GetLossDetectionType() const OVERRIDE; + // Declares pending packets less than the largest observed lost when it has // been 1.25 RTT since they were sent. Packets larger than the largest // observed are retransmitted via TLP. diff --git a/net/quic/congestion_control/time_loss_algorithm_test.cc b/net/quic/congestion_control/time_loss_algorithm_test.cc index 43969a9..d9605e3 100644 --- a/net/quic/congestion_control/time_loss_algorithm_test.cc +++ b/net/quic/congestion_control/time_loss_algorithm_test.cc @@ -27,7 +27,7 @@ class TimeLossAlgorithmTest : public ::testing::Test { SerializedPacket packet(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, new RetransmittableFrames()); unacked_packets_.AddPacket(packet); - unacked_packets_.SetPending(sequence_number, clock_.Now(), 1000); + unacked_packets_.SetSent(sequence_number, clock_.Now(), 1000, true); } void VerifyLosses(QuicPacketSequenceNumber largest_observed, diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h index b634084..0e22c51 100644 --- a/net/quic/crypto/crypto_protocol.h +++ b/net/quic/crypto/crypto_protocol.h @@ -47,6 +47,10 @@ const QuicTag kQBIC = TAG('Q', 'B', 'I', 'C'); // TCP cubic const QuicTag kPACE = TAG('P', 'A', 'C', 'E'); // Paced TCP cubic const QuicTag kINAR = TAG('I', 'N', 'A', 'R'); // Inter arrival +// Loss detection algorithm types +const QuicTag kNACK = TAG('N', 'A', 'C', 'K'); // TCP style nack counting +const QuicTag kTIME = TAG('T', 'I', 'M', 'E'); // Time based + // Proof types (i.e. certificate types) // NOTE: although it would be silly to do so, specifying both kX509 and kX59R // is allowed and is equivalent to specifying only kX509. @@ -64,6 +68,7 @@ const QuicTag kAEAD = TAG('A', 'E', 'A', 'D'); // Authenticated // encryption algorithms const QuicTag kCGST = TAG('C', 'G', 'S', 'T'); // Congestion control // feedback types +const QuicTag kLOSS = TAG('L', 'O', 'S', 'S'); // Loss detection algorithms const QuicTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle connection state // lifetime const QuicTag kKATO = TAG('K', 'A', 'T', 'O'); // Keepalive timeout diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc index 121268d..8a951ed 100644 --- a/net/quic/quic_config.cc +++ b/net/quic/quic_config.cc @@ -296,6 +296,7 @@ QuicErrorCode QuicFixedUint32::ProcessServerHello( QuicConfig::QuicConfig() : congestion_control_(kCGST, PRESENCE_REQUIRED), + loss_detection_(kLOSS, PRESENCE_OPTIONAL), idle_connection_state_lifetime_seconds_(kICSL, PRESENCE_REQUIRED), keepalive_timeout_seconds_(kKATO, PRESENCE_OPTIONAL), max_streams_per_connection_(kMSPC, PRESENCE_REQUIRED), @@ -309,6 +310,10 @@ QuicConfig::QuicConfig() // All optional non-zero parameters should be initialized here. server_initial_congestion_window_.set(kMaxInitialWindow, kDefaultInitialWindow); + QuicTagVector loss_detection; + loss_detection.push_back(kNACK); + loss_detection.push_back(kTIME); + loss_detection_.set(loss_detection, kNACK); } QuicConfig::~QuicConfig() {} @@ -323,6 +328,16 @@ QuicTag QuicConfig::congestion_control() const { return congestion_control_.GetTag(); } +void QuicConfig::set_loss_detection( + const QuicTagVector& loss_detection, + QuicTag default_loss_detection) { + loss_detection_.set(loss_detection, default_loss_detection); +} + +QuicTag QuicConfig::loss_detection() const { + return loss_detection_.GetTag(); +} + void QuicConfig::set_idle_connection_state_lifetime( QuicTime::Delta max_idle_connection_state_lifetime, QuicTime::Delta default_idle_conection_state_lifetime) { @@ -391,6 +406,7 @@ bool QuicConfig::negotiated() { // of them in negotiated, ToHandshakeMessage, ProcessClientHello, and // ProcessServerHello. return congestion_control_.negotiated() && + loss_detection_.negotiated() && idle_connection_state_lifetime_seconds_.negotiated() && keepalive_timeout_seconds_.negotiated() && max_streams_per_connection_.negotiated() && @@ -415,6 +431,9 @@ void QuicConfig::SetDefaults() { kDefaultMaxTimeForCryptoHandshakeSecs); server_initial_congestion_window_.set(kDefaultInitialWindow, kDefaultInitialWindow); + QuicTagVector loss_detection; + loss_detection.push_back(kNACK); + loss_detection_.set(loss_detection, kNACK); } void QuicConfig::EnablePacing(bool enable_pacing) { @@ -434,7 +453,7 @@ void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const { server_initial_congestion_window_.ToHandshakeMessage(out); // TODO(ianswett): Don't transmit parameters which are optional and not set. initial_round_trip_time_us_.ToHandshakeMessage(out); - + loss_detection_.ToHandshakeMessage(out); // Don't add peer_initial_flow_control_window_bytes here, it is not a // negotiated value. } @@ -472,6 +491,9 @@ QuicErrorCode QuicConfig::ProcessClientHello( error = peer_initial_flow_control_window_bytes_.ProcessClientHello( client_hello, error_details); } + if (error == QUIC_NO_ERROR) { + error = loss_detection_.ProcessClientHello(client_hello, error_details); + } return error; } @@ -508,6 +530,9 @@ QuicErrorCode QuicConfig::ProcessServerHello( error = peer_initial_flow_control_window_bytes_.ProcessServerHello( server_hello, error_details); } + if (error == QUIC_NO_ERROR) { + error = loss_detection_.ProcessServerHello(server_hello, error_details); + } return error; } diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h index 05070d4..eb0291d 100644 --- a/net/quic/quic_config.h +++ b/net/quic/quic_config.h @@ -197,6 +197,11 @@ class NET_EXPORT_PRIVATE QuicConfig { QuicTag congestion_control() const; + void set_loss_detection(const QuicTagVector& loss_detection, + QuicTag default_loss_detection); + + QuicTag loss_detection() const; + void set_idle_connection_state_lifetime( QuicTime::Delta max_idle_connection_state_lifetime, QuicTime::Delta default_idle_conection_state_lifetime); @@ -256,6 +261,8 @@ class NET_EXPORT_PRIVATE QuicConfig { private: // Congestion control feedback type. QuicNegotiableTag congestion_control_; + // Loss detection feedback type. + QuicNegotiableTag loss_detection_; // Idle connection state lifetime QuicNegotiableUint32 idle_connection_state_lifetime_seconds_; // Keepalive timeout, or 0 to turn off keepalive probes diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc index bc91c3e..2c3f98b 100644 --- a/net/quic/quic_config_test.cc +++ b/net/quic/quic_config_test.cc @@ -84,6 +84,9 @@ TEST_F(QuicConfigTest, ProcessClientHello) { client_config.set_initial_round_trip_time_us( 10 * base::Time::kMicrosecondsPerMillisecond, 10 * base::Time::kMicrosecondsPerMillisecond); + QuicTagVector loss_detection; + loss_detection.push_back(kNACK); + client_config.set_loss_detection(loss_detection, kNACK); CryptoHandshakeMessage msg; client_config.ToHandshakeMessage(&msg); string error_details; @@ -98,6 +101,7 @@ TEST_F(QuicConfigTest, ProcessClientHello) { EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.keepalive_timeout()); EXPECT_EQ(10 * base::Time::kMicrosecondsPerMillisecond, config_.initial_round_trip_time_us()); + EXPECT_EQ(kNACK, config_.loss_detection()); } TEST_F(QuicConfigTest, ProcessServerHello) { @@ -116,6 +120,9 @@ TEST_F(QuicConfigTest, ProcessServerHello) { server_config.set_initial_round_trip_time_us( 10 * base::Time::kMicrosecondsPerMillisecond, 10 * base::Time::kMicrosecondsPerMillisecond); + QuicTagVector loss_detection; + loss_detection.push_back(kNACK); + server_config.set_loss_detection(loss_detection, kNACK); CryptoHandshakeMessage msg; server_config.ToHandshakeMessage(&msg); string error_details; @@ -132,6 +139,7 @@ TEST_F(QuicConfigTest, ProcessServerHello) { EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.keepalive_timeout()); EXPECT_EQ(10 * base::Time::kMicrosecondsPerMillisecond, config_.initial_round_trip_time_us()); + EXPECT_EQ(kNACK, config_.loss_detection()); } TEST_F(QuicConfigTest, MissingOptionalValuesInCHLO) { diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index ac586d4..95771e2 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -181,7 +181,8 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id, largest_seen_packet_with_ack_(0), largest_seen_packet_with_stop_waiting_(0), pending_version_negotiation_packet_(false), - received_packet_manager_(kTCP), + received_packet_manager_( + FLAGS_quic_congestion_control_inter_arrival ? kInterArrival : kTCP), ack_queued_(false), stop_waiting_count_(0), ack_alarm_(helper->CreateAlarm(new AckAlarm(this))), @@ -199,7 +200,10 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id, time_of_last_received_packet_(clock_->ApproximateNow()), time_of_last_sent_new_packet_(clock_->ApproximateNow()), sequence_number_of_last_sent_packet_(0), - sent_packet_manager_(is_server, clock_, &stats_, kTCP), + sent_packet_manager_( + is_server, clock_, &stats_, + FLAGS_quic_congestion_control_inter_arrival ? kInterArrival : kTCP, + FLAGS_quic_use_time_loss_detection ? kTime : kNack), version_negotiation_state_(START_NEGOTIATION), is_server_(is_server), connected_(true), diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index 6e51d70..6b2bc1f 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -2069,7 +2069,7 @@ TEST_P(QuicConnectionTest, DontLatchUnackedPacket) { EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1); SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); // Packet 1; - // From now on, we send acks, so the send algorithm won't save them. + // From now on, we send acks, so the send algorithm won't mark them pending. ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .WillByDefault(Return(false)); SendAckPacketToPeer(); // Packet 2 @@ -2078,18 +2078,29 @@ TEST_P(QuicConnectionTest, DontLatchUnackedPacket) { QuicAckFrame frame = InitAckFrame(1, 0); ProcessAckPacket(&frame); - // Verify that our internal state has least-unacked as 3. + // Verify that our internal state has least-unacked as 2, because we're still + // waiting for a potential ack for 2. + EXPECT_EQ(2u, outgoing_ack()->sent_info.least_unacked); + + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + frame = InitAckFrame(2, 0); + ProcessAckPacket(&frame); EXPECT_EQ(3u, outgoing_ack()->sent_info.least_unacked); // When we send an ack, we make sure our least-unacked makes sense. In this // case since we're not waiting on an ack for 2 and all packets are acked, we // set it to 3. SendAckPacketToPeer(); // Packet 3 - // Since this was an ack packet, we set least_unacked to 4. - EXPECT_EQ(4u, outgoing_ack()->sent_info.least_unacked); + // Least_unacked remains at 3 until another ack is received. + EXPECT_EQ(3u, outgoing_ack()->sent_info.least_unacked); // Check that the outgoing ack had its sequence number as least_unacked. EXPECT_EQ(3u, least_unacked()); + // Ack the ack, which updates the rtt and raises the least unacked. + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + frame = InitAckFrame(3, 0); + ProcessAckPacket(&frame); + ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) .WillByDefault(Return(true)); SendStreamDataToPeer(1, "bar", 3, false, NULL); // Packet 4 @@ -2098,6 +2109,22 @@ TEST_P(QuicConnectionTest, DontLatchUnackedPacket) { .WillByDefault(Return(false)); SendAckPacketToPeer(); // Packet 5 EXPECT_EQ(4u, least_unacked()); + + // Send two data packets at the end, and ensure if the last one is acked, + // the least unacked is raised above the ack packets. + ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) + .WillByDefault(Return(true)); + SendStreamDataToPeer(1, "bar", 6, false, NULL); // Packet 6 + SendStreamDataToPeer(1, "bar", 9, false, NULL); // Packet 7 + + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(2); + frame = InitAckFrame(7, 0); + NackPacket(5, &frame); + NackPacket(6, &frame); + ProcessAckPacket(&frame); + + EXPECT_EQ(6u, outgoing_ack()->sent_info.least_unacked); } TEST_P(QuicConnectionTest, ReviveMissingPacketAfterFecPacket) { diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc index e7a8e44..ab61720 100644 --- a/net/quic/quic_flags.cc +++ b/net/quic/quic_flags.cc @@ -24,3 +24,6 @@ bool FLAGS_enable_quic_pacing = true; bool FLAGS_enable_quic_stream_flow_control = true; bool FLAGS_quic_allow_oversized_packets_for_test = false; +bool FLAGS_quic_congestion_control_inter_arrival = false; +// When true, the use time based loss detection instead of nack. +bool FLAGS_quic_use_time_loss_detection = false; diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h index cb3bb38..25993ab 100644 --- a/net/quic/quic_flags.h +++ b/net/quic/quic_flags.h @@ -11,5 +11,7 @@ NET_EXPORT_PRIVATE extern bool FLAGS_track_retransmission_history; NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_pacing; NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_stream_flow_control; NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_oversized_packets_for_test; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_congestion_control_inter_arrival; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_time_loss_detection; #endif // NET_QUIC_QUIC_FLAGS_H_ diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index 3465b39..26bdc02 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc @@ -167,6 +167,7 @@ QuicFramer::QuicFramer(const QuicVersionVector& supported_versions, supported_versions_(supported_versions), alternative_decrypter_latch_(false), is_server_(is_server), + validate_flags_(true), creation_time_(creation_time) { DCHECK(!supported_versions.empty()); quic_version_ = supported_versions_[0]; @@ -885,7 +886,8 @@ bool QuicFramer::ProcessPublicHeader( public_header->version_flag = (public_flags & PACKET_PUBLIC_FLAGS_VERSION) != 0; - if (!public_header->version_flag && public_flags > PACKET_PUBLIC_FLAGS_MAX) { + if (validate_flags_ && + !public_header->version_flag && public_flags > PACKET_PUBLIC_FLAGS_MAX) { set_detailed_error("Illegal public flags value."); return false; } diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h index b29de2c..d757954 100644 --- a/net/quic/quic_framer.h +++ b/net/quic/quic_framer.h @@ -365,6 +365,8 @@ class NET_EXPORT_PRIVATE QuicFramer { quic_version_ = versions[0]; } + void set_validate_flags(bool value) { validate_flags_ = value; } + private: friend class test::QuicFramerPeer; @@ -512,6 +514,8 @@ class NET_EXPORT_PRIVATE QuicFramer { // Tracks if the framer is being used by the entity that received the // connection or the entity that initiated it. bool is_server_; + // If false, skip validation that the public flags are set to legal values. + bool validate_flags_; // The time this frames was created. Time written to the wire will be // written as a delta from this value. QuicTime creation_time_; diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index 43c2984..96fc39b 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc @@ -1090,8 +1090,8 @@ TEST_P(QuicFramerTest, PacketHeaderWith1ByteSequenceNumber) { TEST_P(QuicFramerTest, InvalidPublicFlag) { unsigned char packet[] = { - // public flags, unknown flag at bit 6 - 0x40, + // public flags: all flags set but the public reset flag and version flag. + 0xFC, // connection_id 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, @@ -1109,6 +1109,11 @@ TEST_P(QuicFramerTest, InvalidPublicFlag) { arraysize(packet), "Illegal public flags value.", QUIC_INVALID_PACKET_HEADER); + + // Now turn off validation. + framer_.set_validate_flags(false); + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); }; TEST_P(QuicFramerTest, InvalidPublicFlagWithMatchingVersions) { diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index 7dfb598..2609de2 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -94,9 +94,9 @@ const bool kIncludeVersion = true; const size_t kStartOfHashData = 0; // Limit on the delta between stream IDs. -const QuicStreamId kMaxStreamIdDelta = 100; +const QuicStreamId kMaxStreamIdDelta = 200; // Limit on the delta between header IDs. -const QuicHeaderId kMaxHeaderIdDelta = 100; +const QuicHeaderId kMaxHeaderIdDelta = 200; // Reserved ID for the crypto stream. const QuicStreamId kCryptoStreamId = 1; @@ -677,6 +677,11 @@ enum CongestionFeedbackType { kFixRate, // Provided for testing. }; +enum LossDetectionType { + kNack, // Used to mimic TCP's loss detection. + kTime, // Time based loss detection. +}; + struct NET_EXPORT_PRIVATE CongestionFeedbackMessageTCP { CongestionFeedbackMessageTCP(); diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index 56e5153..3509ae7 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc @@ -54,14 +54,15 @@ bool HasCryptoHandshake( QuicSentPacketManager::QuicSentPacketManager(bool is_server, const QuicClock* clock, QuicConnectionStats* stats, - CongestionFeedbackType type) + CongestionFeedbackType type, + LossDetectionType loss_type) : unacked_packets_(), is_server_(is_server), clock_(clock), stats_(stats), send_algorithm_( SendAlgorithmInterface::Create(clock, &rtt_stats_, type, stats)), - loss_algorithm_(LossDetectionInterface::Create()), + loss_algorithm_(LossDetectionInterface::Create(loss_type)), largest_observed_(0), consecutive_rto_count_(0), consecutive_tlp_count_(0), @@ -83,6 +84,9 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { if (config.congestion_control() == kPACE) { MaybeEnablePacing(); } + if (config.loss_detection() == kTIME) { + loss_algorithm_.reset(LossDetectionInterface::Create(kTime)); + } send_algorithm_->SetFromConfig(config, is_server_); } @@ -151,12 +155,18 @@ void QuicSentPacketManager::HandleAckForSentPackets( while (it != unacked_packets_.end()) { QuicPacketSequenceNumber sequence_number = it->first; if (sequence_number > received_info.largest_observed) { - // These are very new sequence_numbers. + // These packets are still in flight. break; } if (IsAwaitingPacket(received_info, sequence_number)) { - ++it; + // Remove any packets not being tracked by the send algorithm, allowing + // the high water mark to be raised if necessary. + if (QuicUnackedPacketMap::IsSentAndNotPending(it->second)) { + it = MarkPacketHandled(sequence_number, NOT_RECEIVED_BY_PEER); + } else { + ++it; + } continue; } @@ -370,17 +380,17 @@ bool QuicSentPacketManager::OnPacketSent( return false; } - // Only track packets the send algorithm wants us to track. + // Only track packets as pending that the send algorithm wants us to track. if (!send_algorithm_->OnPacketSent(sent_time, sequence_number, bytes, has_retransmittable_data)) { - unacked_packets_.RemovePacket(sequence_number); + unacked_packets_.SetSent(sequence_number, sent_time, bytes, false); // Do not reset the retransmission timer, since the packet isn't tracked. return false; } const bool set_retransmission_timer = !unacked_packets_.HasPendingPackets(); - unacked_packets_.SetPending(sequence_number, sent_time, bytes); + unacked_packets_.SetSent(sequence_number, sent_time, bytes, true); // Reset the retransmission timer anytime a packet is sent in tail loss probe // mode or before the crypto handshake has completed. diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h index 512fa48..0f7266c 100644 --- a/net/quic/quic_sent_packet_manager.h +++ b/net/quic/quic_sent_packet_manager.h @@ -62,7 +62,8 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager { QuicSentPacketManager(bool is_server, const QuicClock* clock, QuicConnectionStats* stats, - CongestionFeedbackType congestion_type); + CongestionFeedbackType congestion_type, + LossDetectionType loss_type); virtual ~QuicSentPacketManager(); virtual void SetFromConfig(const QuicConfig& config); diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc index 192fd38..c6a1e29 100644 --- a/net/quic/quic_sent_packet_manager_test.cc +++ b/net/quic/quic_sent_packet_manager_test.cc @@ -22,7 +22,7 @@ namespace { class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> { protected: QuicSentPacketManagerTest() - : manager_(true, &clock_, &stats_, kFixRate), + : manager_(true, &clock_, &stats_, kFixRate, kNack), send_algorithm_(new StrictMock<MockSendAlgorithm>) { QuicSentPacketManagerPeer::SetSendAlgorithm(&manager_, send_algorithm_); // Disable tail loss probes for most tests. @@ -153,6 +153,16 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> { NO_RETRANSMITTABLE_DATA); } + void SendAckPacket(QuicPacketSequenceNumber sequence_number) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, sequence_number, _, _)) + .Times(1).WillOnce(Return(false)); + SerializedPacket packet(CreatePacket(sequence_number, false)); + manager_.OnSerializedPacket(packet); + manager_.OnPacketSent(sequence_number, clock_.Now(), + packet.packet->length(), NOT_RETRANSMISSION, + NO_RETRANSMITTABLE_DATA); + } + // Based on QuicConnection's WritePendingRetransmissions. void RetransmitNextPacket( QuicPacketSequenceNumber retransmission_sequence_number) { @@ -642,16 +652,14 @@ TEST_F(QuicSentPacketManagerTest, FackRetransmit17Packets) { TEST_F(QuicSentPacketManagerTest, FackRetransmit14PacketsAlternateAcks) { const size_t kNumSentPackets = 30; - // Transmit 15 packets of data and 15 ack packets. The send algorithm will - // inform the congestion manager not to save the acks by returning false. + // Transmit 15 packets of data and 15 ack packets. The send algorithm returns + // false to inform the sent packet manager not to count acks as pending. for (QuicPacketSequenceNumber i = 1; i <= kNumSentPackets; ++i) { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _)) - .Times(1).WillOnce(Return(i % 2 == 0 ? false : true)); - SerializedPacket packet(CreatePacket(i, i % 2 == 1)); - manager_.OnSerializedPacket(packet); - manager_.OnPacketSent( - i, clock_.Now(), 1000, NOT_RETRANSMISSION, - i % 2 == 0 ? NO_RETRANSMITTABLE_DATA : HAS_RETRANSMITTABLE_DATA); + if (i % 2 == 0) { + SendAckPacket(i); + } else { + SendDataPacket(i); + } } // Nack the first 29 packets 3 times. @@ -662,8 +670,7 @@ TEST_F(QuicSentPacketManagerTest, FackRetransmit14PacketsAlternateAcks) { for (size_t i = 1; i < kNumSentPackets; ++i) { received_info.missing_packets.insert(i); } - // We never actually get an ack call, since the kNumSentPackets packet was - // not saved. + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(14); EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(14); manager_.OnIncomingAck(received_info, clock_.Now()); @@ -683,6 +690,29 @@ TEST_F(QuicSentPacketManagerTest, FackRetransmit14PacketsAlternateAcks) { } } +TEST_F(QuicSentPacketManagerTest, AckAckAndUpdateRtt) { + SendDataPacket(1); + SendAckPacket(2); + + // Now ack the ack and expect an RTT update. + ReceivedPacketInfo received_info; + received_info.largest_observed = 2; + received_info.delta_time_largest_observed = + QuicTime::Delta::FromMilliseconds(5); + + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + EXPECT_CALL(*send_algorithm_, OnPacketAcked(1, _)).Times(1); + manager_.OnIncomingAck(received_info, clock_.Now()); + + SendAckPacket(3); + + // Now ack the ack and expect only an RTT update. + received_info.largest_observed = 3; + + EXPECT_CALL(*send_algorithm_, UpdateRtt(_)); + manager_.OnIncomingAck(received_info, clock_.Now()); +} + TEST_F(QuicSentPacketManagerTest, Rtt) { QuicPacketSequenceNumber sequence_number = 1; QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(15); @@ -1177,6 +1207,20 @@ TEST_F(QuicSentPacketManagerTest, GetLossDelay) { manager_.OnRetransmissionTimeout(); } +TEST_F(QuicSentPacketManagerTest, NegotiateTimeLossDetection) { + QuicConfig config; + QuicTagVector loss_detection; + loss_detection.push_back(kTIME); + config.set_loss_detection(loss_detection, kTIME); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + manager_.SetFromConfig(config); + + EXPECT_EQ(kTime, + QuicSentPacketManagerPeer::GetLossAlgorithm( + &manager_)->GetLossDetectionType()); +} + + } // namespace } // namespace test } // namespace net diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index 055eb5b..3a3207e 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc @@ -484,9 +484,16 @@ QuicDataStream* QuicSession::GetIncomingDataStream(QuicStreamId stream_id) { implicitly_created_streams_.erase(stream_id); if (stream_id > largest_peer_created_stream_id_) { - // TODO(rch) add unit test for this if (stream_id - largest_peer_created_stream_id_ > kMaxStreamIdDelta) { - connection()->SendConnectionClose(QUIC_INVALID_STREAM_ID); + // We may already have sent a connection close due to multiple reset + // streams in the same packet. + if (connection()->connected()) { + LOG(ERROR) << "Trying to get stream: " << stream_id + << ", largest peer created stream: " + << largest_peer_created_stream_id_ + << ", max delta: " << kMaxStreamIdDelta; + connection()->SendConnectionClose(QUIC_INVALID_STREAM_ID); + } return NULL; } if (largest_peer_created_stream_id_ == 0) { @@ -564,19 +571,6 @@ void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) { write_blocked_streams_.PushBack(id, priority); } -void QuicSession::MarkFlowControlBlocked(QuicStreamId id, - QuicPriority priority) { - ReliableQuicStream* stream = GetStream(id); - if (stream == NULL) { - LOG(DFATAL) << "Trying to mark nonexistent stream " << id - << " flow control blocked."; - return; - } - - // Send a BLOCKED frame to peer. - connection()->SendBlocked(id); -} - bool QuicSession::HasDataToWrite() const { return write_blocked_streams_.HasWriteBlockedStreams() || connection_->HasQueuedData(); diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index 06b56e2..76fb274 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h @@ -179,7 +179,6 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { virtual size_t GetNumOpenStreams() const; void MarkWriteBlocked(QuicStreamId id, QuicPriority priority); - void MarkFlowControlBlocked(QuicStreamId id, QuicPriority priority); // Returns true if the session has data to be sent, either queued in the // connection, or in a write-blocked stream. diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc index 762be71..8780afb 100644 --- a/net/quic/quic_session_test.cc +++ b/net/quic/quic_session_test.cc @@ -282,7 +282,7 @@ TEST_P(QuicSessionTest, StreamIdTooLarge) { QuicStreamId stream_id = 5; session_.GetIncomingDataStream(stream_id); EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID)); - session_.GetIncomingDataStream(stream_id + 102); + session_.GetIncomingDataStream(stream_id + kMaxStreamIdDelta + 2); } TEST_P(QuicSessionTest, DecompressionError) { @@ -333,14 +333,6 @@ TEST_P(QuicSessionTest, OnCanWrite) { TestStream* stream4 = session_.CreateOutgoingDataStream(); TestStream* stream6 = session_.CreateOutgoingDataStream(); - // Streams should not be flow control blocked _and_ write blocked. - // WINDOW_UPDATE frames ensure that streams are not flow control blocked. - if (version() >= QUIC_VERSION_17) { - stream2->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream2->id(), 1234)); - stream4->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream4->id(), 1234)); - stream6->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream6->id(), 1234)); - } - session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority); session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority); session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); @@ -367,14 +359,6 @@ TEST_P(QuicSessionTest, OnCanWriteCongestionControlBlocks) { TestStream* stream4 = session_.CreateOutgoingDataStream(); TestStream* stream6 = session_.CreateOutgoingDataStream(); - // Streams should not be flow control blocked _and_ write blocked. - // WINDOW_UPDATE frames ensure that streams are not flow control blocked. - if (version() >= QUIC_VERSION_17) { - stream2->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream2->id(), 1234)); - stream4->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream4->id(), 1234)); - stream6->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream6->id(), 1234)); - } - session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority); session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority); session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); @@ -413,19 +397,11 @@ TEST_P(QuicSessionTest, BufferedHandshake) { // Test that blocking other streams does not change our status. TestStream* stream2 = session_.CreateOutgoingDataStream(); - // Ensure stream is not flow control blocked. - if (version() >= QUIC_VERSION_17) { - stream2->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream2->id(), 1234)); - } StreamBlocker stream2_blocker(&session_, stream2->id()); stream2_blocker.MarkWriteBlocked(); EXPECT_FALSE(session_.HasPendingHandshake()); TestStream* stream3 = session_.CreateOutgoingDataStream(); - // Ensure stream is not flow control blocked. - if (version() >= QUIC_VERSION_17) { - stream3->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream3->id(), 1234)); - } StreamBlocker stream3_blocker(&session_, stream3->id()); stream3_blocker.MarkWriteBlocked(); EXPECT_FALSE(session_.HasPendingHandshake()); @@ -435,10 +411,6 @@ TEST_P(QuicSessionTest, BufferedHandshake) { EXPECT_TRUE(session_.HasPendingHandshake()); TestStream* stream4 = session_.CreateOutgoingDataStream(); - // Ensure stream is not flow control blocked. - if (version() >= QUIC_VERSION_17) { - stream4->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream4->id(), 1234)); - } StreamBlocker stream4_blocker(&session_, stream4->id()); stream4_blocker.MarkWriteBlocked(); EXPECT_TRUE(session_.HasPendingHandshake()); @@ -473,14 +445,6 @@ TEST_P(QuicSessionTest, OnCanWriteWithClosedStream) { TestStream* stream4 = session_.CreateOutgoingDataStream(); TestStream* stream6 = session_.CreateOutgoingDataStream(); - // Streams should not be flow control blocked _and_ write blocked. - // WINDOW_UPDATE frames ensure that streams are not flow control blocked. - if (version() >= QUIC_VERSION_17) { - stream2->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream2->id(), 1234)); - stream4->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream4->id(), 1234)); - stream6->OnWindowUpdateFrame(QuicWindowUpdateFrame(stream6->id(), 1234)); - } - session_.MarkWriteBlocked(stream2->id(), kSomeMiddlePriority); session_.MarkWriteBlocked(stream6->id(), kSomeMiddlePriority); session_.MarkWriteBlocked(stream4->id(), kSomeMiddlePriority); @@ -535,6 +499,34 @@ TEST_P(QuicSessionTest, RstStreamBeforeHeadersDecompressed) { EXPECT_EQ(0u, session_.GetNumOpenStreams()); } +TEST_P(QuicSessionTest, MultipleRstStreamsCauseSingleConnectionClose) { + // If multiple invalid reset stream frames arrive in a single packet, this + // should trigger a connection close. However there is no need to send + // multiple connection close frames. + + // Create valid stream. + const QuicStreamId kStreamId = 5; + QuicStreamFrame data1(kStreamId, false, 0, MakeIOVector("HT")); + vector<QuicStreamFrame> frames; + frames.push_back(data1); + EXPECT_TRUE(session_.OnStreamFrames(frames)); + EXPECT_EQ(1u, session_.GetNumOpenStreams()); + + // Process first invalid stream reset, resulting in the connection being + // closed. + EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID)) + .Times(1); + QuicStreamId kLargeInvalidStreamId = 99999999; + QuicRstStreamFrame rst1(kLargeInvalidStreamId, QUIC_STREAM_NO_ERROR, 0); + session_.OnRstStream(rst1); + QuicConnectionPeer::CloseConnection(connection_); + + // Processing of second invalid stream reset should not result in the + // connection being closed for a second time. + QuicRstStreamFrame rst2(kLargeInvalidStreamId, QUIC_STREAM_NO_ERROR, 0); + session_.OnRstStream(rst2); +} + TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedStream) { // Test that if a stream is flow control blocked, then on receipt of the SHLO // containing a suitable send window offset, the stream becomes unblocked. diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc index e7e5e16..46cf2b8 100644 --- a/net/quic/quic_unacked_packet_map.cc +++ b/net/quic/quic_unacked_packet_map.cc @@ -198,6 +198,14 @@ void QuicUnackedPacketMap::NeuterPacket( } } +// static +bool QuicUnackedPacketMap::IsSentAndNotPending( + const TransmissionInfo& transmission_info) { + return !transmission_info.pending && + transmission_info.sent_time != QuicTime::Zero() && + transmission_info.bytes_sent == 0; +} + bool QuicUnackedPacketMap::IsUnacked( QuicPacketSequenceNumber sequence_number) const { return ContainsKey(unacked_packets_, sequence_number); @@ -333,9 +341,10 @@ SequenceNumberSet QuicUnackedPacketMap::GetUnackedPackets() const { return unacked_packets; } -void QuicUnackedPacketMap::SetPending(QuicPacketSequenceNumber sequence_number, - QuicTime sent_time, - QuicByteCount bytes_sent) { +void QuicUnackedPacketMap::SetSent(QuicPacketSequenceNumber sequence_number, + QuicTime sent_time, + QuicByteCount bytes_sent, + bool set_pending) { DCHECK_LT(0u, sequence_number); UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number); if (it == unacked_packets_.end()) { @@ -346,10 +355,12 @@ void QuicUnackedPacketMap::SetPending(QuicPacketSequenceNumber sequence_number, DCHECK(!it->second.pending); largest_sent_packet_ = max(sequence_number, largest_sent_packet_); - bytes_in_flight_ += bytes_sent; it->second.sent_time = sent_time; - it->second.bytes_sent = bytes_sent; - it->second.pending = true; + if (set_pending) { + bytes_in_flight_ += bytes_sent; + it->second.bytes_sent = bytes_sent; + it->second.pending = true; + } } } // namespace net diff --git a/net/quic/quic_unacked_packet_map.h b/net/quic/quic_unacked_packet_map.h index d739b91..a687bb6 100644 --- a/net/quic/quic_unacked_packet_map.h +++ b/net/quic/quic_unacked_packet_map.h @@ -102,10 +102,14 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap { // Test only. SequenceNumberSet GetUnackedPackets() const; - // Sets a packet pending, with the sent time |sent_time|. - void SetPending(QuicPacketSequenceNumber sequence_number, - QuicTime sent_time, - QuicByteCount bytes_sent); + // Sets a packet as sent with the sent time |sent_time|. Marks the packet + // as pending and tracks the |bytes_sent| if |set_pending| is true. + // Packets marked as pending are expected to be marked as missing when they + // don't arrive, indicating the need for retransmission. + void SetSent(QuicPacketSequenceNumber sequence_number, + QuicTime sent_time, + QuicByteCount bytes_sent, + bool set_pending); // Clears up to |num_to_clear| previous transmissions in order to make room // in the ack frame for new acks. @@ -151,6 +155,9 @@ class NET_EXPORT_PRIVATE QuicUnackedPacketMap { // frames, and sets all_transmissions to only include itself. void NeuterPacket(QuicPacketSequenceNumber sequence_number); + // Returns true if the packet has been marked as sent by SetSent. + static bool IsSentAndNotPending(const TransmissionInfo& transmission_info); + private: QuicPacketSequenceNumber largest_sent_packet_; diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index c03e5f3..bc8d0f8 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc @@ -351,7 +351,7 @@ QuicConsumedData ReliableQuicStream::WritevData( if (IsFlowControlEnabled()) { if (send_window == 0 && !fin_with_zero_data) { // Quick return if we can't send anything. - session_->MarkFlowControlBlocked(id(), EffectivePriority()); + session()->connection()->SendBlocked(id()); return QuicConsumedData(0, false); } @@ -383,7 +383,7 @@ QuicConsumedData ReliableQuicStream::WritevData( << flow_control_send_limit_; // The entire send_window has been consumed, we are now flow control // blocked. - session_->MarkFlowControlBlocked(id(), EffectivePriority()); + session()->connection()->SendBlocked(id()); } if (fin && consumed_data.fin_consumed) { fin_sent_ = true; @@ -479,12 +479,7 @@ void ReliableQuicStream::UpdateFlowControlSendLimit(QuicStreamOffset offset) { } bool ReliableQuicStream::IsFlowControlBlocked() const { - if (IsFlowControlEnabled()) { - return stream_bytes_written_ == flow_control_send_limit_ || - SendWindowSize() == 0; - } else { - return false; - } + return IsFlowControlEnabled() && SendWindowSize() == 0; } uint64 ReliableQuicStream::SendWindowSize() const { diff --git a/net/quic/test_tools/quic_sent_packet_manager_peer.cc b/net/quic/test_tools/quic_sent_packet_manager_peer.cc index f1643d7..9984243 100644 --- a/net/quic/test_tools/quic_sent_packet_manager_peer.cc +++ b/net/quic/test_tools/quic_sent_packet_manager_peer.cc @@ -27,6 +27,12 @@ void QuicSentPacketManagerPeer::SetSendAlgorithm( } // static +const LossDetectionInterface* QuicSentPacketManagerPeer::GetLossAlgorithm( + QuicSentPacketManager* sent_packet_manager) { + return sent_packet_manager->loss_algorithm_.get(); +} + +// static void QuicSentPacketManagerPeer::SetLossAlgorithm( QuicSentPacketManager* sent_packet_manager, LossDetectionInterface* loss_detector) { diff --git a/net/quic/test_tools/quic_sent_packet_manager_peer.h b/net/quic/test_tools/quic_sent_packet_manager_peer.h index ff86189..c4db12a 100644 --- a/net/quic/test_tools/quic_sent_packet_manager_peer.h +++ b/net/quic/test_tools/quic_sent_packet_manager_peer.h @@ -22,6 +22,9 @@ class QuicSentPacketManagerPeer { static void SetSendAlgorithm(QuicSentPacketManager* sent_packet_manager, SendAlgorithmInterface* send_algorithm); + static const LossDetectionInterface* GetLossAlgorithm( + QuicSentPacketManager* sent_packet_manager); + static void SetLossAlgorithm(QuicSentPacketManager* sent_packet_manager, LossDetectionInterface* loss_detector); diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index ba106f7..1214205 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h @@ -482,6 +482,7 @@ class MockLossAlgorithm : public LossDetectionInterface { MockLossAlgorithm(); virtual ~MockLossAlgorithm(); + MOCK_CONST_METHOD0(GetLossDetectionType, LossDetectionType()); MOCK_METHOD4(DetectLostPackets, SequenceNumberSet(const QuicUnackedPacketMap& unacked_packets, const QuicTime& time, |