summaryrefslogtreecommitdiffstats
path: root/net/quic
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-31 23:17:14 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-31 23:17:14 +0000
commitc5cc9bd03a52d4c96d5e00efe4633ae965c4dcfd (patch)
tree8910a2ed2f88a1751e8ea7823b7b2bc3c64da124 /net/quic
parent45a4f1ff5da3196aa03cfbe3862f57a1e1eb029c (diff)
downloadchromium_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')
-rw-r--r--net/quic/congestion_control/loss_detection_interface.cc13
-rw-r--r--net/quic/congestion_control/loss_detection_interface.h4
-rw-r--r--net/quic/congestion_control/tcp_loss_algorithm.cc4
-rw-r--r--net/quic/congestion_control/tcp_loss_algorithm.h2
-rw-r--r--net/quic/congestion_control/tcp_loss_algorithm_test.cc2
-rw-r--r--net/quic/congestion_control/time_loss_algorithm.cc4
-rw-r--r--net/quic/congestion_control/time_loss_algorithm.h2
-rw-r--r--net/quic/congestion_control/time_loss_algorithm_test.cc2
-rw-r--r--net/quic/crypto/crypto_protocol.h5
-rw-r--r--net/quic/quic_config.cc27
-rw-r--r--net/quic/quic_config.h7
-rw-r--r--net/quic/quic_config_test.cc8
-rw-r--r--net/quic/quic_connection.cc8
-rw-r--r--net/quic/quic_connection_test.cc35
-rw-r--r--net/quic/quic_flags.cc3
-rw-r--r--net/quic/quic_flags.h2
-rw-r--r--net/quic/quic_framer.cc4
-rw-r--r--net/quic/quic_framer.h4
-rw-r--r--net/quic/quic_framer_test.cc9
-rw-r--r--net/quic/quic_protocol.h9
-rw-r--r--net/quic/quic_sent_packet_manager.cc24
-rw-r--r--net/quic/quic_sent_packet_manager.h3
-rw-r--r--net/quic/quic_sent_packet_manager_test.cc68
-rw-r--r--net/quic/quic_session.cc24
-rw-r--r--net/quic/quic_session.h1
-rw-r--r--net/quic/quic_session_test.cc66
-rw-r--r--net/quic/quic_unacked_packet_map.cc23
-rw-r--r--net/quic/quic_unacked_packet_map.h15
-rw-r--r--net/quic/reliable_quic_stream.cc11
-rw-r--r--net/quic/test_tools/quic_sent_packet_manager_peer.cc6
-rw-r--r--net/quic/test_tools/quic_sent_packet_manager_peer.h3
-rw-r--r--net/quic/test_tools/quic_test_utils.h1
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,