diff options
author | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-27 00:09:03 +0000 |
---|---|---|
committer | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-27 00:09:03 +0000 |
commit | 93dd91ff7c039a6db4798f40b212e1aaa380befb (patch) | |
tree | d8577ffd679249784cedf8cd4b3d3511cdb538fe /net/quic | |
parent | 91256e4f440f2588594359fe5e3ac78636448f1f (diff) | |
download | chromium_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')
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; |