summaryrefslogtreecommitdiffstats
path: root/net/quic
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-27 00:09:03 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-27 00:09:03 +0000
commit93dd91ff7c039a6db4798f40b212e1aaa380befb (patch)
treed8577ffd679249784cedf8cd4b3d3511cdb538fe /net/quic
parent91256e4f440f2588594359fe5e3ac78636448f1f (diff)
downloadchromium_src-93dd91ff7c039a6db4798f40b212e1aaa380befb.zip
chromium_src-93dd91ff7c039a6db4798f40b212e1aaa380befb.tar.gz
chromium_src-93dd91ff7c039a6db4798f40b212e1aaa380befb.tar.bz2
Land Recent QUIC Changes.
These LOG(INFO)s claimed 8-9% of time under a load test. Reduce logspam in QuicUnackedPacketMap. Merge internal change: 61895796 https://codereview.chromium.org/179773007/ QUIC WINDOW_UPDATE and BLOCKED frames instigate ACKs. Merge internal change: 61894847 https://codereview.chromium.org/180013004/ Avoiding quic double-close bugs by detecting it at the connection. Merge internal change: 61890466 https://codereview.chromium.org/180793003/ BLOCKED frames not being cleared. These are not yet used. (minor) Clear last BLOCKED frames in QuicConnection Merge internal change: 61875848 https://codereview.chromium.org/180793002/ QUIC - minor cleanup while merging internal change. Merge internal change: 61850595 https://codereview.chromium.org/177073016/ Create QUIC_VERSION_16 which breaks the sent_info field out of the ACK frame into a new STOP_WAITING frame. Does not change when this information is sent. That will happen in a follow-up CL. Send STOP_WAITING_FRAME for QUIC version 16 and above with Ack frame. Added logging for WINDOW_UPDATE and BLOCKED frames. Merge internal change: 61838258 https://codereview.chromium.org/180383004/ QUIC test refactor to move tests from the QuicSentPacketManagerTest to the new TcpLossAlgorithmTest. Merge internal change: 61837708 https://codereview.chromium.org/177203008/ Ctrl-F for "packet XY" in debug logs now matches sent packets "Sending packet XY", and received packets "Got packet XY". (minor) Improve QUIC packet sent debug log message Merge internal change: 61836667 https://codereview.chromium.org/177003007/ Auotmated rollback of internal changelist 57996291. *** Reason for rollback *** Now that clients no longer suggests 100 by default, it would be nice to experiment with allowing the client to suggest larger CWNDs. *** Original change description *** Temporarily change the maximum server initial congestion window to 10 from 100, because many existing Chrome clients are still negotiating 100, causing visible performance issues, particularly for YouTube rebuffers. *** Merge internal change: 61825277 https://codereview.chromium.org/178853003/ Refactor to create a new LossDetectionInterface used by the QuicSentPacketManager. Merge internal change: 61813052 https://codereview.chromium.org/178453005/ Preparation for only writing a fraction of the iov due to flow control blocking in ReliableQuicStream::WritevData. Add max_bytes argument to QuicSession::WritevData Merge internal change: 61810929 https://codereview.chromium.org/177203006/ R=rch@chromium.org Review URL: https://codereview.chromium.org/180723003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@253647 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/quic')
-rw-r--r--net/quic/congestion_control/loss_detection_interface.cc16
-rw-r--r--net/quic/congestion_control/loss_detection_interface.h35
-rw-r--r--net/quic/congestion_control/tcp_loss_algorithm.cc51
-rw-r--r--net/quic/congestion_control/tcp_loss_algorithm.h36
-rw-r--r--net/quic/congestion_control/tcp_loss_algorithm_test.cc147
-rw-r--r--net/quic/quic_connection.cc122
-rw-r--r--net/quic/quic_connection.h18
-rw-r--r--net/quic/quic_connection_logger.cc53
-rw-r--r--net/quic/quic_connection_logger.h1
-rw-r--r--net/quic/quic_connection_test.cc553
-rw-r--r--net/quic/quic_framer.cc117
-rw-r--r--net/quic/quic_framer.h18
-rw-r--r--net/quic/quic_framer_test.cc593
-rw-r--r--net/quic/quic_headers_stream_test.cc9
-rw-r--r--net/quic/quic_packet_creator.cc11
-rw-r--r--net/quic/quic_packet_generator.cc34
-rw-r--r--net/quic/quic_packet_generator.h12
-rw-r--r--net/quic/quic_packet_generator_test.cc31
-rw-r--r--net/quic/quic_protocol.cc21
-rw-r--r--net/quic/quic_protocol.h28
-rw-r--r--net/quic/quic_received_packet_manager.cc15
-rw-r--r--net/quic/quic_received_packet_manager.h5
-rw-r--r--net/quic/quic_reliable_client_stream_test.cc6
-rw-r--r--net/quic/quic_sent_packet_manager.cc59
-rw-r--r--net/quic/quic_sent_packet_manager.h12
-rw-r--r--net/quic/quic_sent_packet_manager_test.cc168
-rw-r--r--net/quic/quic_session.cc5
-rw-r--r--net/quic/quic_session.h3
-rw-r--r--net/quic/quic_unacked_packet_map.cc3
-rw-r--r--net/quic/quic_utils.cc1
-rw-r--r--net/quic/reliable_quic_stream.cc7
-rw-r--r--net/quic/reliable_quic_stream_test.cc20
-rw-r--r--net/quic/test_tools/quic_test_packet_maker.cc13
-rw-r--r--net/quic/test_tools/quic_test_utils.cc17
-rw-r--r--net/quic/test_tools/quic_test_utils.h12
-rw-r--r--net/quic/test_tools/simple_quic_framer.cc23
-rw-r--r--net/quic/test_tools/simple_quic_framer.h1
37 files changed, 1732 insertions, 544 deletions
diff --git a/net/quic/congestion_control/loss_detection_interface.cc b/net/quic/congestion_control/loss_detection_interface.cc
new file mode 100644
index 0000000..ddb5b43
--- /dev/null
+++ b/net/quic/congestion_control/loss_detection_interface.cc
@@ -0,0 +1,16 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/loss_detection_interface.h"
+
+#include "net/quic/congestion_control/tcp_loss_algorithm.h"
+
+namespace net {
+
+// Factory for loss detection algorithm.
+LossDetectionInterface* LossDetectionInterface::Create() {
+ return new TCPLossAlgorithm();
+}
+
+} // namespace net
diff --git a/net/quic/congestion_control/loss_detection_interface.h b/net/quic/congestion_control/loss_detection_interface.h
new file mode 100644
index 0000000..65240a2
--- /dev/null
+++ b/net/quic/congestion_control/loss_detection_interface.h
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The pure virtual class for send side loss detection algorithm.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_
+#define NET_QUIC_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_
+
+#include "base/basictypes.h"
+#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_time.h"
+
+namespace net {
+
+class QuicUnackedPacketMap;
+
+class NET_EXPORT_PRIVATE LossDetectionInterface {
+ public:
+ // Creates a TCP loss detector.
+ static LossDetectionInterface* Create();
+
+ virtual ~LossDetectionInterface() {}
+
+ // Called when a new ack arrives or the loss alarm fires.
+ virtual SequenceNumberSet DetectLostPackets(
+ const QuicUnackedPacketMap& unacked_packets,
+ const QuicTime& time,
+ QuicPacketSequenceNumber largest_observed,
+ QuicTime::Delta srtt) = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_
diff --git a/net/quic/congestion_control/tcp_loss_algorithm.cc b/net/quic/congestion_control/tcp_loss_algorithm.cc
new file mode 100644
index 0000000..d4f2cf1
--- /dev/null
+++ b/net/quic/congestion_control/tcp_loss_algorithm.cc
@@ -0,0 +1,51 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/tcp_loss_algorithm.h"
+
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+namespace {
+// TCP retransmits after 3 nacks.
+static const size_t kNumberOfNacksBeforeRetransmission = 3;
+}
+
+TCPLossAlgorithm::TCPLossAlgorithm() { }
+
+// Uses nack counts to decide when packets are lost.
+SequenceNumberSet TCPLossAlgorithm::DetectLostPackets(
+ const QuicUnackedPacketMap& unacked_packets,
+ const QuicTime& time,
+ QuicPacketSequenceNumber largest_observed,
+ QuicTime::Delta srtt) {
+ SequenceNumberSet lost_packets;
+
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets.begin();
+ it != unacked_packets.end() && it->first <= largest_observed; ++it) {
+ if (!it->second.pending) {
+ continue;
+ }
+ size_t num_nacks_needed = kNumberOfNacksBeforeRetransmission;
+ // Check for early retransmit(RFC5827) when the last packet gets acked and
+ // the there are fewer than 4 pending packets.
+ // TODO(ianswett): Set a retransmission timer instead of losing the packet
+ // and retransmitting immediately.
+ if (it->second.retransmittable_frames &&
+ unacked_packets.largest_sent_packet() == largest_observed) {
+ num_nacks_needed = largest_observed - it->first;
+ }
+
+ if (it->second.nack_count < num_nacks_needed) {
+ continue;
+ }
+
+ lost_packets.insert(it->first);
+ }
+
+ return lost_packets;
+}
+
+} // namespace net
diff --git a/net/quic/congestion_control/tcp_loss_algorithm.h b/net/quic/congestion_control/tcp_loss_algorithm.h
new file mode 100644
index 0000000..a7599aa
--- /dev/null
+++ b/net/quic/congestion_control/tcp_loss_algorithm.h
@@ -0,0 +1,36 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_TCP_LOSS_ALGORITHM_H_
+#define NET_QUIC_CONGESTION_CONTROL_TCP_LOSS_ALGORITHM_H_
+
+#include <algorithm>
+#include <map>
+
+#include "base/basictypes.h"
+#include "net/quic/congestion_control/loss_detection_interface.h"
+#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_time.h"
+#include "net/quic/quic_unacked_packet_map.h"
+
+namespace net {
+
+// Class which implement's TCP's approach of detecting loss when 3 nacks have
+// been received for a packet. Also implements TCP's early retransmit(RFC5827).
+class NET_EXPORT_PRIVATE TCPLossAlgorithm : public LossDetectionInterface {
+ public:
+ TCPLossAlgorithm();
+ virtual ~TCPLossAlgorithm() {}
+
+ // Uses nack counts to decide when packets are lost.
+ virtual SequenceNumberSet DetectLostPackets(
+ const QuicUnackedPacketMap& unacked_packets,
+ const QuicTime& time,
+ QuicPacketSequenceNumber largest_observed,
+ QuicTime::Delta srtt) OVERRIDE;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_TCP_LOSS_ALGORITHM_H_
diff --git a/net/quic/congestion_control/tcp_loss_algorithm_test.cc b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
new file mode 100644
index 0000000..d2737df
--- /dev/null
+++ b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
@@ -0,0 +1,147 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/tcp_loss_algorithm.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "net/quic/quic_unacked_packet_map.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+namespace {
+
+class TcpLossAlgorithmTest : public ::testing::Test {
+ protected:
+ TcpLossAlgorithmTest()
+ : unacked_packets_(true),
+ srtt_(QuicTime::Delta::FromMilliseconds(10)) { }
+
+ void SendDataPacket(QuicPacketSequenceNumber sequence_number) {
+ SerializedPacket packet(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER,
+ NULL, 0, new RetransmittableFrames());
+ unacked_packets_.AddPacket(packet);
+ unacked_packets_.SetPending(sequence_number, QuicTime::Zero(), 1000);
+ }
+
+ void VerifyLosses(QuicPacketSequenceNumber largest_observed,
+ QuicPacketSequenceNumber* losses_expected,
+ size_t num_losses) {
+ SequenceNumberSet lost_packets =
+ loss_algorithm_.DetectLostPackets(
+ unacked_packets_, QuicTime::Zero(), largest_observed, srtt_);
+ EXPECT_EQ(num_losses, lost_packets.size());
+ for (size_t i = 0; i < num_losses; ++i) {
+ EXPECT_TRUE(ContainsKey(lost_packets, losses_expected[i]));
+ }
+ }
+
+ QuicUnackedPacketMap unacked_packets_;
+ TCPLossAlgorithm loss_algorithm_;
+ QuicTime::Delta srtt_;
+};
+
+TEST_F(TcpLossAlgorithmTest, NackRetransmit1Packet) {
+ const size_t kNumSentPackets = 5;
+ // Transmit 5 packets.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+ // No loss on one ack.
+ unacked_packets_.SetNotPending(2);
+ unacked_packets_.NackPacket(1, 1);
+ VerifyLosses(2, NULL, 0);
+ // No loss on two acks.
+ unacked_packets_.SetNotPending(3);
+ unacked_packets_.NackPacket(1, 2);
+ VerifyLosses(3, NULL, 0);
+ // Loss on three acks.
+ unacked_packets_.SetNotPending(4);
+ unacked_packets_.NackPacket(1, 3);
+ QuicPacketSequenceNumber lost[] = { 1 };
+ VerifyLosses(4, lost, arraysize(lost));
+}
+
+// A stretch ack is an ack that covers more than 1 packet of previously
+// unacknowledged data.
+TEST_F(TcpLossAlgorithmTest, NackRetransmit1PacketWith1StretchAck) {
+ const size_t kNumSentPackets = 10;
+ // Transmit 10 packets.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+
+ // Nack the first packet 3 times in a single StretchAck.
+ unacked_packets_.NackPacket(1, 3);
+ unacked_packets_.SetNotPending(2);
+ unacked_packets_.SetNotPending(3);
+ unacked_packets_.SetNotPending(4);
+ QuicPacketSequenceNumber lost[] = { 1 };
+ VerifyLosses(4, lost, arraysize(lost));
+}
+
+// Ack a packet 3 packets ahead, causing a retransmit.
+TEST_F(TcpLossAlgorithmTest, NackRetransmit1PacketSingleAck) {
+ const size_t kNumSentPackets = 10;
+ // Transmit 10 packets.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+
+ // Nack the first packet 3 times in an AckFrame with three missing packets.
+ unacked_packets_.NackPacket(1, 3);
+ unacked_packets_.NackPacket(2, 2);
+ unacked_packets_.NackPacket(3, 1);
+ unacked_packets_.SetNotPending(4);
+ QuicPacketSequenceNumber lost[] = { 1 };
+ VerifyLosses(4, lost, arraysize(lost));
+}
+
+TEST_F(TcpLossAlgorithmTest, EarlyRetransmit1Packet) {
+ const size_t kNumSentPackets = 2;
+ // Transmit 2 packets.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+ // Early retransmit when the final packet gets acked and the first is nacked.
+ unacked_packets_.SetNotPending(2);
+ unacked_packets_.NackPacket(1, 1);
+ QuicPacketSequenceNumber lost[] = { 1 };
+ VerifyLosses(2, lost, arraysize(lost));
+}
+
+TEST_F(TcpLossAlgorithmTest, EarlyRetransmitAllPackets) {
+ const size_t kNumSentPackets = 5;
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+ // Early retransmit when the final packet gets acked and the first 4 are
+ // nacked multiple times via FACK.
+ unacked_packets_.SetNotPending(kNumSentPackets);
+ for (size_t i = 1; i < kNumSentPackets; ++i) {
+ unacked_packets_.NackPacket(i, kNumSentPackets - i);
+ }
+ QuicPacketSequenceNumber lost[] = { 1, 2, 3, 4 };
+ VerifyLosses(kNumSentPackets, lost, arraysize(lost));
+}
+
+TEST_F(TcpLossAlgorithmTest, DontEarlyRetransmitNeuteredPacket) {
+ const size_t kNumSentPackets = 2;
+ // Transmit 2 packets.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+ // Early retransmit when the final packet gets acked and the first is nacked.
+ unacked_packets_.SetNotPending(2);
+ unacked_packets_.NackPacket(1, 1);
+ unacked_packets_.NeuterPacket(1);
+ VerifyLosses(2, NULL, 0);
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 438972c..e5bcbb9 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -179,6 +179,7 @@ QuicConnection::QuicConnection(QuicGuid guid,
guid_(guid),
peer_address_(address),
largest_seen_packet_with_ack_(0),
+ largest_seen_packet_with_stop_waiting_(0),
pending_version_negotiation_packet_(false),
received_packet_manager_(kTCP),
ack_queued_(false),
@@ -260,9 +261,11 @@ void QuicConnection::OnPacket() {
DCHECK(last_stream_frames_.empty() &&
last_goaway_frames_.empty() &&
last_window_update_frames_.empty() &&
+ last_blocked_frames_.empty() &&
last_rst_frames_.empty() &&
last_ack_frames_.empty() &&
- last_congestion_frames_.empty());
+ last_congestion_frames_.empty() &&
+ last_stop_waiting_frames_.empty());
}
void QuicConnection::OnPublicResetPacket(
@@ -493,13 +496,11 @@ bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) {
void QuicConnection::ProcessAckFrame(const QuicAckFrame& incoming_ack) {
largest_seen_packet_with_ack_ = last_header_.packet_sequence_number;
-
received_packet_manager_.UpdatePacketInformationReceivedByPeer(
incoming_ack.received_info);
- received_packet_manager_.UpdatePacketInformationSentByPeer(
- incoming_ack.sent_info);
- // Possibly close any FecGroups which are now irrelevant.
- CloseFecGroupsBefore(incoming_ack.sent_info.least_unacked + 1);
+ if (version() <= QUIC_VERSION_15) {
+ ProcessStopWaitingFrame(incoming_ack.sent_info);
+ }
sent_entropy_manager_.ClearEntropyBefore(
received_packet_manager_.least_packet_awaited_by_peer() - 1);
@@ -521,6 +522,14 @@ void QuicConnection::ProcessAckFrame(const QuicAckFrame& incoming_ack) {
}
}
+void QuicConnection::ProcessStopWaitingFrame(
+ const QuicStopWaitingFrame& stop_waiting) {
+ largest_seen_packet_with_stop_waiting_ = last_header_.packet_sequence_number;
+ received_packet_manager_.UpdatePacketInformationSentByPeer(stop_waiting);
+ // Possibly close any FecGroups which are now irrelevant.
+ CloseFecGroupsBefore(stop_waiting.least_unacked + 1);
+}
+
bool QuicConnection::OnCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& feedback) {
DCHECK(connected_);
@@ -531,6 +540,28 @@ bool QuicConnection::OnCongestionFeedbackFrame(
return connected_;
}
+bool QuicConnection::OnStopWaitingFrame(const QuicStopWaitingFrame& frame) {
+ DCHECK(connected_);
+
+ if (last_header_.packet_sequence_number <=
+ largest_seen_packet_with_stop_waiting_) {
+ DVLOG(1) << ENDPOINT << "Received an old stop waiting frame: ignoring";
+ return true;
+ }
+
+ if (!ValidateStopWaitingFrame(frame)) {
+ SendConnectionClose(QUIC_INVALID_STOP_WAITING_DATA);
+ return false;
+ }
+
+ if (debug_visitor_) {
+ debug_visitor_->OnStopWaitingFrame(frame);
+ }
+
+ last_stop_waiting_frames_.push_back(frame);
+ return connected_;
+}
+
bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
if (incoming_ack.received_info.largest_observed >
packet_creator_.sequence_number()) {
@@ -551,22 +582,10 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
return false;
}
- if (incoming_ack.sent_info.least_unacked <
- received_packet_manager_.peer_least_packet_awaiting_ack()) {
- DLOG(ERROR) << ENDPOINT << "Peer's sent low least_unacked: "
- << incoming_ack.sent_info.least_unacked << " vs "
- << received_packet_manager_.peer_least_packet_awaiting_ack();
- // We never process old ack frames, so this number should only increase.
- return false;
- }
-
- if (incoming_ack.sent_info.least_unacked >
- last_header_.packet_sequence_number) {
- DLOG(ERROR) << ENDPOINT << "Peer sent least_unacked:"
- << incoming_ack.sent_info.least_unacked
- << " greater than the enclosing packet sequence number:"
- << last_header_.packet_sequence_number;
- return false;
+ if (version() <= QUIC_VERSION_15) {
+ if (!ValidateStopWaitingFrame(incoming_ack.sent_info)) {
+ return false;
+ }
}
if (!incoming_ack.received_info.missing_packets.empty() &&
@@ -609,6 +628,29 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
return true;
}
+bool QuicConnection::ValidateStopWaitingFrame(
+ const QuicStopWaitingFrame& stop_waiting) {
+ if (stop_waiting.least_unacked <
+ received_packet_manager_.peer_least_packet_awaiting_ack()) {
+ DLOG(ERROR) << ENDPOINT << "Peer's sent low least_unacked: "
+ << stop_waiting.least_unacked << " vs "
+ << received_packet_manager_.peer_least_packet_awaiting_ack();
+ // We never process old ack frames, so this number should only increase.
+ return false;
+ }
+
+ if (stop_waiting.least_unacked >
+ last_header_.packet_sequence_number) {
+ DLOG(ERROR) << ENDPOINT << "Peer sent least_unacked:"
+ << stop_waiting.least_unacked
+ << " greater than the enclosing packet sequence number:"
+ << last_header_.packet_sequence_number;
+ return false;
+ }
+
+ return true;
+}
+
void QuicConnection::OnFecData(const QuicFecData& fec) {
DCHECK_EQ(IN_FEC_GROUP, last_header_.is_in_fec_group);
DCHECK_NE(0u, last_header_.fec_group);
@@ -678,8 +720,10 @@ void QuicConnection::OnPacketComplete() {
<< " packet " << last_header_.packet_sequence_number
<< " with " << last_ack_frames_.size() << " acks, "
<< last_congestion_frames_.size() << " congestions, "
+ << last_stop_waiting_frames_.size() << " stop_waiting, "
<< last_goaway_frames_.size() << " goaways, "
<< last_window_update_frames_.size() << " window updates, "
+ << last_blocked_frames_.size() << " blocked, "
<< last_rst_frames_.size() << " rsts, "
<< last_close_frames_.size() << " closes, "
<< last_stream_frames_.size()
@@ -726,6 +770,9 @@ void QuicConnection::OnPacketComplete() {
sent_packet_manager_.OnIncomingQuicCongestionFeedbackFrame(
last_congestion_frames_[i], time_of_last_received_packet_);
}
+ for (size_t i = 0; i < last_stop_waiting_frames_.size(); ++i) {
+ ProcessStopWaitingFrame(last_stop_waiting_frames_[i]);
+ }
if (!last_close_frames_.empty()) {
CloseConnection(last_close_frames_[0].error_code, true);
DCHECK(!connected_);
@@ -766,8 +813,10 @@ void QuicConnection::ClearLastFrames() {
last_stream_frames_.clear();
last_goaway_frames_.clear();
last_window_update_frames_.clear();
+ last_blocked_frames_.clear();
last_rst_frames_.clear();
last_ack_frames_.clear();
+ last_stop_waiting_frames_.clear();
last_congestion_frames_.clear();
}
@@ -775,7 +824,7 @@ QuicAckFrame* QuicConnection::CreateAckFrame() {
QuicAckFrame* outgoing_ack = new QuicAckFrame();
received_packet_manager_.UpdateReceivedPacketInfo(
&(outgoing_ack->received_info), clock_->ApproximateNow());
- UpdateSentPacketInfo(&(outgoing_ack->sent_info));
+ UpdateStopWaiting(&(outgoing_ack->sent_info));
DVLOG(1) << ENDPOINT << "Creating ack frame: " << *outgoing_ack;
return outgoing_ack;
}
@@ -784,10 +833,18 @@ QuicCongestionFeedbackFrame* QuicConnection::CreateFeedbackFrame() {
return new QuicCongestionFeedbackFrame(outgoing_congestion_feedback_);
}
+QuicStopWaitingFrame* QuicConnection::CreateStopWaitingFrame() {
+ QuicStopWaitingFrame stop_waiting;
+ UpdateStopWaiting(&stop_waiting);
+ return new QuicStopWaitingFrame(stop_waiting);
+}
+
bool QuicConnection::ShouldLastPacketInstigateAck() const {
if (!last_stream_frames_.empty() ||
!last_goaway_frames_.empty() ||
- !last_rst_frames_.empty()) {
+ !last_rst_frames_.empty() ||
+ !last_window_update_frames_.empty() ||
+ !last_blocked_frames_.empty()) {
return true;
}
@@ -795,7 +852,6 @@ bool QuicConnection::ShouldLastPacketInstigateAck() const {
last_ack_frames_.back().received_info.is_truncated) {
return true;
}
-
return false;
}
@@ -1197,7 +1253,7 @@ bool QuicConnection::WritePacket(QueuedPacket packet) {
<< "Writing an encrypted packet larger than max_packet_length:"
<< options()->max_packet_length << " encrypted length: "
<< encrypted->length();
- DVLOG(1) << ENDPOINT << "Sending packet number " << sequence_number
+ DVLOG(1) << ENDPOINT << "Sending packet " << sequence_number
<< " : " << (packet.packet->is_fec_packet() ? "FEC " :
(packet.retransmittable == HAS_RETRANSMITTABLE_DATA
? "data bearing " : " ack only "))
@@ -1381,10 +1437,10 @@ bool QuicConnection::SendOrQueuePacket(EncryptionLevel level,
return false;
}
-void QuicConnection::UpdateSentPacketInfo(SentPacketInfo* sent_info) {
- sent_info->least_unacked = GetLeastUnacked();
- sent_info->entropy_hash = sent_entropy_manager_.EntropyHash(
- sent_info->least_unacked - 1);
+void QuicConnection::UpdateStopWaiting(QuicStopWaitingFrame* stop_waiting) {
+ stop_waiting->least_unacked = GetLeastUnacked();
+ stop_waiting->entropy_hash = sent_entropy_manager_.EntropyHash(
+ stop_waiting->least_unacked - 1);
}
void QuicConnection::SendAck() {
@@ -1401,7 +1457,8 @@ void QuicConnection::SendAck() {
send_feedback = true;
}
- packet_generator_.SetShouldSendAck(send_feedback);
+ packet_generator_.SetShouldSendAck(send_feedback,
+ version() > QUIC_VERSION_15);
}
void QuicConnection::OnRetransmissionTimeout() {
@@ -1560,6 +1617,9 @@ void QuicConnection::SendConnectionClosePacket(QuicErrorCode error,
void QuicConnection::CloseConnection(QuicErrorCode error, bool from_peer) {
DCHECK(connected_);
+ if (!connected_) {
+ return;
+ }
connected_ = false;
visitor_->OnConnectionClosed(error, from_peer);
// Cancel the alarms so they don't trigger any action now that the
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 909fbbe..481f426 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -148,6 +148,9 @@ class NET_EXPORT_PRIVATE QuicConnectionDebugVisitorInterface
virtual void OnCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame) = 0;
+ // Called when a StopWaitingFrame has been parsed.
+ virtual void OnStopWaitingFrame(const QuicStopWaitingFrame& frame) = 0;
+
// Called when a RstStreamFrame has been parsed.
virtual void OnRstStreamFrame(const QuicRstStreamFrame& frame) = 0;
@@ -302,6 +305,7 @@ class NET_EXPORT_PRIVATE QuicConnection
virtual bool OnAckFrame(const QuicAckFrame& frame) OVERRIDE;
virtual bool OnCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame) OVERRIDE;
+ virtual bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) OVERRIDE;
virtual bool OnRstStreamFrame(const QuicRstStreamFrame& frame) OVERRIDE;
virtual bool OnConnectionCloseFrame(
const QuicConnectionCloseFrame& frame) OVERRIDE;
@@ -317,6 +321,7 @@ class NET_EXPORT_PRIVATE QuicConnection
IsHandshake handshake) OVERRIDE;
virtual QuicAckFrame* CreateAckFrame() OVERRIDE;
virtual QuicCongestionFeedbackFrame* CreateFeedbackFrame() OVERRIDE;
+ virtual QuicStopWaitingFrame* CreateStopWaitingFrame() OVERRIDE;
virtual bool OnSerializedPacket(const SerializedPacket& packet) OVERRIDE;
// Accessors
@@ -425,6 +430,9 @@ class NET_EXPORT_PRIVATE QuicConnection
return sent_packet_manager_;
}
+ // Make sure a stop waiting we got from our peer is sane.
+ bool ValidateStopWaitingFrame(const QuicStopWaitingFrame& stop_waiting);
+
bool CanWrite(TransmissionType transmission_type,
HasRetransmittableData retransmittable,
IsHandshake handshake);
@@ -549,8 +557,10 @@ class NET_EXPORT_PRIVATE QuicConnection
void ProcessAckFrame(const QuicAckFrame& incoming_ack);
- // Update the |sent_info| for an outgoing ack.
- void UpdateSentPacketInfo(SentPacketInfo* sent_info);
+ void ProcessStopWaitingFrame(const QuicStopWaitingFrame& stop_waiting);
+
+ // Update |stop_waiting| for an outgoing ack.
+ void UpdateStopWaiting(QuicStopWaitingFrame* stop_waiting);
// Queues an ack or sets the ack alarm when an incoming packet arrives that
// should be acked.
@@ -597,6 +607,7 @@ class NET_EXPORT_PRIVATE QuicConnection
std::vector<QuicStreamFrame> last_stream_frames_;
std::vector<QuicAckFrame> last_ack_frames_;
std::vector<QuicCongestionFeedbackFrame> last_congestion_frames_;
+ std::vector<QuicStopWaitingFrame> last_stop_waiting_frames_;
std::vector<QuicRstStreamFrame> last_rst_frames_;
std::vector<QuicGoAwayFrame> last_goaway_frames_;
std::vector<QuicWindowUpdateFrame> last_window_update_frames_;
@@ -609,6 +620,9 @@ class NET_EXPORT_PRIVATE QuicConnection
// Largest sequence sent by the peer which had an ack frame (latest ack info).
QuicPacketSequenceNumber largest_seen_packet_with_ack_;
+ // Largest sequence number sent by the peer which had a stop waiting frame.
+ QuicPacketSequenceNumber largest_seen_packet_with_stop_waiting_;
+
// Collection of packets which were received before encryption was
// established, but which could not be decrypted. We buffer these on
// the assumption that they could not be processed because they were
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index d52debe..9a775182 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -163,6 +163,34 @@ base::Value* NetLogQuicConnectionCloseFrameCallback(
return dict;
}
+base::Value* NetLogQuicWindowUpdateFrameCallback(
+ const QuicWindowUpdateFrame* frame,
+ NetLog::LogLevel /* log_level */) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetInteger("stream_id", frame->stream_id);
+ dict->SetString("byte_offset", base::Uint64ToString(frame->byte_offset));
+ return dict;
+}
+
+base::Value* NetLogQuicBlockedFrameCallback(
+ const QuicBlockedFrame* frame,
+ NetLog::LogLevel /* log_level */) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetInteger("stream_id", frame->stream_id);
+ return dict;
+}
+
+base::Value* NetLogQuicStopWaitingFrameCallback(
+ const QuicStopWaitingFrame* frame,
+ NetLog::LogLevel /* log_level */) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ base::DictionaryValue* sent_info = new base::DictionaryValue();
+ dict->Set("sent_info", sent_info);
+ sent_info->SetString("least_unacked",
+ base::Uint64ToString(frame->least_unacked));
+ return dict;
+}
+
base::Value* NetLogQuicVersionNegotiationPacketCallback(
const QuicVersionNegotiationPacket* packet,
NetLog::LogLevel /* log_level */) {
@@ -271,6 +299,24 @@ void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) {
break;
case GOAWAY_FRAME:
break;
+ case WINDOW_UPDATE_FRAME:
+ net_log_.AddEvent(
+ NetLog::TYPE_QUIC_SESSION_WINDOW_UPDATE_FRAME_SENT,
+ base::Bind(&NetLogQuicWindowUpdateFrameCallback,
+ frame.window_update_frame));
+ break;
+ case BLOCKED_FRAME:
+ net_log_.AddEvent(
+ NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_SENT,
+ base::Bind(&NetLogQuicBlockedFrameCallback,
+ frame.blocked_frame));
+ break;
+ case STOP_WAITING_FRAME:
+ net_log_.AddEvent(
+ NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_SENT,
+ base::Bind(&NetLogQuicStopWaitingFrameCallback,
+ frame.stop_waiting_frame));
+ break;
default:
DCHECK(false) << "Illegal frame type: " << frame.type;
}
@@ -392,6 +438,13 @@ void QuicConnectionLogger::OnCongestionFeedbackFrame(
base::Bind(&NetLogQuicCongestionFeedbackFrameCallback, &frame));
}
+void QuicConnectionLogger::OnStopWaitingFrame(
+ const QuicStopWaitingFrame& frame) {
+ net_log_.AddEvent(
+ NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_RECEIVED,
+ base::Bind(&NetLogQuicStopWaitingFrameCallback, &frame));
+}
+
void QuicConnectionLogger::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeServer",
frame.error_code);
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index ed9577a..dd8f6b5 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -42,6 +42,7 @@ class NET_EXPORT_PRIVATE QuicConnectionLogger
virtual void OnAckFrame(const QuicAckFrame& frame) OVERRIDE;
virtual void OnCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame) OVERRIDE;
+ virtual void OnStopWaitingFrame(const QuicStopWaitingFrame& frame) OVERRIDE;
virtual void OnRstStreamFrame(const QuicRstStreamFrame& frame) OVERRIDE;
virtual void OnConnectionCloseFrame(
const QuicConnectionCloseFrame& frame) OVERRIDE;
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 2664149..7feb87a 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -272,8 +272,9 @@ class TestConnectionHelper : public QuicConnectionHelperInterface {
class TestPacketWriter : public QuicPacketWriter {
public:
- TestPacketWriter()
- : last_packet_size_(0),
+ explicit TestPacketWriter(QuicVersion version)
+ : version_(version),
+ last_packet_size_(0),
write_blocked_(false),
block_on_next_write_(false),
is_write_blocked_data_buffered_(false),
@@ -298,7 +299,8 @@ class TestPacketWriter : public QuicPacketWriter {
sizeof(final_bytes_of_last_packet_));
}
- QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(), !is_server_);
+ QuicFramer framer(SupportedVersions(version_),
+ QuicTime::Zero(), !is_server_);
if (use_tagging_decrypter_) {
framer.SetDecrypter(new TaggingDecrypter);
}
@@ -339,6 +341,8 @@ class TestPacketWriter : public QuicPacketWriter {
QuicCongestionFeedbackFrame* feedback() { return visitor_.feedback(); }
+ QuicStopWaitingFrame* stop_waiting() { return visitor_.stop_waiting(); }
+
QuicConnectionCloseFrame* close() { return visitor_.close(); }
const vector<QuicStreamFrame>* stream_frames() const {
@@ -377,6 +381,7 @@ class TestPacketWriter : public QuicPacketWriter {
uint32 packets_write_attempts() { return packets_write_attempts_; }
private:
+ QuicVersion version_;
FramerVisitorCapturingFrames visitor_;
size_t last_packet_size_;
bool write_blocked_;
@@ -397,9 +402,10 @@ class TestConnection : public QuicConnection {
IPEndPoint address,
TestConnectionHelper* helper,
TestPacketWriter* writer,
- bool is_server)
+ bool is_server,
+ QuicVersion version)
: QuicConnection(guid, address, helper, writer, is_server,
- QuicSupportedVersions()),
+ SupportedVersions(version)),
helper_(helper),
writer_(writer) {
// Disable tail loss probes for most tests.
@@ -481,6 +487,10 @@ class TestConnection : public QuicConnection {
QuicConnectionPeer::GetFramer(this)->set_version(version);
}
+ void SetSupportedVersions(const QuicVersionVector& versions) {
+ QuicConnectionPeer::GetFramer(this)->SetSupportedVersions(versions);
+ }
+
void set_is_server(bool is_server) {
writer_->set_is_server(is_server);
QuicPacketCreatorPeer::SetIsServer(
@@ -522,16 +532,17 @@ class TestConnection : public QuicConnection {
DISALLOW_COPY_AND_ASSIGN(TestConnection);
};
-class QuicConnectionTest : public ::testing::TestWithParam<bool> {
+class QuicConnectionTest : public ::testing::TestWithParam<QuicVersion> {
protected:
QuicConnectionTest()
: guid_(42),
- framer_(QuicSupportedVersions(), QuicTime::Zero(), false),
+ framer_(SupportedVersions(version()), QuicTime::Zero(), false),
creator_(guid_, &framer_, &random_generator_, false),
send_algorithm_(new StrictMock<MockSendAlgorithm>),
helper_(new TestConnectionHelper(&clock_, &random_generator_)),
- writer_(new TestPacketWriter()),
- connection_(guid_, IPEndPoint(), helper_.get(), writer_.get(), false),
+ writer_(new TestPacketWriter(version())),
+ connection_(guid_, IPEndPoint(), helper_.get(), writer_.get(),
+ false, version()),
frame1_(1, false, 0, MakeIOVector(data1)),
frame2_(1, false, 3, MakeIOVector(data2)),
accept_packet_(true) {
@@ -560,11 +571,30 @@ class QuicConnectionTest : public ::testing::TestWithParam<bool> {
EXPECT_CALL(visitor_, OnCanWrite()).Times(AnyNumber());
}
+ QuicVersion version() {
+ return GetParam();
+ }
+
QuicAckFrame* outgoing_ack() {
outgoing_ack_.reset(QuicConnectionPeer::CreateAckFrame(&connection_));
return outgoing_ack_.get();
}
+ QuicPacketSequenceNumber least_unacked() {
+ if (version() <= QUIC_VERSION_15) {
+ QuicAckFrame* ack = last_ack();
+ if (ack == NULL) {
+ return 0;
+ }
+ return ack->sent_info.least_unacked;
+ }
+ QuicStopWaitingFrame* stop_waiting = last_stop_waiting();
+ if (stop_waiting == NULL) {
+ return 0;
+ }
+ return stop_waiting->least_unacked;
+ }
+
QuicAckFrame* last_ack() {
return writer_->ack();
}
@@ -573,6 +603,10 @@ class QuicConnectionTest : public ::testing::TestWithParam<bool> {
return writer_->feedback();
}
+ QuicStopWaitingFrame* last_stop_waiting() {
+ return writer_->stop_waiting();
+ }
+
QuicConnectionCloseFrame* last_close() {
return writer_->close();
}
@@ -737,6 +771,10 @@ class QuicConnectionTest : public ::testing::TestWithParam<bool> {
return ProcessFramePacket(QuicFrame(frame));
}
+ QuicPacketEntropyHash ProcessStopWaitingPacket(QuicStopWaitingFrame* frame) {
+ return ProcessFramePacket(QuicFrame(frame));
+ }
+
QuicPacketEntropyHash ProcessGoAwayPacket(QuicGoAwayFrame* frame) {
return ProcessFramePacket(QuicFrame(frame));
}
@@ -813,6 +851,12 @@ class QuicConnectionTest : public ::testing::TestWithParam<bool> {
return frame;
}
+ const QuicStopWaitingFrame InitStopWaitingFrame(
+ QuicPacketSequenceNumber least_unacked) {
+ QuicStopWaitingFrame frame;
+ frame.least_unacked = least_unacked;
+ return frame;
+ }
// Explicitly nack a packet.
void NackPacket(QuicPacketSequenceNumber missing, QuicAckFrame* frame) {
frame->received_info.missing_packets.insert(missing);
@@ -876,7 +920,12 @@ class QuicConnectionTest : public ::testing::TestWithParam<bool> {
DISALLOW_COPY_AND_ASSIGN(QuicConnectionTest);
};
-TEST_F(QuicConnectionTest, PacketsInOrder) {
+// Run all end to end tests with all supported versions.
+INSTANTIATE_TEST_CASE_P(SupportedVersion,
+ QuicConnectionTest,
+ ::testing::ValuesIn(QuicSupportedVersions()));
+
+TEST_P(QuicConnectionTest, PacketsInOrder) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
@@ -892,7 +941,7 @@ TEST_F(QuicConnectionTest, PacketsInOrder) {
EXPECT_EQ(0u, outgoing_ack()->received_info.missing_packets.size());
}
-TEST_F(QuicConnectionTest, PacketsRejected) {
+TEST_P(QuicConnectionTest, PacketsRejected) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
@@ -906,7 +955,7 @@ TEST_F(QuicConnectionTest, PacketsRejected) {
EXPECT_EQ(0u, outgoing_ack()->received_info.missing_packets.size());
}
-TEST_F(QuicConnectionTest, PacketsOutOfOrder) {
+TEST_P(QuicConnectionTest, PacketsOutOfOrder) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(3);
@@ -925,7 +974,7 @@ TEST_F(QuicConnectionTest, PacketsOutOfOrder) {
EXPECT_FALSE(IsMissing(1));
}
-TEST_F(QuicConnectionTest, DuplicatePacket) {
+TEST_P(QuicConnectionTest, DuplicatePacket) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(3);
@@ -941,7 +990,7 @@ TEST_F(QuicConnectionTest, DuplicatePacket) {
EXPECT_TRUE(IsMissing(1));
}
-TEST_F(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) {
+TEST_P(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(3);
@@ -971,7 +1020,7 @@ TEST_F(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) {
EXPECT_TRUE(IsMissing(4));
}
-TEST_F(QuicConnectionTest, RejectPacketTooFarOut) {
+TEST_P(QuicConnectionTest, RejectPacketTooFarOut) {
EXPECT_CALL(visitor_,
OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, false));
// Call ProcessDataPacket rather than ProcessPacket, as we should not get a
@@ -981,7 +1030,7 @@ TEST_F(QuicConnectionTest, RejectPacketTooFarOut) {
QuicConnectionPeer::GetConnectionClosePacket(&connection_) == NULL);
}
-TEST_F(QuicConnectionTest, TruncatedAck) {
+TEST_P(QuicConnectionTest, TruncatedAck) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicPacketSequenceNumber num_packets = 256 * 2 + 1;
for (QuicPacketSequenceNumber i = 0; i < num_packets; ++i) {
@@ -1018,7 +1067,7 @@ TEST_F(QuicConnectionTest, TruncatedAck) {
received_packet_manager->peer_largest_observed_packet());
}
-TEST_F(QuicConnectionTest, AckReceiptCausesAckSendBadEntropy) {
+TEST_P(QuicConnectionTest, AckReceiptCausesAckSendBadEntropy) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
@@ -1039,7 +1088,7 @@ TEST_F(QuicConnectionTest, AckReceiptCausesAckSendBadEntropy) {
ProcessAckPacket(&frame);
}
-TEST_F(QuicConnectionTest, OutOfOrderReceiptCausesAckSend) {
+TEST_P(QuicConnectionTest, OutOfOrderReceiptCausesAckSend) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(3);
@@ -1059,7 +1108,7 @@ TEST_F(QuicConnectionTest, OutOfOrderReceiptCausesAckSend) {
EXPECT_EQ(3u, writer_->packets_write_attempts());
}
-TEST_F(QuicConnectionTest, AckReceiptCausesAckSend) {
+TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(1);
QuicPacketSequenceNumber original;
@@ -1103,7 +1152,11 @@ TEST_F(QuicConnectionTest, AckReceiptCausesAckSend) {
HAS_RETRANSMITTABLE_DATA));
connection_.SendStreamDataWithString(3, "foo", 3, !kFin, NULL);
// Ack bundled.
- EXPECT_EQ(2u, writer_->frame_count());
+ if (version() > QUIC_VERSION_15) {
+ EXPECT_EQ(3u, writer_->frame_count());
+ } else {
+ EXPECT_EQ(2u, writer_->frame_count());
+ }
EXPECT_EQ(1u, writer_->stream_frames()->size());
EXPECT_TRUE(writer_->ack());
@@ -1113,7 +1166,7 @@ TEST_F(QuicConnectionTest, AckReceiptCausesAckSend) {
ProcessAckPacket(&frame2);
}
-TEST_F(QuicConnectionTest, LeastUnackedLower) {
+TEST_P(QuicConnectionTest, LeastUnackedLower) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
SendStreamDataToPeer(1, "foo", 0, !kFin, NULL);
@@ -1122,27 +1175,45 @@ TEST_F(QuicConnectionTest, LeastUnackedLower) {
// Start out saying the least unacked is 2.
creator_.set_sequence_number(5);
- QuicAckFrame frame = InitAckFrame(0, 2);
- ProcessAckPacket(&frame);
+ if (version() > QUIC_VERSION_15) {
+ QuicStopWaitingFrame frame = InitStopWaitingFrame(2);
+ ProcessStopWaitingPacket(&frame);
+ } else {
+ QuicAckFrame frame = InitAckFrame(0, 2);
+ ProcessAckPacket(&frame);
+ }
// Change it to 1, but lower the sequence number to fake out-of-order packets.
// This should be fine.
creator_.set_sequence_number(1);
- QuicAckFrame frame2 = InitAckFrame(0, 1);
// The scheduler will not process out of order acks, but all packet processing
// causes the connection to try to write.
EXPECT_CALL(visitor_, OnCanWrite());
- ProcessAckPacket(&frame2);
+ if (version() > QUIC_VERSION_15) {
+ QuicStopWaitingFrame frame2 = InitStopWaitingFrame(1);
+ ProcessStopWaitingPacket(&frame2);
+ } else {
+ QuicAckFrame frame2 = InitAckFrame(0, 1);
+ ProcessAckPacket(&frame2);
+ }
// Now claim it's one, but set the ordering so it was sent "after" the first
// one. This should cause a connection error.
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, false));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
creator_.set_sequence_number(7);
- ProcessAckPacket(&frame2);
+ if (version() > QUIC_VERSION_15) {
+ EXPECT_CALL(visitor_,
+ OnConnectionClosed(QUIC_INVALID_STOP_WAITING_DATA, false));
+ QuicStopWaitingFrame frame2 = InitStopWaitingFrame(1);
+ ProcessStopWaitingPacket(&frame2);
+ } else {
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, false));
+ QuicAckFrame frame2 = InitAckFrame(0, 1);
+ ProcessAckPacket(&frame2);
+ }
}
-TEST_F(QuicConnectionTest, LargestObservedLower) {
+TEST_P(QuicConnectionTest, LargestObservedLower) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
SendStreamDataToPeer(1, "foo", 0, !kFin, NULL);
@@ -1162,7 +1233,7 @@ TEST_F(QuicConnectionTest, LargestObservedLower) {
ProcessAckPacket(&frame1);
}
-TEST_F(QuicConnectionTest, AckUnsentData) {
+TEST_P(QuicConnectionTest, AckUnsentData) {
// Ack a packet which has not been sent.
EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, false));
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -1172,7 +1243,7 @@ TEST_F(QuicConnectionTest, AckUnsentData) {
ProcessAckPacket(&frame);
}
-TEST_F(QuicConnectionTest, AckAll) {
+TEST_P(QuicConnectionTest, AckAll) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
@@ -1181,7 +1252,7 @@ TEST_F(QuicConnectionTest, AckAll) {
ProcessAckPacket(&frame1);
}
-TEST_F(QuicConnectionTest, SendingDifferentSequenceNumberLengthsBandwidth) {
+TEST_P(QuicConnectionTest, SendingDifferentSequenceNumberLengthsBandwidth) {
EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillOnce(Return(
QuicBandwidth::FromKBitsPerSecond(1000)));
@@ -1236,7 +1307,7 @@ TEST_F(QuicConnectionTest, SendingDifferentSequenceNumberLengthsBandwidth) {
last_header()->public_header.sequence_number_length);
}
-TEST_F(QuicConnectionTest, SendingDifferentSequenceNumberLengthsUnackedDelta) {
+TEST_P(QuicConnectionTest, SendingDifferentSequenceNumberLengthsUnackedDelta) {
QuicPacketSequenceNumber last_packet;
SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet);
EXPECT_EQ(1u, last_packet);
@@ -1281,22 +1352,22 @@ TEST_F(QuicConnectionTest, SendingDifferentSequenceNumberLengthsUnackedDelta) {
last_header()->public_header.sequence_number_length);
}
-TEST_F(QuicConnectionTest, BasicSending) {
+TEST_P(QuicConnectionTest, BasicSending) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicPacketSequenceNumber last_packet;
SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1
EXPECT_EQ(1u, last_packet);
SendAckPacketToPeer(); // Packet 2
- EXPECT_EQ(1u, last_ack()->sent_info.least_unacked);
+ EXPECT_EQ(1u, least_unacked());
SendAckPacketToPeer(); // Packet 3
- EXPECT_EQ(1u, last_ack()->sent_info.least_unacked);
+ EXPECT_EQ(1u, least_unacked());
SendStreamDataToPeer(1, "bar", 3, !kFin, &last_packet); // Packet 4
EXPECT_EQ(4u, last_packet);
SendAckPacketToPeer(); // Packet 5
- EXPECT_EQ(1u, last_ack()->sent_info.least_unacked);
+ EXPECT_EQ(1u, least_unacked());
EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(3);
@@ -1308,7 +1379,7 @@ TEST_F(QuicConnectionTest, BasicSending) {
// As soon as we've acked one, we skip ack packets 2 and 3 and note lack of
// ack for 4.
- EXPECT_EQ(4u, last_ack()->sent_info.least_unacked);
+ EXPECT_EQ(4u, least_unacked());
EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(3);
@@ -1321,20 +1392,23 @@ TEST_F(QuicConnectionTest, BasicSending) {
EXPECT_EQ(6u, last_header()->packet_sequence_number);
// So the last ack has not changed.
- EXPECT_EQ(4u, last_ack()->sent_info.least_unacked);
+ EXPECT_EQ(4u, least_unacked());
// If we force an ack, we shouldn't change our retransmit state.
SendAckPacketToPeer(); // Packet 7
- EXPECT_EQ(7u, last_ack()->sent_info.least_unacked);
+ EXPECT_EQ(7u, least_unacked());
// But if we send more data it should.
SendStreamDataToPeer(1, "eep", 6, !kFin, &last_packet); // Packet 8
EXPECT_EQ(8u, last_packet);
SendAckPacketToPeer(); // Packet 9
- EXPECT_EQ(7u, last_ack()->sent_info.least_unacked);
+ EXPECT_EQ(7u, least_unacked());
}
-TEST_F(QuicConnectionTest, FECSending) {
+TEST_P(QuicConnectionTest, FECSending) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
// All packets carry version info till version is negotiated.
size_t payload_length;
connection_.options()->max_packet_length =
@@ -1353,7 +1427,10 @@ TEST_F(QuicConnectionTest, FECSending) {
EXPECT_FALSE(creator_.ShouldSendFec(true));
}
-TEST_F(QuicConnectionTest, FECQueueing) {
+TEST_P(QuicConnectionTest, FECQueueing) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
// All packets carry version info till version is negotiated.
size_t payload_length;
connection_.options()->max_packet_length =
@@ -1372,7 +1449,10 @@ TEST_F(QuicConnectionTest, FECQueueing) {
EXPECT_EQ(2u, connection_.NumQueuedPackets());
}
-TEST_F(QuicConnectionTest, AbandonFECFromCongestionWindow) {
+TEST_P(QuicConnectionTest, AbandonFECFromCongestionWindow) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
connection_.options()->max_packets_per_fec_group = 1;
// 1 Data and 1 FEC packet.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
@@ -1389,7 +1469,10 @@ TEST_F(QuicConnectionTest, AbandonFECFromCongestionWindow) {
connection_.OnRetransmissionTimeout();
}
-TEST_F(QuicConnectionTest, DontAbandonAckedFEC) {
+TEST_P(QuicConnectionTest, DontAbandonAckedFEC) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
connection_.options()->max_packets_per_fec_group = 1;
@@ -1418,7 +1501,10 @@ TEST_F(QuicConnectionTest, DontAbandonAckedFEC) {
connection_.GetRetransmissionAlarm()->Fire();
}
-TEST_F(QuicConnectionTest, AbandonAllFEC) {
+TEST_P(QuicConnectionTest, AbandonAllFEC) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
connection_.options()->max_packets_per_fec_group = 1;
@@ -1454,7 +1540,7 @@ TEST_F(QuicConnectionTest, AbandonAllFEC) {
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
}
-TEST_F(QuicConnectionTest, FramePacking) {
+TEST_P(QuicConnectionTest, FramePacking) {
// Block the connection.
connection_.GetSendAlarm()->Set(
clock_.ApproximateNow().Add(QuicTime::Delta::FromSeconds(1)));
@@ -1477,14 +1563,19 @@ TEST_F(QuicConnectionTest, FramePacking) {
// Parse the last packet and ensure it's an ack and two stream frames from
// two different streams.
- EXPECT_EQ(3u, writer_->frame_count());
+ if (version() > QUIC_VERSION_15) {
+ EXPECT_EQ(4u, writer_->frame_count());
+ EXPECT_TRUE(writer_->stop_waiting());
+ } else {
+ EXPECT_EQ(3u, writer_->frame_count());
+ }
EXPECT_TRUE(writer_->ack());
EXPECT_EQ(2u, writer_->stream_frames()->size());
EXPECT_EQ(kStreamId3, (*writer_->stream_frames())[0].stream_id);
EXPECT_EQ(kStreamId5, (*writer_->stream_frames())[1].stream_id);
}
-TEST_F(QuicConnectionTest, FramePackingNonCryptoThenCrypto) {
+TEST_P(QuicConnectionTest, FramePackingNonCryptoThenCrypto) {
// Block the connection.
connection_.GetSendAlarm()->Set(
clock_.ApproximateNow().Add(QuicTime::Delta::FromSeconds(1)));
@@ -1512,7 +1603,7 @@ TEST_F(QuicConnectionTest, FramePackingNonCryptoThenCrypto) {
EXPECT_EQ(kCryptoStreamId, (*writer_->stream_frames())[0].stream_id);
}
-TEST_F(QuicConnectionTest, FramePackingCryptoThenNonCrypto) {
+TEST_P(QuicConnectionTest, FramePackingCryptoThenNonCrypto) {
// Block the connection.
connection_.GetSendAlarm()->Set(
clock_.ApproximateNow().Add(QuicTime::Delta::FromSeconds(1)));
@@ -1540,7 +1631,10 @@ TEST_F(QuicConnectionTest, FramePackingCryptoThenNonCrypto) {
EXPECT_EQ(kStreamId3, (*writer_->stream_frames())[0].stream_id);
}
-TEST_F(QuicConnectionTest, FramePackingFEC) {
+TEST_P(QuicConnectionTest, FramePackingFEC) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
// Enable fec.
connection_.options()->max_packets_per_fec_group = 6;
// Block the connection.
@@ -1567,7 +1661,7 @@ TEST_F(QuicConnectionTest, FramePackingFEC) {
EXPECT_EQ(0u, writer_->frame_count());
}
-TEST_F(QuicConnectionTest, FramePackingAckResponse) {
+TEST_P(QuicConnectionTest, FramePackingAckResponse) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Process a data packet to queue up a pending ack.
EXPECT_CALL(visitor_, OnStreamFrames(_)).WillOnce(Return(true));
@@ -1593,14 +1687,19 @@ TEST_F(QuicConnectionTest, FramePackingAckResponse) {
// Parse the last packet and ensure it's an ack and two stream frames from
// two different streams.
- EXPECT_EQ(3u, writer_->frame_count());
+ if (version() > QUIC_VERSION_15) {
+ EXPECT_EQ(4u, writer_->frame_count());
+ EXPECT_TRUE(writer_->stop_waiting());
+ } else {
+ EXPECT_EQ(3u, writer_->frame_count());
+ }
EXPECT_TRUE(writer_->ack());
ASSERT_EQ(2u, writer_->stream_frames()->size());
EXPECT_EQ(kStreamId3, (*writer_->stream_frames())[0].stream_id);
EXPECT_EQ(kStreamId5, (*writer_->stream_frames())[1].stream_id);
}
-TEST_F(QuicConnectionTest, FramePackingSendv) {
+TEST_P(QuicConnectionTest, FramePackingSendv) {
// Send data in 1 packet by writing multiple blocks in a single iovector
// using writev.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _));
@@ -1625,7 +1724,7 @@ TEST_F(QuicConnectionTest, FramePackingSendv) {
(frame.data.iovec()[0].iov_len)));
}
-TEST_F(QuicConnectionTest, FramePackingSendvQueued) {
+TEST_P(QuicConnectionTest, FramePackingSendvQueued) {
// Try to send two stream frames in 1 packet by using writev.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _));
@@ -1650,7 +1749,7 @@ TEST_F(QuicConnectionTest, FramePackingSendvQueued) {
EXPECT_EQ(1u, (*writer_->stream_frames())[0].stream_id);
}
-TEST_F(QuicConnectionTest, SendingZeroBytes) {
+TEST_P(QuicConnectionTest, SendingZeroBytes) {
// Send a zero byte write with a fin using writev.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _));
IOVector empty_iov;
@@ -1666,7 +1765,7 @@ TEST_F(QuicConnectionTest, SendingZeroBytes) {
EXPECT_TRUE((*writer_->stream_frames())[0].fin);
}
-TEST_F(QuicConnectionTest, OnCanWrite) {
+TEST_P(QuicConnectionTest, OnCanWrite) {
// Visitor's OnCanWrite will send data, but will have more pending writes.
EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(DoAll(
IgnoreResult(InvokeWithoutArgs(&connection_,
@@ -1688,7 +1787,7 @@ TEST_F(QuicConnectionTest, OnCanWrite) {
EXPECT_EQ(kStreamId5, (*writer_->stream_frames())[1].stream_id);
}
-TEST_F(QuicConnectionTest, RetransmitOnNack) {
+TEST_P(QuicConnectionTest, RetransmitOnNack) {
EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _));
EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(1);
@@ -1722,7 +1821,7 @@ TEST_F(QuicConnectionTest, RetransmitOnNack) {
ProcessAckPacket(&nack_two);
}
-TEST_F(QuicConnectionTest, DiscardRetransmit) {
+TEST_P(QuicConnectionTest, DiscardRetransmit) {
EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _));
EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(1);
@@ -1769,7 +1868,7 @@ TEST_F(QuicConnectionTest, DiscardRetransmit) {
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
-TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) {
+TEST_P(QuicConnectionTest, RetransmitNackedLargestObserved) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(1);
QuicPacketSequenceNumber largest_observed;
@@ -1789,7 +1888,7 @@ TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) {
ProcessAckPacket(&frame);
}
-TEST_F(QuicConnectionTest, QueueAfterTwoRTOs) {
+TEST_P(QuicConnectionTest, QueueAfterTwoRTOs) {
for (int i = 0; i < 10; ++i) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
connection_.SendStreamDataWithString(3, "foo", i * 3, !kFin, NULL);
@@ -1814,7 +1913,7 @@ TEST_F(QuicConnectionTest, QueueAfterTwoRTOs) {
connection_.OnCanWrite();
}
-TEST_F(QuicConnectionTest, WriteBlockedThenSent) {
+TEST_P(QuicConnectionTest, WriteBlockedThenSent) {
BlockOnNextWrite();
writer_->set_is_write_blocked_data_buffered(true);
connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL);
@@ -1825,7 +1924,7 @@ TEST_F(QuicConnectionTest, WriteBlockedThenSent) {
EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
}
-TEST_F(QuicConnectionTest, WriteBlockedAckedThenSent) {
+TEST_P(QuicConnectionTest, WriteBlockedAckedThenSent) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
BlockOnNextWrite();
writer_->set_is_write_blocked_data_buffered(true);
@@ -1842,7 +1941,7 @@ TEST_F(QuicConnectionTest, WriteBlockedAckedThenSent) {
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
}
-TEST_F(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) {
+TEST_P(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL);
EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
@@ -1866,7 +1965,7 @@ TEST_F(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) {
EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
}
-TEST_F(QuicConnectionTest, AlarmsWhenWriteBlocked) {
+TEST_P(QuicConnectionTest, AlarmsWhenWriteBlocked) {
// Block the connection.
BlockOnNextWrite();
connection_.SendStreamDataWithString(3, "foo", 0, !kFin, NULL);
@@ -1883,7 +1982,7 @@ TEST_F(QuicConnectionTest, AlarmsWhenWriteBlocked) {
EXPECT_EQ(1u, writer_->packets_write_attempts());
}
-TEST_F(QuicConnectionTest, NoLimitPacketsPerNack) {
+TEST_P(QuicConnectionTest, NoLimitPacketsPerNack) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
int offset = 0;
// Send packets 1 to 15.
@@ -1909,7 +2008,7 @@ TEST_F(QuicConnectionTest, NoLimitPacketsPerNack) {
}
// Test sending multiple acks from the connection to the session.
-TEST_F(QuicConnectionTest, MultipleAcks) {
+TEST_P(QuicConnectionTest, MultipleAcks) {
QuicPacketSequenceNumber last_packet;
SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1
EXPECT_EQ(1u, last_packet);
@@ -1938,7 +2037,7 @@ TEST_F(QuicConnectionTest, MultipleAcks) {
ProcessAckPacket(&frame2);
}
-TEST_F(QuicConnectionTest, DontLatchUnackedPacket) {
+TEST_P(QuicConnectionTest, DontLatchUnackedPacket) {
EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(1);
SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); // Packet 1;
@@ -1961,7 +2060,7 @@ TEST_F(QuicConnectionTest, DontLatchUnackedPacket) {
// Since this was an ack packet, we set least_unacked to 4.
EXPECT_EQ(4u, outgoing_ack()->sent_info.least_unacked);
// Check that the outgoing ack had its sequence number as least_unacked.
- EXPECT_EQ(3u, last_ack()->sent_info.least_unacked);
+ EXPECT_EQ(3u, least_unacked());
ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
.WillByDefault(Return(true));
@@ -1970,10 +2069,13 @@ TEST_F(QuicConnectionTest, DontLatchUnackedPacket) {
ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
.WillByDefault(Return(false));
SendAckPacketToPeer(); // Packet 5
- EXPECT_EQ(4u, last_ack()->sent_info.least_unacked);
+ EXPECT_EQ(4u, least_unacked());
}
-TEST_F(QuicConnectionTest, ReviveMissingPacketAfterFecPacket) {
+TEST_P(QuicConnectionTest, ReviveMissingPacketAfterFecPacket) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Don't send missing packet 1.
@@ -1982,7 +2084,10 @@ TEST_F(QuicConnectionTest, ReviveMissingPacketAfterFecPacket) {
EXPECT_EQ(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 2));
}
-TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketThenFecPacket) {
+TEST_P(QuicConnectionTest, ReviveMissingPacketAfterDataPacketThenFecPacket) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessFecProtectedPacket(1, false, kEntropyFlag);
@@ -1992,7 +2097,10 @@ TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketThenFecPacket) {
EXPECT_NE(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 2));
}
-TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketsThenFecPacket) {
+TEST_P(QuicConnectionTest, ReviveMissingPacketAfterDataPacketsThenFecPacket) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessFecProtectedPacket(1, false, !kEntropyFlag);
@@ -2004,7 +2112,10 @@ TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacketsThenFecPacket) {
EXPECT_NE(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 4));
}
-TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacket) {
+TEST_P(QuicConnectionTest, ReviveMissingPacketAfterDataPacket) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Don't send missing packet 1.
@@ -2015,7 +2126,10 @@ TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPacket) {
EXPECT_EQ(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 2));
}
-TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPackets) {
+TEST_P(QuicConnectionTest, ReviveMissingPacketAfterDataPackets) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessFecProtectedPacket(1, false, !kEntropyFlag);
@@ -2029,7 +2143,7 @@ TEST_F(QuicConnectionTest, ReviveMissingPacketAfterDataPackets) {
EXPECT_NE(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 3));
}
-TEST_F(QuicConnectionTest, RTO) {
+TEST_P(QuicConnectionTest, RTO) {
QuicTime default_retransmission_time = clock_.ApproximateNow().Add(
DefaultRetransmissionTime());
SendStreamDataToPeer(3, "foo", 0, !kFin, NULL);
@@ -2048,7 +2162,7 @@ TEST_F(QuicConnectionTest, RTO) {
EXPECT_EQ(1u, outgoing_ack()->sent_info.least_unacked);
}
-TEST_F(QuicConnectionTest, RTOWithSameEncryptionLevel) {
+TEST_P(QuicConnectionTest, RTOWithSameEncryptionLevel) {
QuicTime default_retransmission_time = clock_.ApproximateNow().Add(
DefaultRetransmissionTime());
use_tagging_decrypter();
@@ -2084,7 +2198,7 @@ TEST_F(QuicConnectionTest, RTOWithSameEncryptionLevel) {
EXPECT_EQ(0x02020202u, final_bytes_of_last_packet());
}
-TEST_F(QuicConnectionTest, SendHandshakeMessages) {
+TEST_P(QuicConnectionTest, SendHandshakeMessages) {
use_tagging_decrypter();
// A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at
// the end of the packet. We can test this to check which encrypter was used.
@@ -2115,7 +2229,7 @@ TEST_F(QuicConnectionTest, SendHandshakeMessages) {
EXPECT_EQ(0x01010101u, final_bytes_of_last_packet());
}
-TEST_F(QuicConnectionTest,
+TEST_P(QuicConnectionTest,
DropRetransmitsForNullEncryptedPacketAfterForwardSecure) {
use_tagging_decrypter();
connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01));
@@ -2139,7 +2253,7 @@ TEST_F(QuicConnectionTest,
connection_.GetRetransmissionAlarm()->Fire();
}
-TEST_F(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
+TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
use_tagging_decrypter();
connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01));
connection_.SetDefaultEncryptionLevel(ENCRYPTION_NONE);
@@ -2157,7 +2271,7 @@ TEST_F(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
connection_.RetransmitUnackedPackets(INITIAL_ENCRYPTION_ONLY);
}
-TEST_F(QuicConnectionTest, BufferNonDecryptablePackets) {
+TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
use_tagging_decrypter();
@@ -2184,7 +2298,7 @@ TEST_F(QuicConnectionTest, BufferNonDecryptablePackets) {
ProcessDataPacketAtLevel(3, false, kEntropyFlag, ENCRYPTION_INITIAL);
}
-TEST_F(QuicConnectionTest, TestRetransmitOrder) {
+TEST_P(QuicConnectionTest, TestRetransmitOrder) {
QuicByteCount first_packet_size;
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).WillOnce(
DoAll(SaveArg<2>(&first_packet_size), Return(true)));
@@ -2220,7 +2334,7 @@ TEST_F(QuicConnectionTest, TestRetransmitOrder) {
connection_.GetRetransmissionAlarm()->Fire();
}
-TEST_F(QuicConnectionTest, RetransmissionCountCalculation) {
+TEST_P(QuicConnectionTest, RetransmissionCountCalculation) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicPacketSequenceNumber original_sequence_number;
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _))
@@ -2272,7 +2386,7 @@ TEST_F(QuicConnectionTest, RetransmissionCountCalculation) {
&connection_, nack_sequence_number));
}
-TEST_F(QuicConnectionTest, SetRTOAfterWritingToSocket) {
+TEST_P(QuicConnectionTest, SetRTOAfterWritingToSocket) {
BlockOnNextWrite();
connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL);
// Make sure that RTO is not started when the packet is queued.
@@ -2284,7 +2398,7 @@ TEST_F(QuicConnectionTest, SetRTOAfterWritingToSocket) {
EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
}
-TEST_F(QuicConnectionTest, DelayRTOWithAckReceipt) {
+TEST_P(QuicConnectionTest, DelayRTOWithAckReceipt) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, NOT_RETRANSMISSION, _))
.Times(2);
@@ -2322,7 +2436,7 @@ TEST_F(QuicConnectionTest, DelayRTOWithAckReceipt) {
EXPECT_EQ(next_rto_time, expected_rto_time);
}
-TEST_F(QuicConnectionTest, TestQueued) {
+TEST_P(QuicConnectionTest, TestQueued) {
EXPECT_EQ(0u, connection_.NumQueuedPackets());
BlockOnNextWrite();
connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL);
@@ -2334,7 +2448,7 @@ TEST_F(QuicConnectionTest, TestQueued) {
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
-TEST_F(QuicConnectionTest, CloseFecGroup) {
+TEST_P(QuicConnectionTest, CloseFecGroup) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Don't send missing packet 1.
// Don't send missing packet 2.
@@ -2343,18 +2457,23 @@ TEST_F(QuicConnectionTest, CloseFecGroup) {
ASSERT_EQ(1u, connection_.NumFecGroups());
// Now send non-fec protected ack packet and close the group.
- QuicAckFrame frame = InitAckFrame(0, 5);
creator_.set_sequence_number(4);
- ProcessAckPacket(&frame);
+ if (version() > QUIC_VERSION_15) {
+ QuicStopWaitingFrame frame = InitStopWaitingFrame(5);
+ ProcessStopWaitingPacket(&frame);
+ } else {
+ QuicAckFrame frame = InitAckFrame(0, 5);
+ ProcessAckPacket(&frame);
+ }
ASSERT_EQ(0u, connection_.NumFecGroups());
}
-TEST_F(QuicConnectionTest, NoQuicCongestionFeedbackFrame) {
+TEST_P(QuicConnectionTest, NoQuicCongestionFeedbackFrame) {
SendAckPacketToPeer();
EXPECT_TRUE(last_feedback() == NULL);
}
-TEST_F(QuicConnectionTest, WithQuicCongestionFeedbackFrame) {
+TEST_P(QuicConnectionTest, WithQuicCongestionFeedbackFrame) {
QuicCongestionFeedbackFrame info;
info.type = kFixRate;
info.fix_rate.bitrate = QuicBandwidth::FromBytesPerSecond(123);
@@ -2365,14 +2484,17 @@ TEST_F(QuicConnectionTest, WithQuicCongestionFeedbackFrame) {
EXPECT_EQ(info.fix_rate.bitrate, last_feedback()->fix_rate.bitrate);
}
-TEST_F(QuicConnectionTest, UpdateQuicCongestionFeedbackFrame) {
+TEST_P(QuicConnectionTest, UpdateQuicCongestionFeedbackFrame) {
SendAckPacketToPeer();
EXPECT_CALL(*receive_algorithm_, RecordIncomingPacket(_, _, _));
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
}
-TEST_F(QuicConnectionTest, DontUpdateQuicCongestionFeedbackFrameForRevived) {
+TEST_P(QuicConnectionTest, DontUpdateQuicCongestionFeedbackFrameForRevived) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
SendAckPacketToPeer();
// Process an FEC packet, and revive the missing data packet
@@ -2381,7 +2503,7 @@ TEST_F(QuicConnectionTest, DontUpdateQuicCongestionFeedbackFrameForRevived) {
ProcessFecPacket(2, 1, true, !kEntropyFlag, NULL);
}
-TEST_F(QuicConnectionTest, InitialTimeout) {
+TEST_P(QuicConnectionTest, InitialTimeout) {
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
@@ -2404,7 +2526,7 @@ TEST_F(QuicConnectionTest, InitialTimeout) {
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
}
-TEST_F(QuicConnectionTest, TimeoutAfterSend) {
+TEST_P(QuicConnectionTest, TimeoutAfterSend) {
EXPECT_TRUE(connection_.connected());
QuicTime default_timeout = clock_.ApproximateNow().Add(
@@ -2440,7 +2562,7 @@ TEST_F(QuicConnectionTest, TimeoutAfterSend) {
EXPECT_FALSE(connection_.connected());
}
-TEST_F(QuicConnectionTest, SendScheduler) {
+TEST_P(QuicConnectionTest, SendScheduler) {
// Test that if we send a packet without delay, it is not queued.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
@@ -2452,7 +2574,7 @@ TEST_F(QuicConnectionTest, SendScheduler) {
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
-TEST_F(QuicConnectionTest, SendSchedulerDelay) {
+TEST_P(QuicConnectionTest, SendSchedulerDelay) {
// Test that if we send a packet with a delay, it ends up queued.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
@@ -2464,7 +2586,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelay) {
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
-TEST_F(QuicConnectionTest, SendSchedulerForce) {
+TEST_P(QuicConnectionTest, SendSchedulerForce) {
// Test that if we force send a packet, it is not queued.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
@@ -2476,7 +2598,7 @@ TEST_F(QuicConnectionTest, SendSchedulerForce) {
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
-TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) {
+TEST_P(QuicConnectionTest, SendSchedulerEAGAIN) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
BlockOnNextWrite();
EXPECT_CALL(*send_algorithm_,
@@ -2488,7 +2610,7 @@ TEST_F(QuicConnectionTest, SendSchedulerEAGAIN) {
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
-TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) {
+TEST_P(QuicConnectionTest, SendSchedulerDelayThenSend) {
// Test that if we send a packet with a delay, it ends up queued.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
@@ -2509,7 +2631,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) {
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
-TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
+TEST_P(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, NOT_RETRANSMISSION, _, _))
.WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_,
@@ -2541,7 +2663,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) {
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
-TEST_F(QuicConnectionTest, SendSchedulerDelayAndQueue) {
+TEST_P(QuicConnectionTest, SendSchedulerDelayAndQueue) {
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
TimeUntilSend(_, NOT_RETRANSMISSION, _, _)).WillOnce(
@@ -2557,7 +2679,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayAndQueue) {
EXPECT_EQ(2u, connection_.NumQueuedPackets());
}
-TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
+TEST_P(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
@@ -2582,7 +2704,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndSend) {
EXPECT_FALSE(connection_.GetSendAlarm()->IsSet());
}
-TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
+TEST_P(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
EXPECT_CALL(*send_algorithm_,
@@ -2603,7 +2725,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenAckAndHold) {
EXPECT_EQ(1u, connection_.NumQueuedPackets());
}
-TEST_F(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) {
+TEST_P(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) {
// TODO(ianswett): This test is unrealistic, because we would not serialize
// new data if the send algorithm said not to.
QuicPacket* packet = ConstructDataPacket(1, 0, !kEntropyFlag);
@@ -2620,7 +2742,7 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) {
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
-TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
+TEST_P(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
// All packets carry version info till version is negotiated.
size_t payload_length;
connection_.options()->max_packet_length =
@@ -2639,7 +2761,7 @@ TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
-TEST_F(QuicConnectionTest, LoopThroughSendingPackets) {
+TEST_P(QuicConnectionTest, LoopThroughSendingPackets) {
// All packets carry version info till version is negotiated.
size_t payload_length;
connection_.options()->max_packet_length =
@@ -2656,7 +2778,7 @@ TEST_F(QuicConnectionTest, LoopThroughSendingPackets) {
!kFin, NULL).bytes_consumed);
}
-TEST_F(QuicConnectionTest, SendDelayedAckOnTimer) {
+TEST_P(QuicConnectionTest, SendDelayedAckOnTimer) {
QuicTime ack_time = clock_.ApproximateNow().Add(DefaultDelayedAckTime());
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
@@ -2667,38 +2789,49 @@ TEST_F(QuicConnectionTest, SendDelayedAckOnTimer) {
// Simulate delayed ack alarm firing.
connection_.GetAckAlarm()->Fire();
// Check that ack is sent and that delayed ack alarm is reset.
- EXPECT_EQ(1u, writer_->frame_count());
+ if (version() > QUIC_VERSION_15) {
+ EXPECT_EQ(2u, writer_->frame_count());
+ EXPECT_TRUE(writer_->stop_waiting());
+ } else {
+ EXPECT_EQ(1u, writer_->frame_count());
+ }
EXPECT_TRUE(writer_->ack());
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
}
-TEST_F(QuicConnectionTest, SendDelayedAckOnSecondPacket) {
+TEST_P(QuicConnectionTest, SendDelayedAckOnSecondPacket) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
ProcessPacket(2);
// Check that ack is sent and that delayed ack alarm is reset.
- EXPECT_EQ(1u, writer_->frame_count());
+ if (version() > QUIC_VERSION_15) {
+ EXPECT_EQ(2u, writer_->frame_count());
+ EXPECT_TRUE(writer_->stop_waiting());
+ } else {
+ EXPECT_EQ(1u, writer_->frame_count());
+ }
EXPECT_TRUE(writer_->ack());
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
}
-TEST_F(QuicConnectionTest, NoAckOnOldNacks) {
+TEST_P(QuicConnectionTest, NoAckOnOldNacks) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Drop one packet, triggering a sequence of acks.
ProcessPacket(2);
- EXPECT_EQ(1u, writer_->frame_count());
+ size_t frames_per_ack = version() > QUIC_VERSION_15 ? 2 : 1;
+ EXPECT_EQ(frames_per_ack, writer_->frame_count());
EXPECT_TRUE(writer_->ack());
writer_->Reset();
ProcessPacket(3);
- EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(frames_per_ack, writer_->frame_count());
EXPECT_TRUE(writer_->ack());
writer_->Reset();
ProcessPacket(4);
- EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(frames_per_ack, writer_->frame_count());
EXPECT_TRUE(writer_->ack());
writer_->Reset();
ProcessPacket(5);
- EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(frames_per_ack, writer_->frame_count());
EXPECT_TRUE(writer_->ack());
// Now only set the timer on the 6th packet, instead of sending another ack.
writer_->Reset();
@@ -2707,18 +2840,23 @@ TEST_F(QuicConnectionTest, NoAckOnOldNacks) {
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
}
-TEST_F(QuicConnectionTest, SendDelayedAckOnOutgoingPacket) {
+TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingPacket) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
connection_.SendStreamDataWithString(kStreamId3, "foo", 0, !kFin, NULL);
// Check that ack is bundled with outgoing data and that delayed ack
// alarm is reset.
- EXPECT_EQ(2u, writer_->frame_count());
+ if (version() > QUIC_VERSION_15) {
+ EXPECT_EQ(3u, writer_->frame_count());
+ EXPECT_TRUE(writer_->stop_waiting());
+ } else {
+ EXPECT_EQ(2u, writer_->frame_count());
+ }
EXPECT_TRUE(writer_->ack());
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
}
-TEST_F(QuicConnectionTest, DontSendDelayedAckOnOutgoingCryptoPacket) {
+TEST_P(QuicConnectionTest, DontSendDelayedAckOnOutgoingCryptoPacket) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
connection_.SendStreamDataWithString(kCryptoStreamId, "foo", 0, !kFin, NULL);
@@ -2728,7 +2866,7 @@ TEST_F(QuicConnectionTest, DontSendDelayedAckOnOutgoingCryptoPacket) {
EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
}
-TEST_F(QuicConnectionTest, BundleAckWithDataOnIncomingAck) {
+TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
connection_.SendStreamDataWithString(kStreamId3, "foo", 0, !kFin, NULL);
connection_.SendStreamDataWithString(kStreamId3, "foo", 3, !kFin, NULL);
@@ -2768,13 +2906,18 @@ TEST_F(QuicConnectionTest, BundleAckWithDataOnIncomingAck) {
// Check that ack is bundled with outgoing data and the delayed ack
// alarm is reset.
- EXPECT_EQ(2u, writer_->frame_count());
+ if (version() > QUIC_VERSION_15) {
+ EXPECT_EQ(3u, writer_->frame_count());
+ EXPECT_TRUE(writer_->stop_waiting());
+ } else {
+ EXPECT_EQ(2u, writer_->frame_count());
+ }
EXPECT_TRUE(writer_->ack());
EXPECT_EQ(1u, writer_->stream_frames()->size());
EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
}
-TEST_F(QuicConnectionTest, NoAckForClose) {
+TEST_P(QuicConnectionTest, NoAckForClose) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessPacket(1);
EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(0);
@@ -2783,7 +2926,7 @@ TEST_F(QuicConnectionTest, NoAckForClose) {
ProcessClosePacket(2, 0);
}
-TEST_F(QuicConnectionTest, SendWhenDisconnected) {
+TEST_P(QuicConnectionTest, SendWhenDisconnected) {
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, false));
connection_.CloseConnection(QUIC_PEER_GOING_AWAY, false);
@@ -2794,7 +2937,7 @@ TEST_F(QuicConnectionTest, SendWhenDisconnected) {
ENCRYPTION_NONE, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA);
}
-TEST_F(QuicConnectionTest, PublicReset) {
+TEST_P(QuicConnectionTest, PublicReset) {
QuicPublicResetPacket header;
header.public_header.guid = guid_;
header.public_header.reset_flag = true;
@@ -2806,7 +2949,7 @@ TEST_F(QuicConnectionTest, PublicReset) {
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *packet);
}
-TEST_F(QuicConnectionTest, GoAway) {
+TEST_P(QuicConnectionTest, GoAway) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicGoAwayFrame goaway;
@@ -2817,7 +2960,10 @@ TEST_F(QuicConnectionTest, GoAway) {
ProcessGoAwayPacket(&goaway);
}
-TEST_F(QuicConnectionTest, WindowUpdate) {
+TEST_P(QuicConnectionTest, WindowUpdate) {
+ if (version() < QUIC_VERSION_14) {
+ return;
+ }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicWindowUpdateFrame window_update;
@@ -2827,7 +2973,10 @@ TEST_F(QuicConnectionTest, WindowUpdate) {
ProcessFramePacket(QuicFrame(&window_update));
}
-TEST_F(QuicConnectionTest, Blocked) {
+TEST_P(QuicConnectionTest, Blocked) {
+ if (version() < QUIC_VERSION_14) {
+ return;
+ }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicBlockedFrame blocked;
@@ -2836,7 +2985,7 @@ TEST_F(QuicConnectionTest, Blocked) {
ProcessFramePacket(QuicFrame(&blocked));
}
-TEST_F(QuicConnectionTest, InvalidPacket) {
+TEST_P(QuicConnectionTest, InvalidPacket) {
EXPECT_CALL(visitor_,
OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, false));
QuicEncryptedPacket encrypted(NULL, 0);
@@ -2846,16 +2995,21 @@ TEST_F(QuicConnectionTest, InvalidPacket) {
EXPECT_EQ("Unable to read public flags.", last_close()->error_details);
}
-TEST_F(QuicConnectionTest, MissingPacketsBeforeLeastUnacked) {
- QuicAckFrame ack = InitAckFrame(0, 4);
+TEST_P(QuicConnectionTest, MissingPacketsBeforeLeastUnacked) {
// Set the sequence number of the ack packet to be least unacked (4).
creator_.set_sequence_number(3);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- ProcessAckPacket(&ack);
+ if (version() > QUIC_VERSION_15) {
+ QuicStopWaitingFrame frame = InitStopWaitingFrame(4);
+ ProcessStopWaitingPacket(&frame);
+ } else {
+ QuicAckFrame ack = InitAckFrame(0, 4);
+ ProcessAckPacket(&ack);
+ }
EXPECT_TRUE(outgoing_ack()->received_info.missing_packets.empty());
}
-TEST_F(QuicConnectionTest, ReceivedEntropyHashCalculation) {
+TEST_P(QuicConnectionTest, ReceivedEntropyHashCalculation) {
EXPECT_CALL(visitor_, OnStreamFrames(_)).WillRepeatedly(Return(true));
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessDataPacket(1, 1, kEntropyFlag);
@@ -2865,7 +3019,10 @@ TEST_F(QuicConnectionTest, ReceivedEntropyHashCalculation) {
EXPECT_EQ(146u, outgoing_ack()->received_info.entropy_hash);
}
-TEST_F(QuicConnectionTest, ReceivedEntropyHashCalculationHalfFEC) {
+TEST_P(QuicConnectionTest, ReceivedEntropyHashCalculationHalfFEC) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
// FEC packets should not change the entropy hash calculation.
EXPECT_CALL(visitor_, OnStreamFrames(_)).WillRepeatedly(Return(true));
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -2876,7 +3033,7 @@ TEST_F(QuicConnectionTest, ReceivedEntropyHashCalculationHalfFEC) {
EXPECT_EQ(146u, outgoing_ack()->received_info.entropy_hash);
}
-TEST_F(QuicConnectionTest, UpdateEntropyForReceivedPackets) {
+TEST_P(QuicConnectionTest, UpdateEntropyForReceivedPackets) {
EXPECT_CALL(visitor_, OnStreamFrames(_)).WillRepeatedly(Return(true));
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessDataPacket(1, 1, kEntropyFlag);
@@ -2884,20 +3041,28 @@ TEST_F(QuicConnectionTest, UpdateEntropyForReceivedPackets) {
ProcessDataPacket(4, 1, !kEntropyFlag);
EXPECT_EQ(34u, outgoing_ack()->received_info.entropy_hash);
// Make 4th packet my least unacked, and update entropy for 2, 3 packets.
- QuicAckFrame ack = InitAckFrame(0, 4);
- QuicPacketEntropyHash kRandomEntropyHash = 129u;
- ack.sent_info.entropy_hash = kRandomEntropyHash;
creator_.set_sequence_number(5);
QuicPacketEntropyHash six_packet_entropy_hash = 0;
- if (ProcessAckPacket(&ack)) {
- six_packet_entropy_hash = 1 << 6;
+ QuicPacketEntropyHash kRandomEntropyHash = 129u;
+ if (version() > QUIC_VERSION_15) {
+ QuicStopWaitingFrame frame = InitStopWaitingFrame(4);
+ frame.entropy_hash = kRandomEntropyHash;
+ if (ProcessStopWaitingPacket(&frame)) {
+ six_packet_entropy_hash = 1 << 6;
+ }
+ } else {
+ QuicAckFrame ack = InitAckFrame(0, 4);
+ ack.sent_info.entropy_hash = kRandomEntropyHash;
+ if (ProcessAckPacket(&ack)) {
+ six_packet_entropy_hash = 1 << 6;
+ }
}
EXPECT_EQ((kRandomEntropyHash + (1 << 5) + six_packet_entropy_hash),
outgoing_ack()->received_info.entropy_hash);
}
-TEST_F(QuicConnectionTest, UpdateEntropyHashUptoCurrentPacket) {
+TEST_P(QuicConnectionTest, UpdateEntropyHashUptoCurrentPacket) {
EXPECT_CALL(visitor_, OnStreamFrames(_)).WillRepeatedly(Return(true));
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessDataPacket(1, 1, kEntropyFlag);
@@ -2907,9 +3072,16 @@ TEST_F(QuicConnectionTest, UpdateEntropyHashUptoCurrentPacket) {
creator_.set_sequence_number(22);
QuicPacketEntropyHash kRandomEntropyHash = 85u;
// Current packet is the least unacked packet.
- QuicAckFrame ack = InitAckFrame(0, 23);
- ack.sent_info.entropy_hash = kRandomEntropyHash;
- QuicPacketEntropyHash ack_entropy_hash = ProcessAckPacket(&ack);
+ QuicPacketEntropyHash ack_entropy_hash;
+ if (version() > QUIC_VERSION_15) {
+ QuicStopWaitingFrame frame = InitStopWaitingFrame(23);
+ frame.entropy_hash = kRandomEntropyHash;
+ ack_entropy_hash = ProcessStopWaitingPacket(&frame);
+ } else {
+ QuicAckFrame ack = InitAckFrame(0, 23);
+ ack.sent_info.entropy_hash = kRandomEntropyHash;
+ ack_entropy_hash = ProcessAckPacket(&ack);
+ }
EXPECT_EQ((kRandomEntropyHash + ack_entropy_hash),
outgoing_ack()->received_info.entropy_hash);
ProcessDataPacket(25, 1, kEntropyFlag);
@@ -2917,7 +3089,7 @@ TEST_F(QuicConnectionTest, UpdateEntropyHashUptoCurrentPacket) {
outgoing_ack()->received_info.entropy_hash);
}
-TEST_F(QuicConnectionTest, EntropyCalculationForTruncatedAck) {
+TEST_P(QuicConnectionTest, EntropyCalculationForTruncatedAck) {
EXPECT_CALL(visitor_, OnStreamFrames(_)).WillRepeatedly(Return(true));
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
QuicPacketEntropyHash entropy[51];
@@ -2943,7 +3115,7 @@ TEST_F(QuicConnectionTest, EntropyCalculationForTruncatedAck) {
}
}
-TEST_F(QuicConnectionTest, CheckSentEntropyHash) {
+TEST_P(QuicConnectionTest, CheckSentEntropyHash) {
creator_.set_sequence_number(1);
SequenceNumberSet missing_packets;
QuicPacketEntropyHash entropy_hash = 0;
@@ -2972,7 +3144,8 @@ TEST_F(QuicConnectionTest, CheckSentEntropyHash) {
<< "";
}
-TEST_F(QuicConnectionTest, ServerSendsVersionNegotiationPacket) {
+TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacket) {
+ connection_.SetSupportedVersions(QuicSupportedVersions());
framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED);
QuicPacketHeader header;
@@ -2992,13 +3165,13 @@ TEST_F(QuicConnectionTest, ServerSendsVersionNegotiationPacket) {
scoped_ptr<QuicEncryptedPacket> encrypted(
framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet));
- framer_.set_version(QuicVersionMax());
+ framer_.set_version(version());
connection_.set_is_server(true);
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
EXPECT_TRUE(writer_->version_negotiation_packet() != NULL);
size_t num_versions = arraysize(kSupportedQuicVersions);
- EXPECT_EQ(num_versions,
+ ASSERT_EQ(num_versions,
writer_->version_negotiation_packet()->versions.size());
// We expect all versions in kSupportedQuicVersions to be
@@ -3009,7 +3182,8 @@ TEST_F(QuicConnectionTest, ServerSendsVersionNegotiationPacket) {
}
}
-TEST_F(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) {
+TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) {
+ connection_.SetSupportedVersions(QuicSupportedVersions());
framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED);
QuicPacketHeader header;
@@ -3029,7 +3203,7 @@ TEST_F(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) {
scoped_ptr<QuicEncryptedPacket> encrypted(
framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet));
- framer_.set_version(QuicVersionMax());
+ framer_.set_version(version());
connection_.set_is_server(true);
BlockOnNextWrite();
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
@@ -3041,7 +3215,7 @@ TEST_F(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) {
EXPECT_TRUE(writer_->version_negotiation_packet() != NULL);
size_t num_versions = arraysize(kSupportedQuicVersions);
- EXPECT_EQ(num_versions,
+ ASSERT_EQ(num_versions,
writer_->version_negotiation_packet()->versions.size());
// We expect all versions in kSupportedQuicVersions to be
@@ -3052,8 +3226,9 @@ TEST_F(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) {
}
}
-TEST_F(QuicConnectionTest,
+TEST_P(QuicConnectionTest,
ServerSendsVersionNegotiationPacketSocketBlockedDataBuffered) {
+ connection_.SetSupportedVersions(QuicSupportedVersions());
framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED);
QuicPacketHeader header;
@@ -3073,7 +3248,7 @@ TEST_F(QuicConnectionTest,
scoped_ptr<QuicEncryptedPacket> encrypted(
framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet));
- framer_.set_version(QuicVersionMax());
+ framer_.set_version(version());
connection_.set_is_server(true);
BlockOnNextWrite();
writer_->set_is_write_blocked_data_buffered(true);
@@ -3082,7 +3257,7 @@ TEST_F(QuicConnectionTest,
EXPECT_FALSE(connection_.HasQueuedData());
}
-TEST_F(QuicConnectionTest, ClientHandlesVersionNegotiation) {
+TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) {
// Start out with some unsupported version.
QuicConnectionPeer::GetFramer(&connection_)->set_version_for_tests(
QUIC_VERSION_UNSUPPORTED);
@@ -3124,7 +3299,7 @@ TEST_F(QuicConnectionTest, ClientHandlesVersionNegotiation) {
QuicConnectionPeer::GetPacketCreator(&connection_)));
}
-TEST_F(QuicConnectionTest, BadVersionNegotiation) {
+TEST_P(QuicConnectionTest, BadVersionNegotiation) {
QuicPacketHeader header;
header.public_header.guid = guid_;
header.public_header.reset_flag = false;
@@ -3150,7 +3325,7 @@ TEST_F(QuicConnectionTest, BadVersionNegotiation) {
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
}
-TEST_F(QuicConnectionTest, CheckSendStats) {
+TEST_P(QuicConnectionTest, CheckSendStats) {
EXPECT_CALL(*send_algorithm_,
OnPacketSent(_, _, _, NOT_RETRANSMISSION, _));
connection_.SendStreamDataWithString(3, "first", 0, !kFin, NULL);
@@ -3203,7 +3378,10 @@ TEST_F(QuicConnectionTest, CheckSendStats) {
EXPECT_EQ(1u, stats.rto_count);
}
-TEST_F(QuicConnectionTest, CheckReceiveStats) {
+TEST_P(QuicConnectionTest, CheckReceiveStats) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
size_t received_bytes = 0;
@@ -3226,7 +3404,7 @@ TEST_F(QuicConnectionTest, CheckReceiveStats) {
EXPECT_EQ(1u, stats.packets_dropped);
}
-TEST_F(QuicConnectionTest, TestFecGroupLimits) {
+TEST_P(QuicConnectionTest, TestFecGroupLimits) {
// Create and return a group for 1.
ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 1) != NULL);
@@ -3248,7 +3426,7 @@ TEST_F(QuicConnectionTest, TestFecGroupLimits) {
ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 3) == NULL);
}
-TEST_F(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) {
+TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) {
// Construct a packet with stream frame and connection close frame.
header_.public_header.guid = guid_;
header_.packet_sequence_number = 1;
@@ -3279,7 +3457,7 @@ TEST_F(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) {
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
}
-TEST_F(QuicConnectionTest, DontProcessStreamFrameAndIgnoreCloseFrame) {
+TEST_P(QuicConnectionTest, DontProcessStreamFrameAndIgnoreCloseFrame) {
// Construct a packet with stream frame, ack frame,
// and connection close frame.
header_.public_header.guid = guid_;
@@ -3310,7 +3488,8 @@ TEST_F(QuicConnectionTest, DontProcessStreamFrameAndIgnoreCloseFrame) {
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
}
-TEST_F(QuicConnectionTest, SelectMutualVersion) {
+TEST_P(QuicConnectionTest, SelectMutualVersion) {
+ connection_.SetSupportedVersions(QuicSupportedVersions());
// Set the connection to speak the lowest quic version.
connection_.set_version(QuicVersionMin());
EXPECT_EQ(QuicVersionMin(), connection_.version());
@@ -3339,7 +3518,7 @@ TEST_F(QuicConnectionTest, SelectMutualVersion) {
EXPECT_FALSE(connection_.SelectMutualVersion(unsupported_version));
}
-TEST_F(QuicConnectionTest, ConnectionCloseWhenWritable) {
+TEST_P(QuicConnectionTest, ConnectionCloseWhenWritable) {
EXPECT_FALSE(writer_->IsWriteBlocked());
// Send a packet.
@@ -3351,14 +3530,14 @@ TEST_F(QuicConnectionTest, ConnectionCloseWhenWritable) {
EXPECT_EQ(2u, writer_->packets_write_attempts());
}
-TEST_F(QuicConnectionTest, ConnectionCloseGettingWriteBlocked) {
+TEST_P(QuicConnectionTest, ConnectionCloseGettingWriteBlocked) {
BlockOnNextWrite();
TriggerConnectionClose();
EXPECT_EQ(1u, writer_->packets_write_attempts());
EXPECT_TRUE(writer_->IsWriteBlocked());
}
-TEST_F(QuicConnectionTest, ConnectionCloseWhenWriteBlocked) {
+TEST_P(QuicConnectionTest, ConnectionCloseWhenWriteBlocked) {
BlockOnNextWrite();
connection_.SendStreamDataWithString(1, "foo", 0, !kFin, NULL);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
@@ -3368,7 +3547,7 @@ TEST_F(QuicConnectionTest, ConnectionCloseWhenWriteBlocked) {
EXPECT_EQ(1u, writer_->packets_write_attempts());
}
-TEST_F(QuicConnectionTest, AckNotifierTriggerCallback) {
+TEST_P(QuicConnectionTest, AckNotifierTriggerCallback) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Create a delegate which we expect to be called.
@@ -3385,7 +3564,7 @@ TEST_F(QuicConnectionTest, AckNotifierTriggerCallback) {
ProcessAckPacket(&frame);
}
-TEST_F(QuicConnectionTest, AckNotifierFailToTriggerCallback) {
+TEST_P(QuicConnectionTest, AckNotifierFailToTriggerCallback) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Create a delegate which we don't expect to be called.
@@ -3412,7 +3591,7 @@ TEST_F(QuicConnectionTest, AckNotifierFailToTriggerCallback) {
ProcessAckPacket(&frame);
}
-TEST_F(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) {
+TEST_P(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) {
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
// Create a delegate which we expect to be called.
@@ -3445,7 +3624,10 @@ TEST_F(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) {
// TODO(rjshade): Add a similar test that FEC recovery on peer (and resulting
// ACK) triggers notification on our end.
-TEST_F(QuicConnectionTest, AckNotifierCallbackAfterFECRecovery) {
+TEST_P(QuicConnectionTest, AckNotifierCallbackAfterFECRecovery) {
+ if (version() < QUIC_VERSION_15) {
+ return;
+ }
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
EXPECT_CALL(visitor_, OnCanWrite());
@@ -3524,6 +3706,9 @@ class MockQuicConnectionDebugVisitor
MOCK_METHOD1(OnCongestionFeedbackFrame,
void(const QuicCongestionFeedbackFrame&));
+ MOCK_METHOD1(OnStopWaitingFrame,
+ void(const QuicStopWaitingFrame&));
+
MOCK_METHOD1(OnRstStreamFrame,
void(const QuicRstStreamFrame&));
@@ -3540,7 +3725,7 @@ class MockQuicConnectionDebugVisitor
void(const QuicPacketHeader&, StringPiece payload));
};
-TEST_F(QuicConnectionTest, OnPacketHeaderDebugVisitor) {
+TEST_P(QuicConnectionTest, OnPacketHeaderDebugVisitor) {
QuicPacketHeader header;
scoped_ptr<MockQuicConnectionDebugVisitor>
@@ -3550,17 +3735,43 @@ TEST_F(QuicConnectionTest, OnPacketHeaderDebugVisitor) {
connection_.OnPacketHeader(header);
}
-TEST_F(QuicConnectionTest, Pacing) {
+TEST_P(QuicConnectionTest, Pacing) {
ValueRestore<bool> old_flag(&FLAGS_enable_quic_pacing, true);
TestConnection server(guid_, IPEndPoint(), helper_.get(), writer_.get(),
- true);
+ true, version());
TestConnection client(guid_, IPEndPoint(), helper_.get(), writer_.get(),
- false);
+ false, version());
EXPECT_TRUE(client.sent_packet_manager().using_pacing());
EXPECT_FALSE(server.sent_packet_manager().using_pacing());
}
+TEST_P(QuicConnectionTest, ControlFramesInstigateAcks) {
+ if (version() < QUIC_VERSION_14) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ // Send a WINDOW_UPDATE frame.
+ QuicWindowUpdateFrame window_update;
+ window_update.stream_id = 3;
+ window_update.byte_offset = 1234;
+ EXPECT_CALL(visitor_, OnWindowUpdateFrames(_));
+ ProcessFramePacket(QuicFrame(&window_update));
+
+ // Ensure that this has caused the ACK alarm to be set.
+ QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
+ EXPECT_TRUE(ack_alarm->IsSet());
+
+ // Cancel alarm, and try again with BLOCKED frame.
+ ack_alarm->Cancel();
+ QuicBlockedFrame blocked;
+ blocked.stream_id = 3;
+ EXPECT_CALL(visitor_, OnBlockedFrames(_));
+ ProcessFramePacket(QuicFrame(&blocked));
+ EXPECT_TRUE(ack_alarm->IsSet());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 90d9a89..28491db 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -198,6 +198,13 @@ size_t QuicFramer::GetMinAckFrameSize(
}
// static
+size_t QuicFramer::GetStopWaitingFrameSize(
+ QuicSequenceNumberLength sequence_number_length) {
+ return kQuicFrameTypeSize + kQuicEntropyHashSize +
+ sequence_number_length;
+}
+
+// static
size_t QuicFramer::GetMinRstStreamFrameSize(QuicVersion quic_version) {
if (quic_version > QUIC_VERSION_13) {
return kQuicFrameTypeSize + kQuicMaxStreamIdSize +
@@ -374,9 +381,21 @@ SerializedPacket QuicFramer::BuildDataPacket(
}
break;
case CONGESTION_FEEDBACK_FRAME:
- if (!AppendQuicCongestionFeedbackFrame(
+ if (!AppendCongestionFeedbackFrame(
*frame.congestion_feedback_frame, &writer)) {
- LOG(DFATAL) << "AppendQuicCongestionFeedbackFrame failed";
+ LOG(DFATAL) << "AppendCongestionFeedbackFrame failed";
+ return kNoPacket;
+ }
+ break;
+ case STOP_WAITING_FRAME:
+ if (quic_version_ <= QUIC_VERSION_15) {
+ LOG(DFATAL) << "Attempt to add a StopWaitingFrame in "
+ << QuicVersionToString(quic_version_);
+ return kNoPacket;
+ }
+ if (!AppendStopWaitingFrame(
+ header, *frame.stop_waiting_frame, &writer)) {
+ LOG(DFATAL) << "AppendStopWaitingFrame failed";
return kNoPacket;
}
break;
@@ -1228,6 +1247,24 @@ bool QuicFramer::ProcessFrameData(const QuicPacketHeader& header) {
continue;
}
+ case STOP_WAITING_FRAME: {
+ if (quic_version_ <= QUIC_VERSION_15) {
+ LOG(DFATAL) << "Trying to read a StopWaiting in "
+ << QuicVersionToString(quic_version_);
+ return RaiseError(QUIC_INTERNAL_ERROR);
+ }
+ QuicStopWaitingFrame stop_waiting_frame;
+ if (!ProcessStopWaitingFrame(header, &stop_waiting_frame)) {
+ return RaiseError(QUIC_INVALID_STOP_WAITING_DATA);
+ }
+ if (!visitor_->OnStopWaitingFrame(stop_waiting_frame)) {
+ DVLOG(1) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+
default:
set_detailed_error("Illegal frame type.");
DLOG(WARNING) << "Illegal frame type: "
@@ -1298,8 +1335,10 @@ bool QuicFramer::ProcessStreamFrame(uint8 frame_type,
bool QuicFramer::ProcessAckFrame(const QuicPacketHeader& header,
uint8 frame_type,
QuicAckFrame* frame) {
- if (!ProcessSentInfo(header, &frame->sent_info)) {
- return false;
+ if (quic_version_ <= QUIC_VERSION_15) {
+ if (!ProcessStopWaitingFrame(header, &frame->sent_info)) {
+ return false;
+ }
}
if (!ProcessReceivedInfo(frame_type, &frame->received_info)) {
return false;
@@ -1401,9 +1440,9 @@ bool QuicFramer::ProcessReceivedInfo(uint8 frame_type,
return true;
}
-bool QuicFramer::ProcessSentInfo(const QuicPacketHeader& header,
- SentPacketInfo* sent_info) {
- if (!reader_->ReadBytes(&sent_info->entropy_hash, 1)) {
+bool QuicFramer::ProcessStopWaitingFrame(const QuicPacketHeader& header,
+ QuicStopWaitingFrame* stop_waiting) {
+ if (!reader_->ReadBytes(&stop_waiting->entropy_hash, 1)) {
set_detailed_error("Unable to read entropy hash for sent packets.");
return false;
}
@@ -1415,7 +1454,7 @@ bool QuicFramer::ProcessSentInfo(const QuicPacketHeader& header,
return false;
}
DCHECK_GE(header.packet_sequence_number, least_unacked_delta);
- sent_info->least_unacked =
+ stop_waiting->least_unacked =
header.packet_sequence_number - least_unacked_delta;
return true;
@@ -1861,6 +1900,8 @@ size_t QuicFramer::ComputeFrameLength(
}
return len;
}
+ case STOP_WAITING_FRAME:
+ return GetStopWaitingFrameSize(sequence_number_length);
case RST_STREAM_FRAME:
return GetMinRstStreamFrameSize(quic_version_) +
frame.rst_stream_frame->error_details.size();
@@ -1987,7 +2028,7 @@ bool QuicFramer::AppendStreamFrame(
// static
void QuicFramer::set_version(const QuicVersion version) {
- DCHECK(IsSupportedVersion(version));
+ DCHECK(IsSupportedVersion(version)) << QuicVersionToString(version);
quic_version_ = version;
}
@@ -2040,27 +2081,10 @@ bool QuicFramer::AppendAckFrameAndTypeByte(
return false;
}
- // TODO(satyamshekhar): Decide how often we really should send this
- // entropy_hash update.
- if (!writer->WriteUInt8(frame.sent_info.entropy_hash)) {
- return false;
- }
-
- DCHECK_GE(header.packet_sequence_number, frame.sent_info.least_unacked);
- const QuicPacketSequenceNumber least_unacked_delta =
- header.packet_sequence_number - frame.sent_info.least_unacked;
- const QuicPacketSequenceNumber length_shift =
- header.public_header.sequence_number_length * 8;
- if (least_unacked_delta >> length_shift > 0) {
- LOG(DFATAL) << "sequence_number_length "
- << header.public_header.sequence_number_length
- << " is too small for least_unacked_delta: "
- << least_unacked_delta;
- return false;
- }
- if (!AppendPacketSequenceNumber(header.public_header.sequence_number_length,
- least_unacked_delta, writer)) {
- return false;
+ if (quic_version_ <= QUIC_VERSION_15) {
+ if (!AppendStopWaitingFrame(header, frame.sent_info, writer)) {
+ return false;
+ }
}
const ReceivedPacketInfo& received_info = frame.received_info;
@@ -2160,7 +2184,7 @@ bool QuicFramer::AppendAckFrameAndTypeByte(
return true;
}
-bool QuicFramer::AppendQuicCongestionFeedbackFrame(
+bool QuicFramer::AppendCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame,
QuicDataWriter* writer) {
if (!writer->WriteBytes(&frame.type, 1)) {
@@ -2255,6 +2279,37 @@ bool QuicFramer::AppendQuicCongestionFeedbackFrame(
return true;
}
+bool QuicFramer::AppendStopWaitingFrame(
+ const QuicPacketHeader& header,
+ const QuicStopWaitingFrame& frame,
+ QuicDataWriter* writer) {
+ DCHECK_GE(header.packet_sequence_number, frame.least_unacked);
+ const QuicPacketSequenceNumber least_unacked_delta =
+ header.packet_sequence_number - frame.least_unacked;
+ const QuicPacketSequenceNumber length_shift =
+ header.public_header.sequence_number_length * 8;
+ if (!writer->WriteUInt8(frame.entropy_hash)) {
+ LOG(DFATAL) << " hash failed";
+ return false;
+ }
+
+ if (least_unacked_delta >> length_shift > 0) {
+ LOG(DFATAL) << "sequence_number_length "
+ << header.public_header.sequence_number_length
+ << " is too small for least_unacked_delta: "
+ << least_unacked_delta;
+ return false;
+ }
+ if (!AppendPacketSequenceNumber(header.public_header.sequence_number_length,
+ least_unacked_delta, writer)) {
+ LOG(DFATAL) << " seq failed: "
+ << header.public_header.sequence_number_length;
+ return false;
+ }
+
+ return true;
+}
+
bool QuicFramer::AppendRstStreamFrame(
const QuicRstStreamFrame& frame,
QuicDataWriter* writer) {
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index 2283533..6704602 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -113,6 +113,9 @@ class NET_EXPORT_PRIVATE QuicFramerVisitorInterface {
virtual bool OnCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame) = 0;
+ // Called when a StopWaitingFrame has been parsed.
+ virtual bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) = 0;
+
// Called when a RstStreamFrame has been parsed.
virtual bool OnRstStreamFrame(const QuicRstStreamFrame& frame) = 0;
@@ -248,6 +251,9 @@ class NET_EXPORT_PRIVATE QuicFramer {
QuicVersion version,
QuicSequenceNumberLength sequence_number_length,
QuicSequenceNumberLength largest_observed_length);
+ // Size in bytes of a stop waiting frame.
+ static size_t GetStopWaitingFrameSize(
+ QuicSequenceNumberLength sequence_number_length);
// Size in bytes of all reset stream frame without the error details.
static size_t GetMinRstStreamFrameSize(QuicVersion quic_version);
// Size in bytes of all connection close frame fields without the error
@@ -401,8 +407,8 @@ class NET_EXPORT_PRIVATE QuicFramer {
uint8 frame_type,
QuicAckFrame* frame);
bool ProcessReceivedInfo(uint8 frame_type, ReceivedPacketInfo* received_info);
- bool ProcessSentInfo(const QuicPacketHeader& public_header,
- SentPacketInfo* sent_info);
+ bool ProcessStopWaitingFrame(const QuicPacketHeader& public_header,
+ QuicStopWaitingFrame* stop_waiting);
bool ProcessQuicCongestionFeedbackFrame(
QuicCongestionFeedbackFrame* congestion_feedback);
bool ProcessRstStreamFrame(QuicRstStreamFrame* frame);
@@ -452,9 +458,11 @@ class NET_EXPORT_PRIVATE QuicFramer {
bool AppendAckFrameAndTypeByte(const QuicPacketHeader& header,
const QuicAckFrame& frame,
QuicDataWriter* builder);
- bool AppendQuicCongestionFeedbackFrame(
- const QuicCongestionFeedbackFrame& frame,
- QuicDataWriter* builder);
+ bool AppendCongestionFeedbackFrame(const QuicCongestionFeedbackFrame& frame,
+ QuicDataWriter* builder);
+ bool AppendStopWaitingFrame(const QuicPacketHeader& header,
+ const QuicStopWaitingFrame& frame,
+ QuicDataWriter* builder);
bool AppendRstStreamFrame(const QuicRstStreamFrame& frame,
QuicDataWriter* builder);
bool AppendConnectionCloseFrame(const QuicConnectionCloseFrame& frame,
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index f9c2de7..870eda0 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -211,13 +211,14 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface {
STLDeleteElements(&stream_frames_);
STLDeleteElements(&ack_frames_);
STLDeleteElements(&congestion_feedback_frames_);
+ STLDeleteElements(&stop_waiting_frames_);
STLDeleteElements(&fec_data_);
}
virtual void OnError(QuicFramer* f) OVERRIDE {
DVLOG(1) << "QuicFramer Error: " << QuicUtils::ErrorToString(f->error())
<< " (" << f->error() << ")";
- error_count_++;
+ ++error_count_;
}
virtual void OnPacket() OVERRIDE {}
@@ -233,12 +234,12 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface {
}
virtual void OnRevivedPacket() OVERRIDE {
- revived_packets_++;
+ ++revived_packets_;
}
virtual bool OnProtocolVersionMismatch(QuicVersion version) OVERRIDE {
DVLOG(1) << "QuicFramer Version Mismatch, version: " << version;
- version_mismatch_++;
+ ++version_mismatch_;
return true;
}
@@ -254,13 +255,13 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface {
}
virtual bool OnPacketHeader(const QuicPacketHeader& header) OVERRIDE {
- packet_count_++;
+ ++packet_count_;
header_.reset(new QuicPacketHeader(header));
return accept_packet_;
}
virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE {
- frame_count_++;
+ ++frame_count_;
stream_frames_.push_back(new QuicStreamFrame(frame));
return true;
}
@@ -270,26 +271,32 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface {
}
virtual bool OnAckFrame(const QuicAckFrame& frame) OVERRIDE {
- frame_count_++;
+ ++frame_count_;
ack_frames_.push_back(new QuicAckFrame(frame));
return true;
}
virtual bool OnCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame) OVERRIDE {
- frame_count_++;
+ ++frame_count_;
congestion_feedback_frames_.push_back(
new QuicCongestionFeedbackFrame(frame));
return true;
}
+ virtual bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) OVERRIDE {
+ ++frame_count_;
+ stop_waiting_frames_.push_back(new QuicStopWaitingFrame(frame));
+ return true;
+ }
+
virtual void OnFecData(const QuicFecData& fec) OVERRIDE {
- fec_count_++;
+ ++fec_count_;
fec_data_.push_back(new QuicFecData(fec));
}
virtual void OnPacketComplete() OVERRIDE {
- complete_packets_++;
+ ++complete_packets_;
}
virtual bool OnRstStreamFrame(const QuicRstStreamFrame& frame) OVERRIDE {
@@ -337,6 +344,7 @@ class TestQuicVisitor : public ::net::QuicFramerVisitorInterface {
vector<QuicStreamFrame*> stream_frames_;
vector<QuicAckFrame*> ack_frames_;
vector<QuicCongestionFeedbackFrame*> congestion_feedback_frames_;
+ vector<QuicStopWaitingFrame*> stop_waiting_frames_;
vector<QuicFecData*> fec_data_;
string fec_protected_payload_;
QuicRstStreamFrame rst_stream_frame_;
@@ -1760,8 +1768,8 @@ TEST_P(QuicFramerTest, AckFrameV14) {
}
}
-TEST_P(QuicFramerTest, AckFrame) {
- if (framer_.version() <= QUIC_VERSION_14) {
+TEST_P(QuicFramerTest, AckFrame15) {
+ if (framer_.version() != QUIC_VERSION_15) {
return;
}
@@ -1869,8 +1877,207 @@ TEST_P(QuicFramerTest, AckFrame) {
}
}
+TEST_P(QuicFramerTest, AckFrame) {
+ if (framer_.version() <= QUIC_VERSION_15) {
+ return;
+ }
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // Number of revived packets.
+ 0x00,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame.received_info.entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.received_info.largest_observed);
+ ASSERT_EQ(1u, frame.received_info.missing_packets.size());
+ SequenceNumberSet::const_iterator missing_iter =
+ frame.received_info.missing_packets.begin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+
+ const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLargestObservedOffset = kReceivedEntropyOffset +
+ kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset = kLargestObservedOffset +
+ PACKET_6BYTE_SEQUENCE_NUMBER;
+ const size_t kNumMissingPacketOffset = kMissingDeltaTimeOffset +
+ kQuicDeltaTimeLargestObservedSize;
+ const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
+ kNumberOfMissingPacketsSize;
+ const size_t kMissingPacketsRange = kMissingPacketsOffset +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ const size_t kRevivedPacketsLength = kMissingPacketsRange +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ // Now test framing boundaries
+ const size_t ack_frame_size = kRevivedPacketsLength +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error = "Unable to read delta time largest observed.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else if (i < kMissingPacketsRange) {
+ expected_error = "Unable to read missing sequence number delta.";
+ } else if (i < kRevivedPacketsLength) {
+ expected_error = "Unable to read missing sequence number range.";
+ } else {
+ expected_error = "Unable to read num revived packets.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
- if (framer_.version() <= QUIC_VERSION_14) {
+ if (framer_.version() <= QUIC_VERSION_15) {
+ return;
+ }
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // Number of revived packets.
+ 0x01,
+ // Revived packet sequence number.
+ 0xBE, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame.received_info.entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.received_info.largest_observed);
+ ASSERT_EQ(1u, frame.received_info.missing_packets.size());
+ SequenceNumberSet::const_iterator missing_iter =
+ frame.received_info.missing_packets.begin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter);
+
+ const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLargestObservedOffset = kReceivedEntropyOffset +
+ kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset = kLargestObservedOffset +
+ PACKET_6BYTE_SEQUENCE_NUMBER;
+ const size_t kNumMissingPacketOffset = kMissingDeltaTimeOffset +
+ kQuicDeltaTimeLargestObservedSize;
+ const size_t kMissingPacketsOffset = kNumMissingPacketOffset +
+ kNumberOfMissingPacketsSize;
+ const size_t kMissingPacketsRange = kMissingPacketsOffset +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ const size_t kRevivedPacketsLength = kMissingPacketsRange +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ const size_t kRevivedPacketSequenceNumberLength = kRevivedPacketsLength +
+ PACKET_1BYTE_SEQUENCE_NUMBER;
+ // Now test framing boundaries
+ const size_t ack_frame_size = kRevivedPacketSequenceNumberLength +
+ PACKET_6BYTE_SEQUENCE_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kReceivedEntropyOffset) {
+ expected_error = "Unable to read least unacked delta.";
+ } else if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error = "Unable to read delta time largest observed.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else if (i < kMissingPacketsRange) {
+ expected_error = "Unable to read missing sequence number delta.";
+ } else if (i < kRevivedPacketsLength) {
+ expected_error = "Unable to read missing sequence number range.";
+ } else if (i < kRevivedPacketSequenceNumberLength) {
+ expected_error = "Unable to read num revived packets.";
+ } else {
+ expected_error = "Unable to read revived packet.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, AckFrameRevivedPackets15) {
+ if (framer_.version() != QUIC_VERSION_15) {
return;
}
@@ -1986,6 +2193,64 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
}
TEST_P(QuicFramerTest, AckFrameNoNacks) {
+ if (framer_.version() <= QUIC_VERSION_15) {
+ return;
+ }
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (no nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x4C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ QuicAckFrame* frame = visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame->received_info.entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABF),
+ frame->received_info.largest_observed);
+ ASSERT_EQ(0u, frame->received_info.missing_packets.size());
+
+ // Verify that the packet re-serializes identically.
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame));
+ scoped_ptr<QuicPacket> data(
+ framer_.BuildUnsizedDataPacket(*visitor_.header_, frames).packet);
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, AckFrameNoNacks15) {
+ if (framer_.version() > QUIC_VERSION_15) {
+ return;
+ }
unsigned char packet[] = {
// public flags (8 byte guid)
0x3C,
@@ -2045,7 +2310,82 @@ TEST_P(QuicFramerTest, AckFrameNoNacks) {
}
TEST_P(QuicFramerTest, AckFrame500Nacks) {
- if (framer_.version() <= QUIC_VERSION_14) {
+ if (framer_.version() <= QUIC_VERSION_15) {
+ return;
+ }
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packet ranges
+ 0x02,
+ // missing packet delta
+ 0x01,
+ // 243 more missing packets in range.
+ // The ranges are listed in this order so the re-constructed packet matches.
+ 0xF3,
+ // No gap between ranges
+ 0x00,
+ // 255 more missing packets in range.
+ 0xFF,
+ // No revived packets.
+ 0x00,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ QuicAckFrame* frame = visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame->received_info.entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABF),
+ frame->received_info.largest_observed);
+ EXPECT_EQ(0u, frame->received_info.revived_packets.size());
+ ASSERT_EQ(500u, frame->received_info.missing_packets.size());
+ SequenceNumberSet::const_iterator first_missing_iter =
+ frame->received_info.missing_packets.begin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE) - 499, *first_missing_iter);
+ SequenceNumberSet::const_reverse_iterator last_missing_iter =
+ frame->received_info.missing_packets.rbegin();
+ EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *last_missing_iter);
+
+ // Verify that the packet re-serializes identically.
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame));
+ scoped_ptr<QuicPacket> data(
+ framer_.BuildUnsizedDataPacket(*visitor_.header_, frames).packet);
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, AckFrame500Nacks15) {
+ if (framer_.version() != QUIC_VERSION_15) {
return;
}
unsigned char packet[] = {
@@ -2584,6 +2924,63 @@ TEST_P(QuicFramerTest, CongestionFeedbackFrameInvalidFeedback) {
EXPECT_EQ(QUIC_INVALID_CONGESTION_FEEDBACK_DATA, framer_.error());
}
+TEST_P(QuicFramerTest, StopWaitingFrame) {
+ if (framer_.version() <= QUIC_VERSION_15) {
+ return;
+ }
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x06,
+ // entropy hash of sent packets till least awaiting - 1.
+ 0xAB,
+ // least packet sequence number awaiting an ack, delta from sequence number.
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ };
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.stop_waiting_frames_.size());
+ const QuicStopWaitingFrame& frame = *visitor_.stop_waiting_frames_[0];
+ EXPECT_EQ(0xAB, frame.entropy_hash);
+ EXPECT_EQ(GG_UINT64_C(0x0123456789AA0), frame.least_unacked);
+
+ const size_t kSentEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLeastUnackedOffset = kSentEntropyOffset + kQuicEntropyHashSize;
+ const size_t frame_size = 7;
+ for (size_t i = kQuicFrameTypeSize; i < frame_size; ++i) {
+ string expected_error;
+ if (i < kLeastUnackedOffset) {
+ expected_error = "Unable to read entropy hash for sent packets.";
+ } else {
+ expected_error = "Unable to read least unacked delta.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_STOP_WAITING_DATA);
+ }
+}
+
TEST_P(QuicFramerTest, RstStreamFrameVersion13) {
if (version_ > QUIC_VERSION_13) {
return;
@@ -3571,7 +3968,71 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
}
TEST_P(QuicFramerTest, BuildAckFramePacket) {
- if (version_ <= QUIC_VERSION_14) {
+ if (version_ <= QUIC_VERSION_15) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+ header.fec_group = 0;
+
+ QuicAckFrame ack_frame;
+ ack_frame.received_info.entropy_hash = 0x43;
+ ack_frame.received_info.largest_observed = GG_UINT64_C(0x770123456789ABF);
+ ack_frame.received_info.delta_time_largest_observed = QuicTime::Delta::Zero();
+ ack_frame.received_info.missing_packets.insert(
+ GG_UINT64_C(0x770123456789ABE));
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack_frame));
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0x43,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x0, 0x0,
+ // num missing packet ranges
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // 0 revived packets.
+ 0x00,
+ };
+
+ scoped_ptr<QuicPacket> data(
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildAckFramePacket15) {
+ if (version_ != QUIC_VERSION_15) {
return;
}
QuicPacketHeader header;
@@ -3958,6 +4419,56 @@ TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketInterArrivalV14) {
AsChars(packet), arraysize(packet));
}
+TEST_P(QuicFramerTest, BuildStopWaitingPacket) {
+ if (version_ <= QUIC_VERSION_15) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8);
+ header.fec_group = 0;
+
+ QuicStopWaitingFrame stop_waiting_frame;
+ stop_waiting_frame.entropy_hash = 0x14;
+ stop_waiting_frame.least_unacked = GG_UINT64_C(0x770123456789AA0);
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&stop_waiting_frame));
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (stop waiting frame)
+ 0x06,
+ // entropy hash of sent packets till least awaiting - 1.
+ 0x14,
+ // least packet sequence number awaiting an ack, delta from sequence number.
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ };
+
+ scoped_ptr<QuicPacket> data(
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketFixRate) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
@@ -4025,7 +4536,7 @@ TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketInvalidFeedback) {
scoped_ptr<QuicPacket> data;
EXPECT_DFATAL(
data.reset(framer_.BuildUnsizedDataPacket(header, frames).packet),
- "AppendQuicCongestionFeedbackFrame failed");
+ "AppendCongestionFeedbackFrame failed");
ASSERT_TRUE(data == NULL);
}
@@ -4571,6 +5082,58 @@ TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) {
}
TEST_P(QuicFramerTest, Truncation) {
+ if (framer_.version() <= QUIC_VERSION_15) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = false;
+ header.packet_sequence_number = GG_UINT64_C(0x123456789ABC);
+ header.fec_group = 0;
+
+ QuicAckFrame ack_frame;
+ ack_frame.received_info.largest_observed = 601;
+ for (uint64 i = 1; i < ack_frame.received_info.largest_observed; i += 2) {
+ ack_frame.received_info.missing_packets.insert(i);
+ }
+
+ // Create a packet with just the ack
+ QuicFrame frame;
+ frame.type = ACK_FRAME;
+ frame.ack_frame = &ack_frame;
+ QuicFrames frames;
+ frames.push_back(frame);
+
+ scoped_ptr<QuicPacket> raw_ack_packet(
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
+ ASSERT_TRUE(raw_ack_packet != NULL);
+
+ scoped_ptr<QuicEncryptedPacket> ack_packet(
+ framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number,
+ *raw_ack_packet));
+
+ // Now make sure we can turn our ack packet back into an ack frame
+ ASSERT_TRUE(framer_.ProcessPacket(*ack_packet));
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
+ EXPECT_TRUE(processed_ack_frame.received_info.is_truncated);
+ EXPECT_EQ(510u, processed_ack_frame.received_info.largest_observed);
+ ASSERT_EQ(255u, processed_ack_frame.received_info.missing_packets.size());
+ SequenceNumberSet::const_iterator missing_iter =
+ processed_ack_frame.received_info.missing_packets.begin();
+ EXPECT_EQ(1u, *missing_iter);
+ SequenceNumberSet::const_reverse_iterator last_missing_iter =
+ processed_ack_frame.received_info.missing_packets.rbegin();
+ EXPECT_EQ(509u, *last_missing_iter);
+}
+
+TEST_P(QuicFramerTest, Truncation15) {
+ if (framer_.version() > QUIC_VERSION_15) {
+ return;
+ }
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc
index 47cc054..404e0a9 100644
--- a/net/quic/quic_headers_stream_test.cc
+++ b/net/quic/quic_headers_stream_test.cc
@@ -82,7 +82,9 @@ class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> {
EXPECT_TRUE(headers_stream_ != NULL);
}
- QuicConsumedData SaveIov(const struct iovec* iov, int count) {
+ QuicConsumedData SaveIov(const IOVector& data) {
+ const iovec* iov = data.iovec();
+ int count = data.Capacity();
for (int i = 0 ; i < count; ++i) {
saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
}
@@ -114,9 +116,8 @@ class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> {
QuicPriority priority,
SpdyFrameType type) {
// Write the headers and capture the outgoing data
- EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, _, _, false, NULL))
- .WillOnce(WithArgs<1, 2>(
- Invoke(this, &QuicHeadersStreamTest::SaveIov)));
+ EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, _, false, NULL))
+ .WillOnce(WithArgs<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
headers_stream_->WriteHeaders(stream_id, headers_, fin);
// Parse the outgoing data and check that it matches was was written.
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index b399650..f0e5c2b 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -406,8 +406,15 @@ void QuicPacketCreator::FillPacketHeader(QuicFecGroupNumber fec_group,
}
bool QuicPacketCreator::ShouldRetransmit(const QuicFrame& frame) {
- return frame.type != ACK_FRAME && frame.type != CONGESTION_FEEDBACK_FRAME &&
- frame.type != PADDING_FRAME;
+ switch (frame.type) {
+ case ACK_FRAME:
+ case CONGESTION_FEEDBACK_FRAME:
+ case PADDING_FRAME:
+ case STOP_WAITING_FRAME:
+ return false;
+ default:
+ return true;
+ }
}
bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index 34c65e03..cd2013e 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -23,7 +23,8 @@ QuicPacketGenerator::QuicPacketGenerator(DelegateInterface* delegate,
packet_creator_(creator),
batch_mode_(false),
should_send_ack_(false),
- should_send_feedback_(false) {
+ should_send_feedback_(false),
+ should_send_stop_waiting_(false) {
}
QuicPacketGenerator::~QuicPacketGenerator() {
@@ -57,15 +58,25 @@ QuicPacketGenerator::~QuicPacketGenerator() {
case BLOCKED_FRAME:
delete it->blocked_frame;
break;
+ case STOP_WAITING_FRAME:
+ delete it->stop_waiting_frame;
+ break;
case NUM_FRAME_TYPES:
DCHECK(false) << "Cannot delete type: " << it->type;
}
}
}
-void QuicPacketGenerator::SetShouldSendAck(bool also_send_feedback) {
+void QuicPacketGenerator::SetShouldSendAck(bool also_send_feedback,
+ bool also_send_stop_waiting) {
should_send_ack_ = true;
should_send_feedback_ = also_send_feedback;
+ should_send_stop_waiting_ = also_send_stop_waiting;
+ SendQueuedFrames(false);
+}
+
+void QuicPacketGenerator::SetShouldSendStopWaiting() {
+ should_send_stop_waiting_ = true;
SendQueuedFrames(false);
}
@@ -147,8 +158,8 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id,
bool QuicPacketGenerator::CanSendWithNextPendingFrameAddition() const {
DCHECK(HasPendingFrames());
HasRetransmittableData retransmittable =
- (should_send_ack_ || should_send_feedback_) ? NO_RETRANSMITTABLE_DATA
- : HAS_RETRANSMITTABLE_DATA;
+ (should_send_ack_ || should_send_feedback_ || should_send_stop_waiting_)
+ ? NO_RETRANSMITTABLE_DATA : HAS_RETRANSMITTABLE_DATA;
if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
DCHECK(!queued_control_frames_.empty()); // These are retransmittable.
}
@@ -204,7 +215,7 @@ bool QuicPacketGenerator::HasQueuedFrames() const {
bool QuicPacketGenerator::HasPendingFrames() const {
return should_send_ack_ || should_send_feedback_ ||
- !queued_control_frames_.empty();
+ should_send_stop_waiting_ || !queued_control_frames_.empty();
}
bool QuicPacketGenerator::AddNextPendingFrame() {
@@ -226,9 +237,18 @@ bool QuicPacketGenerator::AddNextPendingFrame() {
return !should_send_feedback_;
}
- if (queued_control_frames_.empty()) {
- LOG(DFATAL) << "AddNextPendingFrame called with no queued control frames.";
+ if (should_send_stop_waiting_) {
+ pending_stop_waiting_frame_.reset(delegate_->CreateStopWaitingFrame());
+ // If we can't this add the frame now, then we still need to do so later.
+ should_send_stop_waiting_ =
+ !AddFrame(QuicFrame(pending_stop_waiting_frame_.get()));
+ // Return success if we have cleared out this flag (i.e., added the frame).
+ // If we still need to send, then the frame is full, and we have failed.
+ return !should_send_stop_waiting_;
}
+
+ LOG_IF(DFATAL, queued_control_frames_.empty())
+ << "AddNextPendingFrame called with no queued control frames.";
if (!AddFrame(queued_control_frames_.back())) {
// Packet was full.
return false;
diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h
index 1ff0488..1434451 100644
--- a/net/quic/quic_packet_generator.h
+++ b/net/quic/quic_packet_generator.h
@@ -69,6 +69,7 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator {
IsHandshake handshake) = 0;
virtual QuicAckFrame* CreateAckFrame() = 0;
virtual QuicCongestionFeedbackFrame* CreateFeedbackFrame() = 0;
+ virtual QuicStopWaitingFrame* CreateStopWaitingFrame() = 0;
// Takes ownership of |packet.packet| and |packet.retransmittable_frames|.
virtual bool OnSerializedPacket(const SerializedPacket& packet) = 0;
virtual void CloseConnection(QuicErrorCode error, bool from_peer) = 0;
@@ -93,9 +94,16 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator {
// Indicates that an ACK frame should be sent. If |also_send_feedback| is
// true, then it also indicates a CONGESTION_FEEDBACK frame should be sent.
+ // If |also_send_stop_waiting| is true, then it also indicates that a
+ // STOP_WAITING frame should be sent as well.
// The contents of the frame(s) will be generated via a call to the delegates
// CreateAckFrame() and CreateFeedbackFrame() when the packet is serialized.
- void SetShouldSendAck(bool also_send_feedback);
+ void SetShouldSendAck(bool also_send_feedback,
+ bool also_send_stop_waiting);
+
+ // Indicates that a STOP_WAITING frame should be sent.
+ void SetShouldSendStopWaiting();
+
void AddControlFrame(const QuicFrame& frame);
// Given some data, may consume part or all of it and pass it to the
@@ -155,12 +163,14 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator {
// Flags to indicate the need for just-in-time construction of a frame.
bool should_send_ack_;
bool should_send_feedback_;
+ bool should_send_stop_waiting_;
// If we put a non-retransmittable frame (namley ack or feedback frame) in
// this packet, then we have to hold a reference to it until we flush (and
// serialize it). Retransmittable frames are referenced elsewhere so that they
// can later be (optionally) retransmitted.
scoped_ptr<QuicAckFrame> pending_ack_frame_;
scoped_ptr<QuicCongestionFeedbackFrame> pending_feedback_frame_;
+ scoped_ptr<QuicStopWaitingFrame> pending_stop_waiting_frame_;
DISALLOW_COPY_AND_ASSIGN(QuicPacketGenerator);
};
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index 4b64c15..f6e9b85 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -39,6 +39,7 @@ class MockDelegate : public QuicPacketGenerator::DelegateInterface {
IsHandshake handshake));
MOCK_METHOD0(CreateAckFrame, QuicAckFrame*());
MOCK_METHOD0(CreateFeedbackFrame, QuicCongestionFeedbackFrame*());
+ MOCK_METHOD0(CreateStopWaitingFrame, QuicStopWaitingFrame*());
MOCK_METHOD1(OnSerializedPacket, bool(const SerializedPacket& packet));
MOCK_METHOD2(CloseConnection, void(QuicErrorCode, bool));
@@ -81,6 +82,7 @@ struct PacketContents {
num_feedback_frames(0),
num_goaway_frames(0),
num_rst_stream_frames(0),
+ num_stop_waiting_frames(0),
num_stream_frames(0),
fec_group(0) {
}
@@ -90,6 +92,7 @@ struct PacketContents {
size_t num_feedback_frames;
size_t num_goaway_frames;
size_t num_rst_stream_frames;
+ size_t num_stop_waiting_frames;
size_t num_stream_frames;
QuicFecGroupNumber fec_group;
@@ -135,6 +138,13 @@ class QuicPacketGeneratorTest : public ::testing::Test {
return frame;
}
+ QuicStopWaitingFrame* CreateStopWaitingFrame() {
+ QuicStopWaitingFrame* frame = new QuicStopWaitingFrame();
+ frame->entropy_hash = 0;
+ frame->least_unacked = 0;
+ return frame;
+ }
+
QuicRstStreamFrame* CreateRstStreamFrame() {
return new QuicRstStreamFrame(1, QUIC_STREAM_NO_ERROR, 0);
}
@@ -149,7 +159,7 @@ class QuicPacketGeneratorTest : public ::testing::Test {
contents.num_goaway_frames + contents.num_rst_stream_frames +
contents.num_stream_frames;
size_t num_frames = contents.num_feedback_frames + contents.num_ack_frames +
- num_retransmittable_frames;
+ contents.num_stop_waiting_frames + num_retransmittable_frames;
if (num_retransmittable_frames == 0) {
ASSERT_TRUE(packet.retransmittable_frames == NULL);
@@ -173,6 +183,8 @@ class QuicPacketGeneratorTest : public ::testing::Test {
simple_framer_.rst_stream_frames().size());
EXPECT_EQ(contents.num_stream_frames,
simple_framer_.stream_frames().size());
+ EXPECT_EQ(contents.num_stop_waiting_frames,
+ simple_framer_.stop_waiting_frames().size());
EXPECT_EQ(contents.fec_group, simple_framer_.header().fec_group);
}
@@ -227,7 +239,7 @@ class MockDebugDelegate : public QuicPacketGenerator::DebugDelegateInterface {
TEST_F(QuicPacketGeneratorTest, ShouldSendAck_NotWritable) {
delegate_.SetCanNotWrite();
- generator_.SetShouldSendAck(false);
+ generator_.SetShouldSendAck(false, false);
EXPECT_TRUE(generator_.HasQueuedFrames());
}
@@ -241,7 +253,7 @@ TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldNotFlush) {
EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame()));
EXPECT_CALL(debug_delegate, OnFrameAddedToPacket(_)).Times(1);
- generator_.SetShouldSendAck(false);
+ generator_.SetShouldSendAck(false, false);
EXPECT_TRUE(generator_.HasQueuedFrames());
}
@@ -252,7 +264,7 @@ TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldFlush) {
EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
DoAll(SaveArg<0>(&packet_), Return(true)));
- generator_.SetShouldSendAck(false);
+ generator_.SetShouldSendAck(false, false);
EXPECT_FALSE(generator_.HasQueuedFrames());
PacketContents contents;
@@ -269,7 +281,7 @@ TEST_F(QuicPacketGeneratorTest,
EXPECT_CALL(delegate_, CreateFeedbackFrame()).WillOnce(
Return(CreateFeedbackFrame()));
- generator_.SetShouldSendAck(true);
+ generator_.SetShouldSendAck(true, false);
EXPECT_TRUE(generator_.HasQueuedFrames());
}
@@ -280,16 +292,19 @@ TEST_F(QuicPacketGeneratorTest,
EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame()));
EXPECT_CALL(delegate_, CreateFeedbackFrame()).WillOnce(
Return(CreateFeedbackFrame()));
+ EXPECT_CALL(delegate_, CreateStopWaitingFrame()).WillOnce(
+ Return(CreateStopWaitingFrame()));
EXPECT_CALL(delegate_, OnSerializedPacket(_)).WillOnce(
DoAll(SaveArg<0>(&packet_), Return(true)));
- generator_.SetShouldSendAck(true);
+ generator_.SetShouldSendAck(true, true);
EXPECT_FALSE(generator_.HasQueuedFrames());
PacketContents contents;
contents.num_ack_frames = 1;
contents.num_feedback_frames = 1;
+ contents.num_stop_waiting_frames = 1;
CheckPacketContains(contents, packet_);
}
@@ -532,7 +547,7 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
delegate_.SetCanNotWrite();
- generator_.SetShouldSendAck(true);
+ generator_.SetShouldSendAck(true, false);
generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
EXPECT_TRUE(generator_.HasQueuedFrames());
@@ -568,7 +583,7 @@ TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) {
delegate_.SetCanNotWrite();
- generator_.SetShouldSendAck(true);
+ generator_.SetShouldSendAck(true, false);
generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
EXPECT_TRUE(generator_.HasQueuedFrames());
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 1d673d9..e56522d 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -159,6 +159,8 @@ QuicTag QuicVersionToQuicTag(const QuicVersion version) {
return MakeQuicTag('Q', '0', '1', '4');
case QUIC_VERSION_15:
return MakeQuicTag('Q', '0', '1', '5');
+ case QUIC_VERSION_16:
+ return MakeQuicTag('Q', '0', '1', '6');
default:
// This shold be an ERROR because we should never attempt to convert an
// invalid QuicVersion to be written to the wire.
@@ -189,6 +191,7 @@ string QuicVersionToString(const QuicVersion version) {
RETURN_STRING_LITERAL(QUIC_VERSION_13);
RETURN_STRING_LITERAL(QUIC_VERSION_14);
RETURN_STRING_LITERAL(QUIC_VERSION_15);
+ RETURN_STRING_LITERAL(QUIC_VERSION_16);
default:
return "QUIC_VERSION_UNSUPPORTED";
}
@@ -249,12 +252,12 @@ void InsertMissingPacketsBetween(ReceivedPacketInfo* received_info,
}
}
-SentPacketInfo::SentPacketInfo()
+QuicStopWaitingFrame::QuicStopWaitingFrame()
: entropy_hash(0),
least_unacked(0) {
}
-SentPacketInfo::~SentPacketInfo() {}
+QuicStopWaitingFrame::~QuicStopWaitingFrame() {}
QuicAckFrame::QuicAckFrame() {}
@@ -321,6 +324,11 @@ QuicFrame::QuicFrame(QuicCongestionFeedbackFrame* frame)
congestion_feedback_frame(frame) {
}
+QuicFrame::QuicFrame(QuicStopWaitingFrame* frame)
+ : type(STOP_WAITING_FRAME),
+ stop_waiting_frame(frame) {
+}
+
QuicFrame::QuicFrame(QuicRstStreamFrame* frame)
: type(RST_STREAM_FRAME),
rst_stream_frame(frame) {
@@ -348,7 +356,7 @@ QuicFrame::QuicFrame(QuicBlockedFrame* frame)
QuicFecData::QuicFecData() : fec_group(0) {}
-ostream& operator<<(ostream& os, const SentPacketInfo& sent_info) {
+ostream& operator<<(ostream& os, const QuicStopWaitingFrame& sent_info) {
os << "entropy_hash: " << static_cast<int>(sent_info.entropy_hash)
<< " least_unacked: " << sent_info.least_unacked;
return os;
@@ -414,6 +422,10 @@ ostream& operator<<(ostream& os, const QuicFrame& frame) {
<< *(frame.congestion_feedback_frame);
break;
}
+ case STOP_WAITING_FRAME: {
+ os << "type { STOP_WAITING_FRAME } " << *(frame.stop_waiting_frame);
+ break;
+ }
default: {
LOG(ERROR) << "Unknown frame type: " << frame.type;
break;
@@ -621,6 +633,9 @@ RetransmittableFrames::~RetransmittableFrames() {
case CONGESTION_FEEDBACK_FRAME:
delete it->congestion_feedback_frame;
break;
+ case STOP_WAITING_FRAME:
+ delete it->stop_waiting_frame;
+ break;
case RST_STREAM_FRAME:
delete it->rst_stream_frame;
break;
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 8bb89fa..23b6038 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -60,9 +60,7 @@ const QuicByteCount kMaxPacketSize = 1452;
// Maximum size of the initial congestion window in packets.
const size_t kDefaultInitialWindow = 10;
-// TODO(ianswett): Temporarily changed to 10 due to a large number of clients
-// mistakenly negotiating 100 initially and suffering the consequences.
-const size_t kMaxInitialWindow = 10;
+const size_t kMaxInitialWindow = 100;
// Maximum size of the congestion window, in packets, for TCP congestion control
// algorithms.
@@ -157,6 +155,7 @@ enum QuicFrameType {
GOAWAY_FRAME = 3,
WINDOW_UPDATE_FRAME = 4,
BLOCKED_FRAME = 5,
+ STOP_WAITING_FRAME = 6,
// STREAM, ACK, and CONGESTION_FEEDBACK frames are special frames. They are
// encoded differently on the wire and their values do not need to be stable.
@@ -257,7 +256,8 @@ enum QuicVersion {
QUIC_VERSION_12 = 12,
QUIC_VERSION_13 = 13,
QUIC_VERSION_14 = 14,
- QUIC_VERSION_15 = 15, // Current version.
+ QUIC_VERSION_15 = 15,
+ QUIC_VERSION_16 = 16, // Current version.
};
// This vector contains QUIC versions which we currently support.
@@ -267,7 +267,8 @@ enum QuicVersion {
//
// IMPORTANT: if you are addding to this list, follow the instructions at
// http://sites/quic/adding-and-removing-versions
-static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_15,
+static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_16,
+ QUIC_VERSION_15,
QUIC_VERSION_14,
QUIC_VERSION_13,
QUIC_VERSION_12};
@@ -378,6 +379,8 @@ enum QuicErrorCode {
QUIC_INVALID_WINDOW_UPDATE_DATA = 57,
// BLOCKED frame data is malformed.
QUIC_INVALID_BLOCKED_DATA = 58,
+ // STOP_WAITING frame data is malformed.
+ QUIC_INVALID_STOP_WAITING_DATA = 60,
// ACK frame data is malformed.
QUIC_INVALID_ACK_DATA = 9,
// CONGESTION_FEEDBACK frame data is malformed.
@@ -483,7 +486,7 @@ enum QuicErrorCode {
QUIC_VERSION_NEGOTIATION_MISMATCH = 55,
// No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 60,
+ QUIC_LAST_ERROR = 61,
};
struct NET_EXPORT_PRIVATE QuicPacketPublicHeader {
@@ -629,12 +632,13 @@ void NET_EXPORT_PRIVATE InsertMissingPacketsBetween(
QuicPacketSequenceNumber lower,
QuicPacketSequenceNumber higher);
-struct NET_EXPORT_PRIVATE SentPacketInfo {
- SentPacketInfo();
- ~SentPacketInfo();
+struct NET_EXPORT_PRIVATE QuicStopWaitingFrame {
+ QuicStopWaitingFrame();
+ ~QuicStopWaitingFrame();
NET_EXPORT_PRIVATE friend std::ostream& operator<<(
- std::ostream& os, const SentPacketInfo& s);
+ std::ostream& os, const QuicStopWaitingFrame& s);
+
// Entropy hash of all packets up to, but not including, the least unacked
// packet.
QuicPacketEntropyHash entropy_hash;
@@ -653,7 +657,7 @@ struct NET_EXPORT_PRIVATE QuicAckFrame {
NET_EXPORT_PRIVATE friend std::ostream& operator<<(
std::ostream& os, const QuicAckFrame& s);
- SentPacketInfo sent_info;
+ QuicStopWaitingFrame sent_info;
ReceivedPacketInfo received_info;
};
@@ -802,6 +806,7 @@ struct NET_EXPORT_PRIVATE QuicFrame {
explicit QuicFrame(QuicCongestionFeedbackFrame* frame);
explicit QuicFrame(QuicRstStreamFrame* frame);
explicit QuicFrame(QuicConnectionCloseFrame* frame);
+ explicit QuicFrame(QuicStopWaitingFrame* frame);
explicit QuicFrame(QuicGoAwayFrame* frame);
explicit QuicFrame(QuicWindowUpdateFrame* frame);
explicit QuicFrame(QuicBlockedFrame* frame);
@@ -815,6 +820,7 @@ struct NET_EXPORT_PRIVATE QuicFrame {
QuicStreamFrame* stream_frame;
QuicAckFrame* ack_frame;
QuicCongestionFeedbackFrame* congestion_feedback_frame;
+ QuicStopWaitingFrame* stop_waiting_frame;
QuicRstStreamFrame* rst_stream_frame;
QuicConnectionCloseFrame* connection_close_frame;
QuicGoAwayFrame* goaway_frame;
diff --git a/net/quic/quic_received_packet_manager.cc b/net/quic/quic_received_packet_manager.cc
index 2ebbd97..3e9860b 100644
--- a/net/quic/quic_received_packet_manager.cc
+++ b/net/quic/quic_received_packet_manager.cc
@@ -207,19 +207,20 @@ bool QuicReceivedPacketManager::DontWaitForPacketsBefore(
}
void QuicReceivedPacketManager::UpdatePacketInformationSentByPeer(
- const SentPacketInfo& sent_info) {
+ const QuicStopWaitingFrame& stop_waiting) {
// ValidateAck() should fail if peer_least_packet_awaiting_ack_ shrinks.
- DCHECK_LE(peer_least_packet_awaiting_ack_, sent_info.least_unacked);
- if (sent_info.least_unacked > peer_least_packet_awaiting_ack_) {
- bool missed_packets = DontWaitForPacketsBefore(sent_info.least_unacked);
- if (missed_packets || sent_info.least_unacked >
+ DCHECK_LE(peer_least_packet_awaiting_ack_, stop_waiting.least_unacked);
+ if (stop_waiting.least_unacked > peer_least_packet_awaiting_ack_) {
+ bool missed_packets = DontWaitForPacketsBefore(stop_waiting.least_unacked);
+ if (missed_packets || stop_waiting.least_unacked >
received_info_.largest_observed + 1) {
DVLOG(1) << "Updating entropy hashed since we missed packets";
// There were some missing packets that we won't ever get now. Recalculate
// the received entropy hash.
- RecalculateEntropyHash(sent_info.least_unacked, sent_info.entropy_hash);
+ RecalculateEntropyHash(stop_waiting.least_unacked,
+ stop_waiting.entropy_hash);
}
- peer_least_packet_awaiting_ack_ = sent_info.least_unacked;
+ peer_least_packet_awaiting_ack_ = stop_waiting.least_unacked;
}
DCHECK(received_info_.missing_packets.empty() ||
*received_info_.missing_packets.begin() >=
diff --git a/net/quic/quic_received_packet_manager.h b/net/quic/quic_received_packet_manager.h
index e089519..5bc9f0c 100644
--- a/net/quic/quic_received_packet_manager.h
+++ b/net/quic/quic_received_packet_manager.h
@@ -64,8 +64,9 @@ class NET_EXPORT_PRIVATE QuicReceivedPacketManager :
// Updates internal state based on |received_info|.
void UpdatePacketInformationReceivedByPeer(
const ReceivedPacketInfo& received_nfo);
- // Updates internal state based on |sent_info|.
- void UpdatePacketInformationSentByPeer(const SentPacketInfo& sent_info);
+ // Updates internal state based on |stop_waiting|.
+ void UpdatePacketInformationSentByPeer(
+ const QuicStopWaitingFrame& stop_waiting);
// Returns whether the peer is missing packets.
bool HasMissingPackets();
diff --git a/net/quic/quic_reliable_client_stream_test.cc b/net/quic/quic_reliable_client_stream_test.cc
index b01d0fd..75e099c 100644
--- a/net/quic/quic_reliable_client_stream_test.cc
+++ b/net/quic/quic_reliable_client_stream_test.cc
@@ -146,7 +146,7 @@ TEST_P(QuicReliableClientStreamTest, WriteStreamData) {
const size_t kDataLen = arraysize(kData1);
// All data written.
- EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _, _)).WillOnce(
+ EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _)).WillOnce(
Return(QuicConsumedData(kDataLen, true)));
TestCompletionCallback callback;
EXPECT_EQ(OK, stream_->WriteStreamData(base::StringPiece(kData1, kDataLen),
@@ -161,7 +161,7 @@ TEST_P(QuicReliableClientStreamTest, WriteStreamDataAsync) {
const size_t kDataLen = arraysize(kData1);
// No data written.
- EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _, _)).WillOnce(
+ EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _)).WillOnce(
Return(QuicConsumedData(0, false)));
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
@@ -170,7 +170,7 @@ TEST_P(QuicReliableClientStreamTest, WriteStreamDataAsync) {
ASSERT_FALSE(callback.have_result());
// All data written.
- EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _, _)).WillOnce(
+ EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _)).WillOnce(
Return(QuicConsumedData(kDataLen, true)));
stream_->OnCanWrite();
ASSERT_TRUE(callback.have_result());
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 8fa0bd7..17cd836 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -41,9 +41,6 @@ static const int kMinRetransmissionTimeMs = 200;
static const int kMaxRetransmissionTimeMs = 60000;
static const size_t kMaxRetransmissions = 10;
-// TCP retransmits after 3 nacks.
-static const size_t kNumberOfNacksBeforeRetransmission = 3;
-
// Only exponentially back off the handshake timer 5 times due to a timeout.
static const size_t kMaxHandshakeRetransmissionBackoffs = 5;
static const size_t kMinHandshakeTimeoutMs = 10;
@@ -75,7 +72,9 @@ QuicSentPacketManager::QuicSentPacketManager(bool is_server,
clock_(clock),
stats_(stats),
send_algorithm_(SendAlgorithmInterface::Create(clock, type)),
+ loss_algorithm_(LossDetectionInterface::Create()),
rtt_sample_(QuicTime::Delta::Infinite()),
+ largest_observed_(0),
pending_crypto_packet_count_(0),
consecutive_rto_count_(0),
consecutive_tlp_count_(0),
@@ -141,6 +140,7 @@ bool QuicSentPacketManager::OnIncomingAck(
// we only update rtt when the largest observed gets acked.
bool largest_observed_acked =
unacked_packets_.IsUnacked(received_info.largest_observed);
+ largest_observed_ = received_info.largest_observed;
MaybeUpdateRTT(received_info, ack_receive_time);
HandleAckForSentPackets(received_info);
MaybeRetransmitOnAckFrame(received_info, ack_receive_time);
@@ -305,7 +305,6 @@ QuicSentPacketManager::MarkPacketHandled(
unacked_packets_.SetNotPending(sequence_number);
}
-
SequenceNumberSet all_transmissions = *transmission_info.all_transmissions;
SequenceNumberSet::reverse_iterator all_transmissions_it =
all_transmissions.rbegin();
@@ -528,8 +527,7 @@ void QuicSentPacketManager::OnIncomingQuicCongestionFeedbackFrame(
void QuicSentPacketManager::MaybeRetransmitOnAckFrame(
const ReceivedPacketInfo& received_info,
const QuicTime& ack_receive_time) {
- // Go through all pending packets up to the largest observed and see if any
- // need to be retransmitted or lost.
+ // Go through all pending packets up to the largest observed and count nacks.
for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
it != unacked_packets_.end() &&
it->first <= received_info.largest_observed; ++it) {
@@ -544,16 +542,19 @@ void QuicSentPacketManager::MaybeRetransmitOnAckFrame(
// Consider it multiple nacks when there is a gap between the missing packet
// and the largest observed, since the purpose of a nack threshold is to
// tolerate re-ordering. This handles both StretchAcks and Forward Acks.
- // TODO(ianswett): This relies heavily on sequential reception of packets,
- // and makes an assumption that the congestion control uses TCP style nacks.
size_t min_nacks = received_info.largest_observed - sequence_number;
unacked_packets_.NackPacket(sequence_number, min_nacks);
}
+ InvokeLossDetection(ack_receive_time);
+}
+
+void QuicSentPacketManager::InvokeLossDetection(QuicTime time) {
SequenceNumberSet lost_packets =
- DetectLostPackets(unacked_packets_,
- ack_receive_time,
- received_info.largest_observed);
+ loss_algorithm_->DetectLostPackets(unacked_packets_,
+ time,
+ largest_observed_,
+ send_algorithm_->SmoothedRtt());
for (SequenceNumberSet::const_iterator it = lost_packets.begin();
it != lost_packets.end(); ++it) {
QuicPacketSequenceNumber sequence_number = *it;
@@ -561,7 +562,7 @@ void QuicSentPacketManager::MaybeRetransmitOnAckFrame(
// should be recorded as a loss to the send algorithm, but not retransmitted
// until it's known whether the FEC packet arrived.
++stats_->packets_lost;
- send_algorithm_->OnPacketLost(sequence_number, ack_receive_time);
+ send_algorithm_->OnPacketLost(sequence_number, time);
OnPacketAbandoned(sequence_number);
if (unacked_packets_.HasRetransmittableFrames(sequence_number)) {
@@ -576,40 +577,6 @@ void QuicSentPacketManager::MaybeRetransmitOnAckFrame(
}
}
-// static
-SequenceNumberSet QuicSentPacketManager::DetectLostPackets(
- const QuicUnackedPacketMap& unacked_packets,
- const QuicTime& time,
- QuicPacketSequenceNumber largest_observed) {
- SequenceNumberSet lost_packets;
-
- for (QuicUnackedPacketMap::const_iterator it = unacked_packets.begin();
- it != unacked_packets.end() && it->first <= largest_observed; ++it) {
- if (!it->second.pending) {
- continue;
- }
- size_t num_nacks_needed = kNumberOfNacksBeforeRetransmission;
- // Check for early retransmit(RFC5827) when the last packet gets acked and
- // the there are fewer than 4 pending packets.
- // TODO(ianswett): Set a retransmission timer instead of losing the packet
- // and retransmitting immediately. Also consider only invoking OnPacketLost
- // and OnPacketAbandoned when they're actually retransmitted in case they
- // arrive while queued for retransmission.
- if (it->second.retransmittable_frames &&
- unacked_packets.largest_sent_packet() == largest_observed) {
- num_nacks_needed = largest_observed - it->first;
- }
-
- if (it->second.nack_count < num_nacks_needed) {
- continue;
- }
-
- lost_packets.insert(it->first);
- }
-
- return lost_packets;
-}
-
void QuicSentPacketManager::MaybeUpdateRTT(
const ReceivedPacketInfo& received_info,
const QuicTime& ack_receive_time) {
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index 69688ac..4690f21 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -16,6 +16,7 @@
#include "base/containers/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/linked_hash_map.h"
+#include "net/quic/congestion_control/loss_detection_interface.h"
#include "net/quic/congestion_control/send_algorithm_interface.h"
#include "net/quic/quic_ack_notifier_manager.h"
#include "net/quic/quic_protocol.h"
@@ -220,6 +221,10 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
void MaybeRetransmitOnAckFrame(const ReceivedPacketInfo& received_info,
const QuicTime& ack_receive_time);
+ // Invokes the loss detection algorithm and loses and retransmits packets if
+ // necessary.
+ void InvokeLossDetection(QuicTime time);
+
// Marks |sequence_number| as being fully handled, either due to receipt
// by the peer, or having been discarded as indecipherable. Returns an
// iterator to the next remaining unacked packet.
@@ -233,11 +238,6 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
void MarkForRetransmission(QuicPacketSequenceNumber sequence_number,
TransmissionType transmission_type);
- static SequenceNumberSet DetectLostPackets(
- const QuicUnackedPacketMap& unacked_packets,
- const QuicTime& time,
- QuicPacketSequenceNumber largest_observed);
-
// Newly serialized retransmittable and fec packets are added to this map,
// which contains owning pointers to any contained frames. If a packet is
// retransmitted, this map will contain entries for both the old and the new
@@ -262,7 +262,9 @@ class NET_EXPORT_PRIVATE QuicSentPacketManager {
const QuicClock* clock_;
QuicConnectionStats* stats_;
scoped_ptr<SendAlgorithmInterface> send_algorithm_;
+ scoped_ptr<LossDetectionInterface> loss_algorithm_;
QuicTime::Delta rtt_sample_; // RTT estimate from the most recent ACK.
+ QuicPacketSequenceNumber largest_observed_; // From the most recent ACK.
// Number of outstanding crypto handshake packets.
size_t pending_crypto_packet_count_;
// Number of times the RTO timer has fired in a row without receiving an ack.
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index 5adff71..3ab3e39 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -35,6 +35,12 @@ class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
STLDeleteElements(&packets_);
}
+ virtual void SetUp() {
+ // Ack handling requests a smoothed rtt for loss detection.
+ EXPECT_CALL(*send_algorithm_, SmoothedRtt())
+ .WillRepeatedly(Return(QuicTime::Delta::FromMilliseconds(1)));
+ }
+
void VerifyUnackedPackets(QuicPacketSequenceNumber* packets,
size_t num_packets) {
if (num_packets == 0) {
@@ -614,140 +620,6 @@ TEST_F(QuicSentPacketManagerTest, GetSentTime) {
EXPECT_EQ(sent_time, QuicSentPacketManagerPeer::GetSentTime(&manager_, 2));
}
-TEST_F(QuicSentPacketManagerTest, NackRetransmit1Packet) {
- const size_t kNumSentPackets = 4;
- // Transmit 4 packets.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
- EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-
- // Nack the first packet 3 times with increasing largest observed.
- ReceivedPacketInfo received_info;
- received_info.delta_time_largest_observed =
- QuicTime::Delta::FromMilliseconds(5);
- received_info.missing_packets.insert(1);
- for (QuicPacketSequenceNumber i = 1; i <= 3; ++i) {
- received_info.largest_observed = i + 1;
- EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(i + 1, _)).Times(1);
- if (i == 3) {
- EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1);
- }
- manager_.OnIncomingAck(received_info, clock_.Now());
- EXPECT_EQ(
- i == 3 ? 1u : 0u,
- QuicSentPacketManagerPeer::GetPendingRetransmissionCount(&manager_));
- EXPECT_EQ(i, QuicSentPacketManagerPeer::GetNackCount(&manager_, 1));
- }
- EXPECT_EQ(1u, stats_.packets_lost);
-}
-
-// A stretch ack is an ack that covers more than 1 packet of previously
-// unacknowledged data.
-TEST_F(QuicSentPacketManagerTest, NackRetransmit1PacketWith1StretchAck) {
- const size_t kNumSentPackets = 4;
- // Transmit 4 packets.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
-
- // Nack the first packet 3 times in a single StretchAck.
- ReceivedPacketInfo received_info;
- received_info.delta_time_largest_observed =
- QuicTime::Delta::FromMilliseconds(5);
- received_info.missing_packets.insert(1);
- received_info.largest_observed = kNumSentPackets;
- EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(_, _)).Times(3);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1);
- manager_.OnIncomingAck(received_info, clock_.Now());
- EXPECT_EQ(
- 1u, QuicSentPacketManagerPeer::GetPendingRetransmissionCount(&manager_));
- EXPECT_EQ(3u, QuicSentPacketManagerPeer::GetNackCount(&manager_, 1));
- EXPECT_EQ(1u, stats_.packets_lost);
-}
-
-// Ack a packet 3 packets ahead, causing a retransmit.
-TEST_F(QuicSentPacketManagerTest, NackRetransmit1PacketSingleAck) {
- const size_t kNumSentPackets = 5;
- // Transmit 5 packets.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
-
- // Nack the first packet 3 times in an AckFrame with three missing packets.
- ReceivedPacketInfo received_info;
- received_info.delta_time_largest_observed =
- QuicTime::Delta::FromMilliseconds(5);
- received_info.missing_packets.insert(1);
- received_info.missing_packets.insert(2);
- received_info.missing_packets.insert(3);
- received_info.largest_observed = 4;
- EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(4, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1);
- manager_.OnIncomingAck(received_info, clock_.Now());
- EXPECT_EQ(
- 1u, QuicSentPacketManagerPeer::GetPendingRetransmissionCount(&manager_));
- EXPECT_EQ(3u, QuicSentPacketManagerPeer::GetNackCount(&manager_, 1));
- EXPECT_EQ(1u, stats_.packets_lost);
-}
-
-TEST_F(QuicSentPacketManagerTest, EarlyRetransmit1Packet) {
- const size_t kNumSentPackets = 2;
- // Transmit 2 packets.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
-
- // Early retransmit when the final packet gets acked and the first is nacked.
- ReceivedPacketInfo received_info;
- received_info.delta_time_largest_observed =
- QuicTime::Delta::FromMilliseconds(5);
- received_info.missing_packets.insert(1);
- received_info.largest_observed = kNumSentPackets;
- EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(kNumSentPackets, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(1, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(1, _)).Times(1);
- manager_.OnIncomingAck(received_info, clock_.Now());
- EXPECT_EQ(
- 1u, QuicSentPacketManagerPeer::GetPendingRetransmissionCount(&manager_));
- EXPECT_EQ(1u, QuicSentPacketManagerPeer::GetNackCount(&manager_, 1));
- EXPECT_EQ(1u, stats_.packets_lost);
-}
-
-TEST_F(QuicSentPacketManagerTest, EarlyRetransmitAllPackets) {
- const size_t kNumSentPackets = 5;
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
-
- // Early retransmit all packets when the final packet arrives, since we do
- // not expect to receive any more acks.
- ReceivedPacketInfo received_info;
- received_info.delta_time_largest_observed =
- QuicTime::Delta::FromMilliseconds(5);
- received_info.missing_packets.insert(1);
- received_info.missing_packets.insert(2);
- received_info.missing_packets.insert(3);
- received_info.missing_packets.insert(4);
- received_info.largest_observed = kNumSentPackets;
- EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
- EXPECT_CALL(*send_algorithm_, OnPacketAcked(5, _)).Times(1);
- EXPECT_CALL(*send_algorithm_, OnPacketLost(_, _)).Times(4);
- EXPECT_CALL(*send_algorithm_, OnPacketAbandoned(_, _)).Times(4);
- manager_.OnIncomingAck(received_info, clock_.Now());
- EXPECT_EQ(
- 4u, QuicSentPacketManagerPeer::GetPendingRetransmissionCount(&manager_));
- EXPECT_EQ(4u, QuicSentPacketManagerPeer::GetNackCount(&manager_, 1));
- EXPECT_EQ(4u, stats_.packets_lost);
-}
-
TEST_F(QuicSentPacketManagerTest, NackRetransmit2Packets) {
const size_t kNumSentPackets = 25;
// Transmit 25 packets.
@@ -821,34 +693,6 @@ TEST_F(QuicSentPacketManagerTest, NackRetransmit2PacketsAlternateAcks) {
}
}
-TEST_F(QuicSentPacketManagerTest, NackTwiceThenAck) {
- // Transmit 4 packets.
- for (QuicPacketSequenceNumber i = 1; i <= 4; ++i) {
- SendDataPacket(i);
- }
-
- // Nack the first packet 2 times, then ack it.
- ReceivedPacketInfo received_info;
- received_info.missing_packets.insert(1);
- for (size_t i = 1; i <= 3; ++i) {
- if (i == 3) {
- received_info.missing_packets.clear();
- }
- received_info.largest_observed = i + 1;
- received_info.delta_time_largest_observed =
- QuicTime::Delta::FromMilliseconds(5);
- EXPECT_CALL(*send_algorithm_, UpdateRtt(_));
- EXPECT_CALL(*send_algorithm_,
- OnPacketAcked(_, _)).Times(i == 3 ? 2 : 1);
- manager_.OnIncomingAck(received_info, clock_.Now());
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- // The nack count is not available once the packet has been acked.
- if (i != 3) {
- EXPECT_EQ(i, QuicSentPacketManagerPeer::GetNackCount(&manager_, 1));
- }
- }
-}
-
TEST_F(QuicSentPacketManagerTest, Rtt) {
QuicPacketSequenceNumber sequence_number = 1;
QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(15);
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 8678268..6147224c2 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -352,13 +352,10 @@ bool QuicSession::HasPendingHandshake() const {
QuicConsumedData QuicSession::WritevData(
QuicStreamId id,
- const struct iovec* iov,
- int iov_count,
+ const IOVector& data,
QuicStreamOffset offset,
bool fin,
QuicAckNotifier::DelegateInterface* ack_notifier_delegate) {
- IOVector data;
- data.AppendIovec(iov, iov_count);
return connection_->SendStreamData(id, data, offset, fin,
ack_notifier_delegate);
}
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 0edf560..fa551bf 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -101,8 +101,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
// this class.
virtual QuicConsumedData WritevData(
QuicStreamId id,
- const struct iovec* iov,
- int iov_count,
+ const IOVector& data,
QuicStreamOffset offset,
bool fin,
QuicAckNotifier::DelegateInterface* ack_notifier_delegate);
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc
index a9e2d1b..bcafa56 100644
--- a/net/quic/quic_unacked_packet_map.cc
+++ b/net/quic/quic_unacked_packet_map.cc
@@ -156,7 +156,6 @@ void QuicUnackedPacketMap::NackPacket(QuicPacketSequenceNumber sequence_number,
void QuicUnackedPacketMap::RemovePacket(
QuicPacketSequenceNumber sequence_number) {
- DVLOG(1) << __FUNCTION__ << " " << sequence_number;
UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
if (it == unacked_packets_.end()) {
LOG(DFATAL) << "packet is not unacked: " << sequence_number;
@@ -175,8 +174,6 @@ void QuicUnackedPacketMap::RemovePacket(
void QuicUnackedPacketMap::NeuterPacket(
QuicPacketSequenceNumber sequence_number) {
- DVLOG(1) << __FUNCTION__ << " " << sequence_number << " pending? "
- << unacked_packets_[sequence_number].pending;
UnackedPacketMap::iterator it = unacked_packets_.find(sequence_number);
if (it == unacked_packets_.end()) {
LOG(DFATAL) << "packet is not unacked: " << sequence_number;
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index 3a11bf7..ce453c1 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -162,6 +162,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_INVALID_GOAWAY_DATA);
RETURN_STRING_LITERAL(QUIC_INVALID_WINDOW_UPDATE_DATA);
RETURN_STRING_LITERAL(QUIC_INVALID_BLOCKED_DATA);
+ RETURN_STRING_LITERAL(QUIC_INVALID_STOP_WAITING_DATA);
RETURN_STRING_LITERAL(QUIC_INVALID_ACK_DATA);
RETURN_STRING_LITERAL(QUIC_INVALID_CONGESTION_FEEDBACK_DATA);
RETURN_STRING_LITERAL(QUIC_INVALID_VERSION_NEGOTIATION_PACKET);
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index 946865d..a37affe 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -182,8 +182,13 @@ QuicConsumedData ReliableQuicStream::WritevData(
write_length += iov[i].iov_len;
// TODO(rjshade): Maybe block write based on available flow control window.
}
+
+ // Fill an IOVector with bytes from the iovec.
+ IOVector data;
+ data.AppendIovecAtMostBytes(iov, iov_count, write_length);
+
QuicConsumedData consumed_data = session()->WritevData(
- id(), iov, iov_count, stream_bytes_written_, fin, ack_notifier_delegate);
+ id(), data, stream_bytes_written_, fin, ack_notifier_delegate);
stream_bytes_written_ += consumed_data.bytes_consumed;
if (consumed_data.bytes_consumed == write_length) {
if (fin && consumed_data.fin_consumed) {
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index 389d910..3b47362 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -134,7 +134,7 @@ TEST_F(ReliableQuicStreamTest, WriteAllData) {
1 + QuicPacketCreator::StreamFramePacketOverhead(
connection_->version(), PACKET_8BYTE_GUID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
- EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _, _)).WillOnce(
+ EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
Return(QuicConsumedData(kDataLen, true)));
stream_->WriteOrBufferData(kData1, false);
EXPECT_FALSE(write_blocked_list_->HasWriteBlockedStreams());
@@ -154,7 +154,7 @@ TEST_F(ReliableQuicStreamTest, BlockIfOnlySomeDataConsumed) {
// Write some data and no fin. If we consume some but not all of the data,
// we should be write blocked a not all the data was consumed.
- EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _, _)).WillOnce(
+ EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
Return(QuicConsumedData(1, false)));
stream_->WriteOrBufferData(StringPiece(kData1, 2), false);
ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
@@ -168,7 +168,7 @@ TEST_F(ReliableQuicStreamTest, BlockIfFinNotConsumedWithData) {
// we should be write blocked because the fin was not consumed.
// (This should never actually happen as the fin should be sent out with the
// last data)
- EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _, _)).WillOnce(
+ EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
Return(QuicConsumedData(2, false)));
stream_->WriteOrBufferData(StringPiece(kData1, 2), true);
ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
@@ -179,7 +179,7 @@ TEST_F(ReliableQuicStreamTest, BlockIfSoloFinNotConsumed) {
// Write no data and a fin. If we consume nothing we should be write blocked,
// as the fin was not consumed.
- EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _, _)).WillOnce(
+ EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
Return(QuicConsumedData(0, false)));
stream_->WriteOrBufferData(StringPiece(), true);
ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
@@ -193,7 +193,7 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferData) {
1 + QuicPacketCreator::StreamFramePacketOverhead(
connection_->version(), PACKET_8BYTE_GUID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
- EXPECT_CALL(*session_, WritevData(_, _, 1, _, _, _)).WillOnce(
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).WillOnce(
Return(QuicConsumedData(kDataLen - 1, false)));
stream_->WriteOrBufferData(kData1, false);
EXPECT_TRUE(write_blocked_list_->HasWriteBlockedStreams());
@@ -203,14 +203,14 @@ TEST_F(ReliableQuicStreamTest, WriteOrBufferData) {
// Make sure we get the tail of the first write followed by the bytes_consumed
InSequence s;
- EXPECT_CALL(*session_, WritevData(_, _, 1, _, _, _)).
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).
WillOnce(Return(QuicConsumedData(1, false)));
- EXPECT_CALL(*session_, WritevData(_, _, 1, _, _, _)).
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).
WillOnce(Return(QuicConsumedData(kDataLen - 2, false)));
stream_->OnCanWrite();
// And finally the end of the bytes_consumed.
- EXPECT_CALL(*session_, WritevData(_, _, 1, _, _, _)).
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).
WillOnce(Return(QuicConsumedData(2, true)));
stream_->OnCanWrite();
}
@@ -237,7 +237,7 @@ TEST_F(ReliableQuicStreamTest, RstAlwaysSentIfNoFinSent) {
EXPECT_FALSE(rst_sent());
// Write some data, with no FIN.
- EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _, _)).WillOnce(
+ EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
Return(QuicConsumedData(1, false)));
stream_->WriteOrBufferData(StringPiece(kData1, 1), false);
EXPECT_FALSE(fin_sent());
@@ -260,7 +260,7 @@ TEST_F(ReliableQuicStreamTest, RstNotSentIfFinSent) {
EXPECT_FALSE(rst_sent());
// Write some data, with FIN.
- EXPECT_CALL(*session_, WritevData(kStreamId, _, 1, _, _, _)).WillOnce(
+ EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(
Return(QuicConsumedData(1, true)));
stream_->WriteOrBufferData(StringPiece(kData1, 1), true);
EXPECT_TRUE(fin_sent());
diff --git a/net/quic/test_tools/quic_test_packet_maker.cc b/net/quic/test_tools/quic_test_packet_maker.cc
index 6969740..1fadb29 100644
--- a/net/quic/test_tools/quic_test_packet_maker.cc
+++ b/net/quic/test_tools/quic_test_packet_maker.cc
@@ -71,6 +71,12 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckAndRstPacket(
frames.push_back(QuicFrame(&feedback));
}
+ if (version_ > QUIC_VERSION_15) {
+ QuicStopWaitingFrame stop_waiting;
+ stop_waiting.least_unacked = least_unacked;
+ frames.push_back(QuicFrame(&stop_waiting));
+ }
+
QuicRstStreamFrame rst(stream_id, error_code, 0);
frames.push_back(QuicFrame(&rst));
@@ -126,6 +132,13 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckPacket(
if (send_feedback) {
frames.push_back(QuicFrame(&feedback));
}
+
+ if (version_ > QUIC_VERSION_15) {
+ QuicStopWaitingFrame stop_waiting;
+ stop_waiting.least_unacked = least_unacked;
+ frames.push_back(QuicFrame(&stop_waiting));
+ }
+
scoped_ptr<QuicPacket> packet(
framer.BuildUnsizedDataPacket(header, frames).packet);
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 745237a..5268149 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -65,6 +65,9 @@ MockFramerVisitor::MockFramerVisitor() {
ON_CALL(*this, OnCongestionFeedbackFrame(_))
.WillByDefault(testing::Return(true));
+ ON_CALL(*this, OnStopWaitingFrame(_))
+ .WillByDefault(testing::Return(true));
+
ON_CALL(*this, OnRstStreamFrame(_))
.WillByDefault(testing::Return(true));
@@ -109,6 +112,11 @@ bool NoOpFramerVisitor::OnCongestionFeedbackFrame(
return true;
}
+bool NoOpFramerVisitor::OnStopWaitingFrame(
+ const QuicStopWaitingFrame& frame) {
+ return true;
+}
+
bool NoOpFramerVisitor::OnRstStreamFrame(
const QuicRstStreamFrame& frame) {
return true;
@@ -184,6 +192,13 @@ bool FramerVisitorCapturingFrames::OnCongestionFeedbackFrame(
return true;
}
+bool FramerVisitorCapturingFrames::OnStopWaitingFrame(
+ const QuicStopWaitingFrame& frame) {
+ stop_waiting_.reset(new QuicStopWaitingFrame(frame));
+ ++frame_count_;
+ return true;
+}
+
bool FramerVisitorCapturingFrames::OnRstStreamFrame(
const QuicRstStreamFrame& frame) {
rst_.reset(new QuicRstStreamFrame(frame));
@@ -325,7 +340,7 @@ bool PacketSavingConnection::SendOrQueuePacket(
MockSession::MockSession(QuicConnection* connection)
: QuicSession(connection, DefaultQuicConfig()) {
- ON_CALL(*this, WritevData(_, _, _, _, _, _))
+ ON_CALL(*this, WritevData(_, _, _, _, _))
.WillByDefault(testing::Return(QuicConsumedData(0, false)));
}
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index d175600..ffe3b13 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -108,6 +108,7 @@ class MockFramerVisitor : public QuicFramerVisitorInterface {
MOCK_METHOD1(OnAckFrame, bool(const QuicAckFrame& frame));
MOCK_METHOD1(OnCongestionFeedbackFrame,
bool(const QuicCongestionFeedbackFrame& frame));
+ MOCK_METHOD1(OnStopWaitingFrame, bool(const QuicStopWaitingFrame& frame));
MOCK_METHOD1(OnFecData, void(const QuicFecData& fec));
MOCK_METHOD1(OnRstStreamFrame, bool(const QuicRstStreamFrame& frame));
MOCK_METHOD1(OnConnectionCloseFrame,
@@ -142,6 +143,8 @@ class NoOpFramerVisitor : public QuicFramerVisitorInterface {
virtual bool OnAckFrame(const QuicAckFrame& frame) OVERRIDE;
virtual bool OnCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame) OVERRIDE;
+ virtual bool OnStopWaitingFrame(
+ const QuicStopWaitingFrame& frame) OVERRIDE;
virtual void OnFecData(const QuicFecData& fec) OVERRIDE {}
virtual bool OnRstStreamFrame(const QuicRstStreamFrame& frame) OVERRIDE;
virtual bool OnConnectionCloseFrame(
@@ -187,6 +190,8 @@ class FramerVisitorCapturingFrames : public NoOpFramerVisitor {
virtual bool OnAckFrame(const QuicAckFrame& frame) OVERRIDE;
virtual bool OnCongestionFeedbackFrame(
const QuicCongestionFeedbackFrame& frame) OVERRIDE;
+ virtual bool OnStopWaitingFrame(
+ const QuicStopWaitingFrame& frame) OVERRIDE;
virtual bool OnRstStreamFrame(const QuicRstStreamFrame& frame) OVERRIDE;
virtual bool OnConnectionCloseFrame(
const QuicConnectionCloseFrame& frame) OVERRIDE;
@@ -202,6 +207,7 @@ class FramerVisitorCapturingFrames : public NoOpFramerVisitor {
}
QuicAckFrame* ack() { return ack_.get(); }
QuicCongestionFeedbackFrame* feedback() { return feedback_.get(); }
+ QuicStopWaitingFrame* stop_waiting() { return stop_waiting_.get(); }
QuicRstStreamFrame* rst() { return rst_.get(); }
QuicConnectionCloseFrame* close() { return close_.get(); }
QuicGoAwayFrame* goaway() { return goaway_.get(); }
@@ -216,6 +222,7 @@ class FramerVisitorCapturingFrames : public NoOpFramerVisitor {
std::vector<std::string*> stream_data_;
scoped_ptr<QuicAckFrame> ack_;
scoped_ptr<QuicCongestionFeedbackFrame> feedback_;
+ scoped_ptr<QuicStopWaitingFrame> stop_waiting_;
scoped_ptr<QuicRstStreamFrame> rst_;
scoped_ptr<QuicConnectionCloseFrame> close_;
scoped_ptr<QuicGoAwayFrame> goaway_;
@@ -342,10 +349,9 @@ class MockSession : public QuicSession {
MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id));
MOCK_METHOD0(GetCryptoStream, QuicCryptoStream*());
MOCK_METHOD0(CreateOutgoingDataStream, QuicDataStream*());
- MOCK_METHOD6(WritevData,
+ MOCK_METHOD5(WritevData,
QuicConsumedData(QuicStreamId id,
- const struct iovec* iov,
- int count,
+ const IOVector& data,
QuicStreamOffset offset,
bool fin,
QuicAckNotifier::DelegateInterface*));
diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc
index 21b6c1f..fca7f79 100644
--- a/net/quic/test_tools/simple_quic_framer.cc
+++ b/net/quic/test_tools/simple_quic_framer.cc
@@ -80,6 +80,11 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface {
return true;
}
+ virtual bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) OVERRIDE {
+ stop_waiting_frames_.push_back(frame);
+ return true;
+ }
+
virtual void OnFecData(const QuicFecData& fec) OVERRIDE {
fec_data_ = fec;
fec_redundancy_ = fec_data_.redundancy.as_string();
@@ -102,8 +107,8 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface {
return true;
}
- virtual bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame)
- OVERRIDE {
+ virtual bool OnWindowUpdateFrame(
+ const QuicWindowUpdateFrame& frame) OVERRIDE {
window_update_frames_.push_back(frame);
return true;
}
@@ -132,6 +137,9 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface {
const vector<QuicStreamFrame>& stream_frames() const {
return stream_frames_;
}
+ const vector<QuicStopWaitingFrame>& stop_waiting_frames() const {
+ return stop_waiting_frames_;
+ }
const vector<QuicWindowUpdateFrame>& window_update_frames() const {
return window_update_frames_;
}
@@ -150,6 +158,7 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface {
string fec_redundancy_;
vector<QuicAckFrame> ack_frames_;
vector<QuicCongestionFeedbackFrame> feedback_frames_;
+ vector<QuicStopWaitingFrame> stop_waiting_frames_;
vector<QuicStreamFrame> stream_frames_;
vector<QuicRstStreamFrame> rst_stream_frames_;
vector<QuicGoAwayFrame> goaway_frames_;
@@ -198,10 +207,11 @@ QuicFramer* SimpleQuicFramer::framer() {
size_t SimpleQuicFramer::num_frames() const {
return ack_frames().size() +
- stream_frames().size() +
feedback_frames().size() +
- rst_stream_frames().size() +
goaway_frames().size() +
+ rst_stream_frames().size() +
+ stop_waiting_frames().size() +
+ stream_frames().size() +
connection_close_frames().size();
}
@@ -209,6 +219,11 @@ const vector<QuicAckFrame>& SimpleQuicFramer::ack_frames() const {
return visitor_->ack_frames();
}
+const vector<QuicStopWaitingFrame>&
+SimpleQuicFramer::stop_waiting_frames() const {
+ return visitor_->stop_waiting_frames();
+}
+
const vector<QuicStreamFrame>& SimpleQuicFramer::stream_frames() const {
return visitor_->stream_frames();
}
diff --git a/net/quic/test_tools/simple_quic_framer.h b/net/quic/test_tools/simple_quic_framer.h
index fe742ca..6f4908a 100644
--- a/net/quic/test_tools/simple_quic_framer.h
+++ b/net/quic/test_tools/simple_quic_framer.h
@@ -41,6 +41,7 @@ class SimpleQuicFramer {
const std::vector<QuicAckFrame>& ack_frames() const;
const std::vector<QuicConnectionCloseFrame>& connection_close_frames() const;
const std::vector<QuicCongestionFeedbackFrame>& feedback_frames() const;
+ const std::vector<QuicStopWaitingFrame>& stop_waiting_frames() const;
const std::vector<QuicGoAwayFrame>& goaway_frames() const;
const std::vector<QuicRstStreamFrame>& rst_stream_frames() const;
const std::vector<QuicStreamFrame>& stream_frames() const;