summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-05 19:43:06 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-05 19:43:06 +0000
commit3e60db87c3efc64a62a24e8dbd973ef8a83f420a (patch)
tree595f10254a4dcc4dcf36bd4ea3465a2b35db8a66
parentf0eda8165420562d6769b19f0126d5158dabd817 (diff)
downloadchromium_src-3e60db87c3efc64a62a24e8dbd973ef8a83f420a.zip
chromium_src-3e60db87c3efc64a62a24e8dbd973ef8a83f420a.tar.gz
chromium_src-3e60db87c3efc64a62a24e8dbd973ef8a83f420a.tar.bz2
Land Recent QUIC changes.
Minor style change for initialization of hdr.msg_flags. Merge internal change: 49828095 Enabled MaxNumStreams in quic/tools area. Renamed MaxNumConnections to MaxNumStreams. Initialize set_max_streams_per_connection only in MaxNumStreams, not for all tests. Merge internal change: 49728455 QUIC - Adding a bit more information to a logged DFATAL. Merge internal change: 49724887 Always expecting certificates for secure quic (test) clients. Changing the end_to_end test to be insecure as it doesn't configure certs. Merge internal change: 49723287 QUIC - Adding back a comment change that was deleted in the following CL. https://chromiumcodereview.appspot.com/22020002/diff/1/net/quic/quic_connection.cc Merge internal change: 49713074 Fail to process a header when the fec group offset is larger than the packet sequence number. Merge internal change: 49677837 Added a test to ensure that if the QuicPacketCreator has room for the stream frame it can be added. Merge internal change: 49620569 Adding support to QUIC for QUIC_VERSION_7, enabling lower overhead stream frames. Merge internal change: 49540337 Rearrange code to match spdy_protocol.h SpdyFrameType declaration order: mostly method declarations and definitions and case statements. Merge internal change: 49503521 Refactor QuicReceivedEntropyManager and the other received packet code into Quic ReceivedPacketManager to allow the entropy state and the ack's received info to stay in sync. Merge internal change: 49440136 Made a copy of QuicReceivedEntropyManager*.* code into QuicReceivedPacketManager*.* Doing a better job of detecting unrecoverable compression state. This is really tricky to get right. We don't want to unilaterally close the connection if a stream closes before headers are decompressed. If, for example, a server gets a protocol-layer error while processing a request it could kill of a stream with something like QUIC_MULTIPLE_TERMINATION_OFFSETS without sending the http/spdy response. In this case, the client could continue processing on that connection. We basically want to kill off the connection if we get any packets for a stream we've closed without processing complete headers. Which means tracking state for every stream which closes without processing complete headers which is a very unlikely OOM attack vector. I'm capping it at 20 somewhat arbitrarily, and calling it a day. Merge internal change: 49373258 Removing logspam from quic connection. Merge internal change: 49370853 Altering the server to not process headers until full headers have been read. This fixes a problem where if we parsed partial headers, found an error, and rejected the stream before getting full headers it would be possible to doom the entire connection. Merge internal change: 49239328 R=rch@chromium.org Review URL: https://chromiumcodereview.appspot.com/22122002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@215661 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/net.gyp8
-rw-r--r--net/quic/quic_connection.cc191
-rw-r--r--net/quic/quic_connection.h38
-rw-r--r--net/quic/quic_connection_helper_test.cc6
-rw-r--r--net/quic/quic_connection_test.cc94
-rw-r--r--net/quic/quic_framer.cc377
-rw-r--r--net/quic/quic_framer.h52
-rw-r--r--net/quic/quic_framer_test.cc853
-rw-r--r--net/quic/quic_http_stream_test.cc2
-rw-r--r--net/quic/quic_network_transaction_unittest.cc4
-rw-r--r--net/quic/quic_packet_creator.cc24
-rw-r--r--net/quic/quic_packet_creator.h3
-rw-r--r--net/quic/quic_packet_creator_test.cc30
-rw-r--r--net/quic/quic_packet_generator.cc2
-rw-r--r--net/quic/quic_protocol.cc14
-rw-r--r--net/quic/quic_protocol.h6
-rw-r--r--net/quic/quic_protocol_test.cc8
-rw-r--r--net/quic/quic_received_entropy_manager.cc98
-rw-r--r--net/quic/quic_received_entropy_manager.h70
-rw-r--r--net/quic/quic_received_entropy_manager_test.cc99
-rw-r--r--net/quic/quic_received_packet_manager.cc188
-rw-r--r--net/quic/quic_received_packet_manager.h124
-rw-r--r--net/quic/quic_received_packet_manager_test.cc119
-rw-r--r--net/quic/quic_session.cc24
-rw-r--r--net/quic/quic_session.h10
-rw-r--r--net/quic/quic_spdy_decompressor.cc34
-rw-r--r--net/quic/quic_stream_factory_test.cc4
-rw-r--r--net/quic/reliable_quic_stream.h2
-rw-r--r--net/quic/reliable_quic_stream_test.cc4
-rw-r--r--net/quic/test_tools/quic_connection_peer.cc8
-rw-r--r--net/quic/test_tools/quic_connection_peer.h2
-rw-r--r--net/quic/test_tools/quic_received_packet_manager_peer.cc30
-rw-r--r--net/quic/test_tools/quic_received_packet_manager_peer.h35
-rw-r--r--net/quic/test_tools/quic_test_utils.cc18
-rw-r--r--net/quic/test_tools/quic_test_utils.h10
-rw-r--r--net/quic/test_tools/reliable_quic_stream_peer.cc6
-rw-r--r--net/quic/test_tools/reliable_quic_stream_peer.h2
-rw-r--r--net/tools/quic/end_to_end_test.cc23
-rw-r--r--net/tools/quic/quic_client.cc8
-rw-r--r--net/tools/quic/quic_client.h5
-rw-r--r--net/tools/quic/quic_client_session_test.cc4
-rw-r--r--net/tools/quic/quic_dispatcher.cc3
-rw-r--r--net/tools/quic/quic_dispatcher_test.cc2
-rw-r--r--net/tools/quic/quic_epoll_connection_helper_test.cc5
-rw-r--r--net/tools/quic/quic_socket_utils.cc2
-rw-r--r--net/tools/quic/quic_time_wait_list_manager.cc4
-rw-r--r--net/tools/quic/test_tools/quic_test_client.cc94
-rw-r--r--net/tools/quic/test_tools/quic_test_client.h26
48 files changed, 1969 insertions, 806 deletions
diff --git a/net/net.gyp b/net/net.gyp
index a973e08..70436d1 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -815,8 +815,8 @@
'quic/quic_packet_generator.h',
'quic/quic_protocol.cc',
'quic/quic_protocol.h',
- 'quic/quic_received_entropy_manager.cc',
- 'quic/quic_received_entropy_manager.h',
+ 'quic/quic_received_packet_manager.cc',
+ 'quic/quic_received_packet_manager.h',
'quic/quic_reliable_client_stream.cc',
'quic/quic_reliable_client_stream.h',
'quic/quic_sent_entropy_manager.cc',
@@ -1714,6 +1714,8 @@
'quic/test_tools/quic_framer_peer.h',
'quic/test_tools/quic_packet_creator_peer.cc',
'quic/test_tools/quic_packet_creator_peer.h',
+ 'quic/test_tools/quic_received_packet_manager_peer.cc',
+ 'quic/test_tools/quic_received_packet_manager_peer.h',
'quic/test_tools/quic_session_peer.cc',
'quic/test_tools/quic_session_peer.h',
'quic/test_tools/quic_test_utils.cc',
@@ -1741,7 +1743,7 @@
'quic/quic_packet_creator_test.cc',
'quic/quic_packet_generator_test.cc',
'quic/quic_protocol_test.cc',
- 'quic/quic_received_entropy_manager_test.cc',
+ 'quic/quic_received_packet_manager_test.cc',
'quic/quic_reliable_client_stream_test.cc',
'quic/quic_sent_entropy_manager_test.cc',
'quic/quic_session_test.cc',
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 4badfa7..ea738af 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -81,9 +81,6 @@ QuicConnection::QuicConnection(QuicGuid guid,
guid_(guid),
peer_address_(address),
largest_seen_packet_with_ack_(0),
- peer_largest_observed_packet_(0),
- least_packet_awaited_by_peer_(1),
- peer_least_packet_awaiting_ack_(0),
handling_retransmission_timeout_(false),
write_blocked_(false),
debug_visitor_(NULL),
@@ -95,7 +92,6 @@ QuicConnection::QuicConnection(QuicGuid guid,
creation_time_(clock_->ApproximateNow()),
time_of_last_received_packet_(clock_->ApproximateNow()),
time_of_last_sent_packet_(clock_->ApproximateNow()),
- time_largest_observed_(QuicTime::Zero()),
congestion_manager_(clock_, kTCP),
version_negotiation_state_(START_NEGOTIATION),
max_packets_per_retransmission_alarm_(kMaxPacketsPerRetransmissionAlarm),
@@ -107,11 +103,7 @@ QuicConnection::QuicConnection(QuicGuid guid,
helper_->SetConnection(this);
helper_->SetTimeoutAlarm(idle_network_timeout_);
framer_.set_visitor(this);
- framer_.set_received_entropy_calculator(&received_entropy_manager_);
- outgoing_ack_.sent_info.least_unacked = 0;
- outgoing_ack_.sent_info.entropy_hash = 0;
- outgoing_ack_.received_info.largest_observed = 0;
- outgoing_ack_.received_info.entropy_hash = 0;
+ framer_.set_received_entropy_calculator(&received_packet_manager_);
/*
if (FLAGS_fake_packet_loss_percentage > 0) {
@@ -130,7 +122,6 @@ QuicConnection::~QuicConnection() {
it != queued_packets_.end(); ++it) {
delete it->packet;
}
- DLOG(INFO) << ENDPOINT << "write_blocked: " << write_blocked_;
}
bool QuicConnection::SelectMutualVersion(
@@ -290,8 +281,8 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
// If this packet has already been seen, or that the sender
// has told us will not be retransmitted, then stop processing the packet.
- if (!IsAwaitingPacket(outgoing_ack_.received_info,
- header.packet_sequence_number)) {
+ if (!received_packet_manager_.IsAwaitingPacket(
+ header.packet_sequence_number)) {
return false;
}
@@ -366,8 +357,20 @@ bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) {
incoming_ack.received_info.missing_packets.size() >=
QuicFramer::GetMaxUnackedPackets(last_header_);
- UpdatePacketInformationReceivedByPeer(incoming_ack);
- UpdatePacketInformationSentByPeer(incoming_ack);
+ received_packet_manager_.UpdatePacketInformationReceivedByPeer(incoming_ack);
+ received_packet_manager_.UpdatePacketInformationSentByPeer(incoming_ack);
+ // Possibly close any FecGroups which are now irrelevant.
+ CloseFecGroupsBefore(incoming_ack.sent_info.least_unacked + 1);
+
+ sent_entropy_manager_.ClearEntropyBefore(
+ received_packet_manager_.least_packet_awaited_by_peer() - 1);
+
+ SequenceNumberSet acked_packets;
+ HandleAckForSentPackets(incoming_ack, &acked_packets);
+ HandleAckForSentFecPackets(incoming_ack, &acked_packets);
+ if (acked_packets.size() > 0) {
+ visitor_->OnAck(acked_packets);
+ }
congestion_manager_.OnIncomingAckFrame(incoming_ack,
time_of_last_received_packet_);
@@ -407,10 +410,10 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
}
if (incoming_ack.received_info.largest_observed <
- peer_largest_observed_packet_) {
+ received_packet_manager_.peer_largest_observed_packet()) {
DLOG(ERROR) << ENDPOINT << "Peer's largest_observed packet decreased:"
<< incoming_ack.received_info.largest_observed << " vs "
- << peer_largest_observed_packet_;
+ << received_packet_manager_.peer_largest_observed_packet();
// A new ack has a diminished largest_observed value. Error out.
// If this was an old packet, we wouldn't even have checked.
return false;
@@ -421,10 +424,11 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
DCHECK_LE(incoming_ack.received_info.missing_packets.size(),
QuicFramer::GetMaxUnackedPackets(last_header_));
- if (incoming_ack.sent_info.least_unacked < peer_least_packet_awaiting_ack_) {
+ 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 " << peer_least_packet_awaiting_ack_;
+ << 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;
}
@@ -450,11 +454,11 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
if (!incoming_ack.received_info.missing_packets.empty() &&
*incoming_ack.received_info.missing_packets.begin() <
- least_packet_awaited_by_peer_) {
+ received_packet_manager_.least_packet_awaited_by_peer()) {
DLOG(ERROR) << ENDPOINT << "Peer sent missing packet: "
<< *incoming_ack.received_info.missing_packets.begin()
<< "smaller than least_packet_awaited_by_peer_: "
- << least_packet_awaited_by_peer_;
+ << received_packet_manager_.least_packet_awaited_by_peer();
return false;
}
@@ -477,7 +481,8 @@ void QuicConnection::HandleAckForSentPackets(const QuicAckFrame& incoming_ack,
UnackedPacketMap::iterator it = unacked_packets_.begin();
while (it != unacked_packets_.end()) {
QuicPacketSequenceNumber sequence_number = it->first;
- if (sequence_number > peer_largest_observed_packet_) {
+ if (sequence_number >
+ received_packet_manager_.peer_largest_observed_packet()) {
// These are very new sequence_numbers.
break;
}
@@ -519,7 +524,8 @@ void QuicConnection::HandleAckForSentFecPackets(
UnackedPacketMap::iterator it = unacked_fec_packets_.begin();
while (it != unacked_fec_packets_.end()) {
QuicPacketSequenceNumber sequence_number = it->first;
- if (sequence_number > peer_largest_observed_packet_) {
+ if (sequence_number >
+ received_packet_manager_.peer_largest_observed_packet()) {
break;
}
if (!IsAwaitingPacket(incoming_ack.received_info, sequence_number)) {
@@ -534,68 +540,6 @@ void QuicConnection::HandleAckForSentFecPackets(
}
}
-void QuicConnection::UpdatePacketInformationReceivedByPeer(
- const QuicAckFrame& incoming_ack) {
- // ValidateAck should fail if largest_observed ever shrinks.
- DCHECK_LE(peer_largest_observed_packet_,
- incoming_ack.received_info.largest_observed);
- peer_largest_observed_packet_ = incoming_ack.received_info.largest_observed;
-
- if (incoming_ack.received_info.missing_packets.empty()) {
- least_packet_awaited_by_peer_ = peer_largest_observed_packet_ + 1;
- } else {
- least_packet_awaited_by_peer_ =
- *(incoming_ack.received_info.missing_packets.begin());
- }
-
- sent_entropy_manager_.ClearEntropyBefore(least_packet_awaited_by_peer_ - 1);
-
- SequenceNumberSet acked_packets;
- HandleAckForSentPackets(incoming_ack, &acked_packets);
- HandleAckForSentFecPackets(incoming_ack, &acked_packets);
-
- if (acked_packets.size() > 0) {
- visitor_->OnAck(acked_packets);
- }
-}
-
-bool QuicConnection::DontWaitForPacketsBefore(
- QuicPacketSequenceNumber least_unacked) {
- size_t missing_packets_count =
- outgoing_ack_.received_info.missing_packets.size();
- outgoing_ack_.received_info.missing_packets.erase(
- outgoing_ack_.received_info.missing_packets.begin(),
- outgoing_ack_.received_info.missing_packets.lower_bound(least_unacked));
- return missing_packets_count !=
- outgoing_ack_.received_info.missing_packets.size();
-}
-
-void QuicConnection::UpdatePacketInformationSentByPeer(
- const QuicAckFrame& incoming_ack) {
- // ValidateAck() should fail if peer_least_packet_awaiting_ack_ shrinks.
- DCHECK_LE(peer_least_packet_awaiting_ack_,
- incoming_ack.sent_info.least_unacked);
- if (incoming_ack.sent_info.least_unacked > peer_least_packet_awaiting_ack_) {
- bool missed_packets =
- DontWaitForPacketsBefore(incoming_ack.sent_info.least_unacked);
- if (missed_packets || incoming_ack.sent_info.least_unacked >
- outgoing_ack_.received_info.largest_observed + 1) {
- DVLOG(1) << ENDPOINT << "Updating entropy hashed since we missed packets";
- // There were some missing packets that we won't ever get now. Recalculate
- // the received entropy hash.
- received_entropy_manager_.RecalculateEntropyHash(
- incoming_ack.sent_info.least_unacked,
- incoming_ack.sent_info.entropy_hash);
- }
- peer_least_packet_awaiting_ack_ = incoming_ack.sent_info.least_unacked;
- }
- DCHECK(outgoing_ack_.received_info.missing_packets.empty() ||
- *outgoing_ack_.received_info.missing_packets.begin() >=
- peer_least_packet_awaiting_ack_);
- // Possibly close any FecGroups which are now irrelevant
- CloseFecGroupsBefore(incoming_ack.sent_info.least_unacked + 1);
-}
-
void QuicConnection::OnFecData(const QuicFecData& fec) {
DCHECK_EQ(IN_FEC_GROUP, last_header_.is_in_fec_group);
DCHECK_NE(0u, last_header_.fec_group);
@@ -662,7 +606,8 @@ void QuicConnection::OnPacketComplete() {
if ((last_stream_frames_.empty() ||
visitor_->OnPacket(self_address_, peer_address_,
last_header_, last_stream_frames_))) {
- RecordPacketReceived(last_header_);
+ received_packet_manager_.RecordPacketReceived(
+ last_header_, time_of_last_received_packet_);
}
MaybeSendAckInResponseToPacket();
@@ -670,19 +615,12 @@ void QuicConnection::OnPacketComplete() {
}
QuicAckFrame* QuicConnection::CreateAckFrame() {
- UpdateOutgoingAck();
- if (time_largest_observed_ == QuicTime::Zero()) {
- // We have not received any new higher sequence numbers since we sent our
- // last ACK.
- outgoing_ack_.received_info.delta_time_largest_observed =
- QuicTime::Delta::Infinite();
- } else {
- outgoing_ack_.received_info.delta_time_largest_observed =
- clock_->ApproximateNow().Subtract(time_largest_observed_);
-
- time_largest_observed_ = QuicTime::Zero();
- }
- return new QuicAckFrame(outgoing_ack_);
+ QuicAckFrame* outgoing_ack = new QuicAckFrame();
+ received_packet_manager_.UpdateReceivedPacketInfo(
+ &(outgoing_ack->received_info), clock_->ApproximateNow());
+ UpdateSentPacketInfo(&(outgoing_ack->sent_info));
+ DVLOG(1) << ENDPOINT << "Creating ack frame: " << *outgoing_ack;
+ return outgoing_ack;
}
QuicCongestionFeedbackFrame* QuicConnection::CreateFeedbackFrame() {
@@ -859,34 +797,6 @@ bool QuicConnection::WriteQueuedPackets() {
return !write_blocked_;
}
-void QuicConnection::RecordPacketReceived(const QuicPacketHeader& header) {
- QuicPacketSequenceNumber sequence_number = header.packet_sequence_number;
- DCHECK(IsAwaitingPacket(outgoing_ack_.received_info, sequence_number));
-
- InsertMissingPacketsBetween(
- &outgoing_ack_.received_info,
- max(outgoing_ack_.received_info.largest_observed + 1,
- peer_least_packet_awaiting_ack_),
- header.packet_sequence_number);
-
- if (outgoing_ack_.received_info.largest_observed >
- header.packet_sequence_number) {
- // We've gotten one of the out of order packets - remove it from our
- // "missing packets" list.
- DVLOG(1) << ENDPOINT << "Removing " << sequence_number
- << " from missing list";
- outgoing_ack_.received_info.missing_packets.erase(sequence_number);
- }
- if (header.packet_sequence_number >
- outgoing_ack_.received_info.largest_observed) {
- outgoing_ack_.received_info.largest_observed =
- header.packet_sequence_number;
- time_largest_observed_ = time_of_last_received_packet_;
- }
- received_entropy_manager_.RecordPacketEntropyHash(
- sequence_number, header.entropy_hash);
-}
-
bool QuicConnection::MaybeRetransmitPacketForRTO(
QuicPacketSequenceNumber sequence_number) {
DCHECK_EQ(ContainsKey(unacked_packets_, sequence_number),
@@ -906,8 +816,8 @@ bool QuicConnection::MaybeRetransmitPacketForRTO(
// any RTO for packets larger than the peer's largest observed packet; it may
// have been received by the peer and just wasn't acked due to the ack frame
// running out of space.
- if (received_truncated_ack_ &&
- sequence_number > peer_largest_observed_packet_ &&
+ if (received_truncated_ack_ && sequence_number >
+ received_packet_manager_.peer_largest_observed_packet() &&
// We allow retransmission of already retransmitted packets so that we
// retransmit packets that were retransmissions of the packet with
// sequence number < the largest observed field of the truncated ack.
@@ -1128,7 +1038,7 @@ bool QuicConnection::WritePacket(EncryptionLevel level,
DCHECK(encrypted->length() <= kMaxPacketSize)
<< "Packet " << sequence_number << " will not be read; too large: "
<< packet->length() << " " << encrypted->length() << " "
- << outgoing_ack_ << " forced: " << (forced == FORCE ? "yes" : "no");
+ << " forced: " << (forced == FORCE ? "yes" : "no");
int error;
QuicTime now = clock_->Now();
@@ -1245,27 +1155,21 @@ bool QuicConnection::ShouldSimulateLostPacket() {
*/
}
-void QuicConnection::UpdateOutgoingAck() {
+void QuicConnection::UpdateSentPacketInfo(SentPacketInfo* sent_info) {
if (!unacked_packets_.empty()) {
- outgoing_ack_.sent_info.least_unacked = unacked_packets_.begin()->first;
+ sent_info->least_unacked = unacked_packets_.begin()->first;
} else {
// If there are no unacked packets, set the least unacked packet to
// sequence_number() + 1 since that will be the sequence number of this
// ack packet whenever it is sent.
- outgoing_ack_.sent_info.least_unacked =
- packet_creator_.sequence_number() + 1;
+ sent_info->least_unacked = packet_creator_.sequence_number() + 1;
}
- outgoing_ack_.sent_info.entropy_hash = sent_entropy_manager_.EntropyHash(
- outgoing_ack_.sent_info.least_unacked - 1);
- outgoing_ack_.received_info.entropy_hash =
- received_entropy_manager_.EntropyHash(
- outgoing_ack_.received_info.largest_observed);
+ sent_info->entropy_hash = sent_entropy_manager_.EntropyHash(
+ sent_info->least_unacked - 1);
}
void QuicConnection::SendAck() {
helper_->ClearAckAlarm();
- UpdateOutgoingAck();
- DVLOG(1) << ENDPOINT << "Sending ack: " << outgoing_ack_;
// TODO(rch): delay this until the CreateFeedbackFrame
// method is invoked. This requires changes SetShouldSendAck
@@ -1464,8 +1368,9 @@ void QuicConnection::SendConnectionClosePacket(QuicErrorCode error,
QuicConnectionCloseFrame frame;
frame.error_code = error;
frame.error_details = details;
- UpdateOutgoingAck();
- frame.ack_frame = outgoing_ack_;
+ UpdateSentPacketInfo(&frame.ack_frame.sent_info);
+ received_packet_manager_.UpdateReceivedPacketInfo(
+ &frame.ack_frame.received_info, clock_->ApproximateNow());
SerializedPacket serialized_packet =
packet_creator_.SerializeConnectionClose(&frame);
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 8f4f3f1..4ac4fa4 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -32,7 +32,7 @@
#include "net/quic/quic_packet_creator.h"
#include "net/quic/quic_packet_generator.h"
#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_received_entropy_manager.h"
+#include "net/quic/quic_received_packet_manager.h"
#include "net/quic/quic_sent_entropy_manager.h"
#include "net/quic/quic_stats.h"
@@ -329,9 +329,6 @@ class NET_EXPORT_PRIVATE QuicConnection
const QuicClock* clock() const { return clock_; }
QuicRandom* random_generator() const { return random_generator_; }
- // Updates the internal state concerning which packets have been acked.
- void RecordPacketReceived(const QuicPacketHeader& header);
-
// Called by a RetransmissionAlarm when the timer goes off. If the peer
// appears to be sending truncated acks, this returns false to indicate
// failure, otherwise it calls MaybeRetransmitPacket and returns true.
@@ -412,12 +409,6 @@ class NET_EXPORT_PRIVATE QuicConnection
const QuicDecrypter* alternative_decrypter() const;
protected:
- // Deletes all missing packets before least unacked. The connection won't
- // process any packets with sequence number before |least_unacked| that it
- // received after this call. Returns true if there were missing packets before
- // |least_unacked| unacked, false otherwise.
- bool DontWaitForPacketsBefore(QuicPacketSequenceNumber least_unacked);
-
// Send a packet to the peer using encryption |level|. If |sequence_number|
// is present in the |retransmission_map_|, then contents of this packet will
// be retransmitted with a new sequence number if it's not acked by the peer.
@@ -569,15 +560,8 @@ class NET_EXPORT_PRIVATE QuicConnection
void HandleAckForSentFecPackets(const QuicAckFrame& incoming_ack,
SequenceNumberSet* acked_packets);
- // These two are called by OnAckFrame.
- //
- // Updates internal state based on incoming_ack.received_info
- void UpdatePacketInformationReceivedByPeer(
- const QuicAckFrame& incoming_ack);
- // Updates internal state based on incoming_ack.sent_info
- void UpdatePacketInformationSentByPeer(const QuicAckFrame& incoming_ack);
-
- void UpdateOutgoingAck();
+ // Update the |sent_info| for an outgoing ack.
+ void UpdateSentPacketInfo(SentPacketInfo* sent_info);
void MaybeSendAckInResponseToPacket();
@@ -606,20 +590,11 @@ class NET_EXPORT_PRIVATE QuicConnection
QuicPacketHeader last_header_;
std::vector<QuicStreamFrame> last_stream_frames_;
- QuicAckFrame outgoing_ack_;
QuicCongestionFeedbackFrame outgoing_congestion_feedback_;
// Track some peer state so we can do less bookkeeping
// Largest sequence sent by the peer which had an ack frame (latest ack info).
QuicPacketSequenceNumber largest_seen_packet_with_ack_;
- // Largest sequence number that the peer has observed. Mostly received,
- // missing in case of truncated acks.
- QuicPacketSequenceNumber peer_largest_observed_packet_;
- // Least sequence number which the peer is still waiting for.
- QuicPacketSequenceNumber least_packet_awaited_by_peer_;
- // Least sequence number of the the packet sent by the peer for which it
- // hasn't received an ack.
- QuicPacketSequenceNumber peer_least_packet_awaiting_ack_;
// When new packets are created which may be retransmitted, they are added
// to this map, which contains owning pointers to the contained frames.
@@ -662,7 +637,7 @@ class NET_EXPORT_PRIVATE QuicConnection
FecGroupMap group_map_;
- QuicReceivedEntropyManager received_entropy_manager_;
+ QuicReceivedPacketManager received_packet_manager_;
QuicSentEntropyManager sent_entropy_manager_;
QuicConnectionVisitorInterface* visitor_;
@@ -681,15 +656,12 @@ class NET_EXPORT_PRIVATE QuicConnection
QuicConnectionStats stats_;
// The time that we got a packet for this connection.
+ // This is used for timeouts, and does not indicate the packet was processed.
QuicTime time_of_last_received_packet_;
// The time that we last sent a packet for this connection.
QuicTime time_of_last_sent_packet_;
- // Member holding the time we received the largest_observed sequence number.
- // Needed for calculating delta_time_largest_observed.
- QuicTime time_largest_observed_;
-
// Congestion manager which controls the rate the connection sends packets
// as well as collecting and generating congestion feedback.
QuicCongestionManager congestion_manager_;
diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc
index a955e4c5..6e84c0f 100644
--- a/net/quic/quic_connection_helper_test.cc
+++ b/net/quic/quic_connection_helper_test.cc
@@ -126,7 +126,7 @@ class QuicConnectionHelperTest : public ::testing::Test {
QuicFrames frames;
frames.push_back(QuicFrame(&frame_));
- return framer_.ConstructFrameDataPacket(header_, frames).packet;
+ return framer_.BuildUnsizedDataPacket(header_, frames).packet;
}
// Returns a newly created packet to send ack data.
@@ -147,7 +147,7 @@ class QuicConnectionHelperTest : public ::testing::Test {
frames.push_back(QuicFrame(&ack));
frames.push_back(QuicFrame(&feedback));
scoped_ptr<QuicPacket> packet(
- framer_.ConstructFrameDataPacket(header_, frames).packet);
+ framer_.BuildUnsizedDataPacket(header_, frames).packet);
return framer_.EncryptPacket(
ENCRYPTION_NONE, header_.packet_sequence_number, *packet);
}
@@ -196,7 +196,7 @@ class QuicConnectionHelperTest : public ::testing::Test {
QuicFrames frames;
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
- framer_.ConstructFrameDataPacket(header_, frames).packet);
+ framer_.BuildUnsizedDataPacket(header_, frames).packet);
return framer_.EncryptPacket(
ENCRYPTION_NONE, header_.packet_sequence_number, *packet);
}
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 2161d53a..80854aa 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -428,7 +428,6 @@ class TestConnection : public QuicConnection {
}
using QuicConnection::SendOrQueuePacket;
- using QuicConnection::DontWaitForPacketsBefore;
using QuicConnection::SelectMutualVersion;
private:
@@ -464,7 +463,8 @@ class QuicConnectionTest : public ::testing::Test {
}
QuicAckFrame* outgoing_ack() {
- return QuicConnectionPeer::GetOutgoingAck(&connection_);
+ outgoing_ack_.reset(QuicConnectionPeer::CreateAckFrame(&connection_));
+ return outgoing_ack_.get();
}
QuicAckFrame* last_ack() {
@@ -601,7 +601,7 @@ class QuicConnectionTest : public ::testing::Test {
}
fec_data.redundancy = data_packet->FecProtectedData();
scoped_ptr<QuicPacket> fec_packet(
- framer_.ConstructFecPacket(header_, fec_data).packet);
+ framer_.BuildFecPacket(header_, fec_data).packet);
scoped_ptr<QuicEncryptedPacket> encrypted(
framer_.EncryptPacket(ENCRYPTION_NONE, number, *fec_packet));
@@ -662,7 +662,7 @@ class QuicConnectionTest : public ::testing::Test {
QuicFrame frame(&frame1_);
frames.push_back(frame);
QuicPacket* packet =
- framer_.ConstructFrameDataPacket(header_, frames).packet;
+ framer_.BuildUnsizedDataPacket(header_, frames).packet;
EXPECT_TRUE(packet != NULL);
return packet;
}
@@ -686,7 +686,7 @@ class QuicConnectionTest : public ::testing::Test {
QuicFrame frame(&qccf);
frames.push_back(frame);
QuicPacket* packet =
- framer_.ConstructFrameDataPacket(header_, frames).packet;
+ framer_.BuildUnsizedDataPacket(header_, frames).packet;
EXPECT_TRUE(packet != NULL);
return packet;
}
@@ -712,6 +712,7 @@ class QuicConnectionTest : public ::testing::Test {
QuicPacketHeader revived_header_;
QuicStreamFrame frame1_;
QuicStreamFrame frame2_;
+ scoped_ptr<QuicAckFrame> outgoing_ack_;
bool accept_packet_;
private:
@@ -939,13 +940,6 @@ TEST_F(QuicConnectionTest, AckAll) {
ProcessAckPacket(&frame1, true);
}
-TEST_F(QuicConnectionTest, DontWaitForPacketsBefore) {
- ProcessPacket(2);
- ProcessPacket(7);
- EXPECT_TRUE(connection_.DontWaitForPacketsBefore(4));
- EXPECT_EQ(3u, outgoing_ack()->received_info.missing_packets.size());
-}
-
TEST_F(QuicConnectionTest, BasicSending) {
EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(6);
QuicPacketSequenceNumber last_packet;
@@ -1006,15 +1000,15 @@ TEST_F(QuicConnectionTest, FECSending) {
// All packets carry version info till version is negotiated.
size_t payload_length;
connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(
- kIncludeVersion, IN_FEC_GROUP, &payload_length);
+ GetPacketLengthForOneStream(connection_.version(), kIncludeVersion,
+ IN_FEC_GROUP, &payload_length);
// And send FEC every two packets.
connection_.options()->max_packets_per_fec_group = 2;
// Send 4 data packets and 2 FEC packets.
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(6);
- // TODO(ianswett): The first stream frame will consume 2 fewer bytes.
- const string payload(payload_length * 4, 'a');
+ // The first stream frame will consume 2 fewer bytes than the other three.
+ const string payload(payload_length * 4 - 6, 'a');
connection_.SendStreamData(1, payload, 0, !kFin);
// Expect the FEC group to be closed after SendStreamData.
EXPECT_FALSE(creator_.ShouldSendFec(true));
@@ -1024,8 +1018,8 @@ TEST_F(QuicConnectionTest, FECQueueing) {
// All packets carry version info till version is negotiated.
size_t payload_length;
connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(
- kIncludeVersion, IN_FEC_GROUP, &payload_length);
+ GetPacketLengthForOneStream(connection_.version(), kIncludeVersion,
+ IN_FEC_GROUP, &payload_length);
// And send FEC every two packets.
connection_.options()->max_packets_per_fec_group = 2;
@@ -1947,8 +1941,8 @@ TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
// All packets carry version info till version is negotiated.
size_t payload_length;
connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(
- kIncludeVersion, NOT_IN_FEC_GROUP, &payload_length);
+ GetPacketLengthForOneStream(connection_.version(), kIncludeVersion,
+ NOT_IN_FEC_GROUP, &payload_length);
// Queue the first packet.
EXPECT_CALL(*send_algorithm_,
@@ -1964,13 +1958,13 @@ TEST_F(QuicConnectionTest, LoopThroughSendingPackets) {
// All packets carry version info till version is negotiated.
size_t payload_length;
connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(
- kIncludeVersion, NOT_IN_FEC_GROUP, &payload_length);
+ GetPacketLengthForOneStream(connection_.version(), kIncludeVersion,
+ NOT_IN_FEC_GROUP, &payload_length);
// Queue the first packet.
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(7);
- // TODO(ianswett): The first stream frame will consume 2 fewer bytes.
- const string payload(payload_length * 7, 'a');
+ // The first stream frame will consume 2 fewer bytes than the other six.
+ const string payload(payload_length * 7 - 12, 'a');
EXPECT_EQ(payload.size(),
connection_.SendStreamData(1, payload, 0, !kFin).bytes_consumed);
}
@@ -2001,7 +1995,7 @@ TEST_F(QuicConnectionTest, PublicReset) {
header.public_header.version_flag = false;
header.rejected_sequence_number = 10101;
scoped_ptr<QuicEncryptedPacket> packet(
- framer_.ConstructPublicResetPacket(header));
+ framer_.BuildPublicResetPacket(header));
EXPECT_CALL(visitor_, ConnectionClose(QUIC_PUBLIC_RESET, true));
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *packet);
}
@@ -2144,7 +2138,7 @@ TEST_F(QuicConnectionTest, SendVersionNegotiationPacket) {
QuicFrame frame(&frame1_);
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
scoped_ptr<QuicEncryptedPacket> encrypted(
framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet));
@@ -2281,7 +2275,7 @@ TEST_F(QuicConnectionTest, DontProcessFramesIfPacketClosedConnection) {
frames.push_back(stream_frame);
frames.push_back(close_frame);
scoped_ptr<QuicPacket> packet(
- framer_.ConstructFrameDataPacket(header_, frames).packet);
+ framer_.BuildUnsizedDataPacket(header_, frames).packet);
EXPECT_TRUE(NULL != packet.get());
scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
ENCRYPTION_NONE, 1, *packet));
@@ -2293,26 +2287,32 @@ TEST_F(QuicConnectionTest, DontProcessFramesIfPacketClosedConnection) {
connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
}
-//// The QUIC_VERSION_X versions are deliberately set, rather than using all
-//// values in kSupportedQuicVersions.
-//TEST_F(QuicConnectionTest, SelectMutualVersion) {
-// // Set the connection to speak QUIC_VERSION_6.
-// connection_.set_version(QUIC_VERSION_6);
-// EXPECT_EQ(connection_.version(), QUIC_VERSION_6);
-//
-// // Pass in available versions which includes a higher mutually supported
-// // version. The higher mutually supported version should be selected.
-// EXPECT_TRUE(
-// connection_.SelectMutualVersion({QUIC_VERSION_6, QUIC_VERSION_7}));
-// EXPECT_EQ(connection_.version(), QUIC_VERSION_7);
-//
-// // Expect that the lower version is selected.
-// EXPECT_TRUE(connection_.SelectMutualVersion({QUIC_VERSION_6}));
-// EXPECT_EQ(connection_.version(), QUIC_VERSION_6);
-//
-// // Shouldn't be able to find a mutually supported version.
-// EXPECT_FALSE(connection_.SelectMutualVersion({QUIC_VERSION_UNSUPPORTED}));
-//}
+// The QUIC_VERSION_X versions are deliberately set, rather than using all
+// values in kSupportedQuicVersions.
+TEST_F(QuicConnectionTest, SelectMutualVersion) {
+ // Set the connection to speak QUIC_VERSION_6.
+ connection_.set_version(QUIC_VERSION_6);
+ EXPECT_EQ(connection_.version(), QUIC_VERSION_6);
+
+ // Pass in available versions which includes a higher mutually supported
+ // version. The higher mutually supported version should be selected.
+ QuicVersionVector available_versions;
+ available_versions.push_back(QUIC_VERSION_6);
+ available_versions.push_back(QUIC_VERSION_7);
+ EXPECT_TRUE(connection_.SelectMutualVersion(available_versions));
+ EXPECT_EQ(connection_.version(), QUIC_VERSION_7);
+
+ // Expect that the lower version is selected.
+ QuicVersionVector lower_version;
+ lower_version.push_back(QUIC_VERSION_6);
+ EXPECT_TRUE(connection_.SelectMutualVersion(lower_version));
+ EXPECT_EQ(connection_.version(), QUIC_VERSION_6);
+
+ // Shouldn't be able to find a mutually supported version.
+ QuicVersionVector unsupported_version;
+ unsupported_version.push_back(QUIC_VERSION_UNSUPPORTED);
+ EXPECT_FALSE(connection_.SelectMutualVersion(unsupported_version));
+}
TEST_F(QuicConnectionTest, ConnectionCloseWhenNotWriteBlocked) {
helper_->set_blocked(false); // Already default.
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index e4484f6..e1f8ec8 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -33,6 +33,32 @@ const QuicPacketSequenceNumber k1ByteSequenceNumberMask =
const QuicGuid k1ByteGuidMask = GG_UINT64_C(0x00000000000000FF);
const QuicGuid k4ByteGuidMask = GG_UINT64_C(0x00000000FFFFFFFF);
+// Mask to determine if it's a special frame type(Stream, Ack, or
+// Congestion Control) by checking if the first bit is 0, then shifting right.
+const uint8 kQuicFrameType0BitMask = 0x01;
+
+// Default frame type shift and mask.
+const uint8 kQuicDefaultFrameTypeShift = 3;
+const uint8 kQuicDefaultFrameTypeMask = 0x07;
+
+// Stream frame relative shifts and masks for interpreting the stream flags.
+// StreamID may be 1, 2, 3, or 4 bytes.
+const uint8 kQuicStreamIdShift = 2;
+const uint8 kQuicStreamIDLengthMask = 0x03;
+
+// Offset may be 0, 2, 3, 4, 5, 6, 7, 8 bytes.
+const uint8 kQuicStreamOffsetShift = 3;
+const uint8 kQuicStreamOffsetMask = 0x07;
+
+// Data length may be 0 or 2 bytes.
+const uint8 kQuicStreamDataLengthShift = 1;
+const uint8 kQuicStreamDataLengthMask = 0x01;
+
+// Fin bit may be set or not.
+const uint8 kQuicStreamFinShift = 1;
+const uint8 kQuicStreamFinMask = 0x01;
+
+
const uint32 kInvalidDeltaTime = 0xffffffff;
// Returns the absolute value of the difference between |a| and |b|.
@@ -72,28 +98,19 @@ QuicFramer::QuicFramer(QuicVersion version,
QuicFramer::~QuicFramer() {}
-bool CanTruncate(const QuicFrame& frame) {
- if (frame.type == ACK_FRAME ||
- frame.type == CONNECTION_CLOSE_FRAME) {
- return true;
- }
- return false;
-}
-
-// static
-size_t QuicFramer::GetMinStreamFrameSize() {
- return kQuicFrameTypeSize + kQuicStreamIdSize +
- kQuicStreamFinSize + kQuicStreamOffsetSize + kQuicStreamPayloadLengthSize;
-}
-
// static
-size_t QuicFramer::GetMinStreamFrameSize(QuicStreamId stream_id,
+size_t QuicFramer::GetMinStreamFrameSize(QuicVersion version,
+ QuicStreamId stream_id,
QuicStreamOffset offset,
- bool last_frame) {
- // TODO(ianswett): Remove kQuicStreamFinSize for the next STREAM framing.
+ bool last_frame_in_packet) {
+ if (version == QUIC_VERSION_6) {
+ return kQuicFrameTypeSize + kQuicMaxStreamIdSize +
+ kQuicStreamFinSize + kQuicMaxStreamOffsetSize +
+ kQuicStreamPayloadLengthSize;
+ }
return kQuicFrameTypeSize + GetStreamIdSize(stream_id) +
- GetStreamOffsetSize(offset) + kQuicStreamFinSize +
- kQuicStreamPayloadLengthSize;
+ GetStreamOffsetSize(offset) +
+ (last_frame_in_packet ? 0 : kQuicStreamPayloadLengthSize);
}
// static
@@ -106,7 +123,7 @@ size_t QuicFramer::GetMinAckFrameSize() {
// static
size_t QuicFramer::GetMinRstStreamFrameSize() {
- return kQuicFrameTypeSize + kQuicStreamIdSize + kQuicErrorCodeSize +
+ return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicErrorCodeSize +
kQuicErrorDetailsLengthSize;
}
@@ -119,7 +136,7 @@ size_t QuicFramer::GetMinConnectionCloseFrameSize() {
// static
size_t QuicFramer::GetMinGoAwayFrameSize() {
return kQuicFrameTypeSize + kQuicErrorCodeSize + kQuicErrorDetailsLengthSize +
- kQuicStreamIdSize;
+ kQuicMaxStreamIdSize;
}
// static
@@ -134,14 +151,53 @@ size_t QuicFramer::GetMaxUnackedPackets(QuicPacketHeader header) {
// static
size_t QuicFramer::GetStreamIdSize(QuicStreamId stream_id) {
+ // Sizes are 1 through 4 bytes.
+ for (int i = 1; i <= 4; ++i) {
+ stream_id >>= 8;
+ if (stream_id == 0) {
+ return i;
+ }
+ }
+ LOG(DFATAL) << "Failed to determine StreamIDSize.";
return 4;
}
// static
size_t QuicFramer::GetStreamOffsetSize(QuicStreamOffset offset) {
+ // 0 is a special case.
+ if (offset == 0) {
+ return 0;
+ }
+ // 2 through 8 are the remaining sizes.
+ offset >>= 8;
+ for (int i = 2; i <= 8; ++i) {
+ offset >>= 8;
+ if (offset == 0) {
+ return i;
+ }
+ }
+ LOG(DFATAL) << "Failed to determine StreamOffsetSize.";
return 8;
}
+// static
+size_t QuicFramer::GetVersionNegotiationPacketSize(size_t number_versions) {
+ return kPublicFlagsSize + PACKET_8BYTE_GUID +
+ number_versions * kQuicVersionSize;
+}
+
+// static
+bool QuicFramer::CanTruncate(const QuicFrame& frame, size_t free_bytes) {
+ // TODO(ianswett): GetMinConnectionCloseFrameSize may be incorrect, because
+ // checking for it here results in frames not being added, but the resulting
+ // frames do actually fit.
+ if ((frame.type == ACK_FRAME || frame.type == CONNECTION_CLOSE_FRAME) &&
+ free_bytes >= GetMinAckFrameSize()) {
+ return true;
+ }
+ return false;
+}
+
bool QuicFramer::IsSupportedVersion(const QuicVersion version) const {
for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
if (version == kSupportedQuicVersions[i]) {
@@ -151,11 +207,6 @@ bool QuicFramer::IsSupportedVersion(const QuicVersion version) const {
return false;
}
-size_t QuicFramer::GetVersionNegotiationPacketSize(size_t number_versions) {
- return kPublicFlagsSize + PACKET_8BYTE_GUID +
- number_versions * kQuicVersionSize;
-}
-
size_t QuicFramer::GetSerializedFrameLength(
const QuicFrame& frame, size_t free_bytes, bool first_frame) {
if (frame.type == PADDING_FRAME) {
@@ -164,20 +215,21 @@ size_t QuicFramer::GetSerializedFrameLength(
}
// See if it fits as the non-last frame.
size_t frame_len = ComputeFrameLength(frame, false);
+ // STREAM frames save two bytes when they're the last frame in the packet.
+ if (frame_len > free_bytes && frame.type == STREAM_FRAME) {
+ frame_len = ComputeFrameLength(frame, true);
+ }
if (frame_len > free_bytes) {
// Only truncate the first frame in a packet, so if subsequent ones go
// over, stop including more frames.
if (!first_frame) {
return 0;
}
- if (CanTruncate(frame)) {
+ if (CanTruncate(frame, free_bytes)) {
// Truncate the frame so the packet will not exceed kMaxPacketSize.
// Note that we may not use every byte of the writer in this case.
- if (free_bytes >= GetMinAckFrameSize()) {
- DLOG(INFO) << "Truncating large frame";
- return free_bytes;
- }
- return 0;
+ DLOG(INFO) << "Truncating large frame";
+ return free_bytes;
}
}
return frame_len;
@@ -193,7 +245,7 @@ QuicPacketEntropyHash QuicFramer::GetPacketEntropyHash(
return 1 << (header.packet_sequence_number % 8);
}
-SerializedPacket QuicFramer::ConstructFrameDataPacket(
+SerializedPacket QuicFramer::BuildUnsizedDataPacket(
const QuicPacketHeader& header,
const QuicFrames& frames) {
const size_t max_plaintext_size = GetMaxPlaintextSize(kMaxPacketSize);
@@ -205,15 +257,15 @@ SerializedPacket QuicFramer::ConstructFrameDataPacket(
DCHECK(frame_size);
packet_size += frame_size;
}
- return ConstructFrameDataPacket(header, frames, packet_size);
+ return BuildDataPacket(header, frames, packet_size);
}
-SerializedPacket QuicFramer::ConstructFrameDataPacket(
+SerializedPacket QuicFramer::BuildDataPacket(
const QuicPacketHeader& header,
const QuicFrames& frames,
size_t packet_size) {
QuicDataWriter writer(packet_size);
- SerializedPacket kNoPacket = SerializedPacket(0, NULL, 0, NULL);
+ const SerializedPacket kNoPacket(0, NULL, 0, NULL);
if (!WritePacketHeader(header, &writer)) {
return kNoPacket;
}
@@ -221,7 +273,8 @@ SerializedPacket QuicFramer::ConstructFrameDataPacket(
for (size_t i = 0; i < frames.size(); ++i) {
const QuicFrame& frame = frames[i];
- if (!writer.WriteUInt8(frame.type)) {
+ const bool last_frame_in_packet = i == (frames.size() - 1);
+ if (!AppendTypeByte(frame, last_frame_in_packet, &writer)) {
return kNoPacket;
}
@@ -230,9 +283,15 @@ SerializedPacket QuicFramer::ConstructFrameDataPacket(
writer.WritePadding();
break;
case STREAM_FRAME:
- if (!AppendStreamFramePayload(
- *frame.stream_frame, &writer)) {
- return kNoPacket;
+ if (quic_version_ == QUIC_VERSION_6) {
+ if (!AppendV6StreamFramePayload(*frame.stream_frame, &writer)) {
+ return kNoPacket;
+ }
+ } else {
+ if (!AppendStreamFramePayload(
+ *frame.stream_frame, last_frame_in_packet, &writer)) {
+ return kNoPacket;
+ }
}
break;
case ACK_FRAME:
@@ -287,9 +346,8 @@ SerializedPacket QuicFramer::ConstructFrameDataPacket(
GetPacketEntropyHash(header), NULL);
}
-SerializedPacket QuicFramer::ConstructFecPacket(
- const QuicPacketHeader& header,
- const QuicFecData& fec) {
+SerializedPacket QuicFramer::BuildFecPacket(const QuicPacketHeader& header,
+ const QuicFecData& fec) {
DCHECK_EQ(IN_FEC_GROUP, header.is_in_fec_group);
DCHECK_NE(0u, header.fec_group);
size_t len = GetPacketHeaderSize(header);
@@ -315,7 +373,7 @@ SerializedPacket QuicFramer::ConstructFecPacket(
}
// static
-QuicEncryptedPacket* QuicFramer::ConstructPublicResetPacket(
+QuicEncryptedPacket* QuicFramer::BuildPublicResetPacket(
const QuicPublicResetPacket& packet) {
DCHECK(packet.public_header.reset_flag);
size_t len = GetPublicResetPacketSize();
@@ -345,7 +403,7 @@ QuicEncryptedPacket* QuicFramer::ConstructPublicResetPacket(
return new QuicEncryptedPacket(writer.take(), len, true);
}
-QuicEncryptedPacket* QuicFramer::ConstructVersionNegotiationPacket(
+QuicEncryptedPacket* QuicFramer::BuildVersionNegotiationPacket(
const QuicPacketPublicHeader& header,
const QuicVersionVector& supported_versions) {
DCHECK(header.version_flag);
@@ -796,6 +854,11 @@ bool QuicFramer::ProcessPacketHeader(
set_detailed_error("Unable to read first fec protected packet offset.");
return RaiseError(QUIC_INVALID_PACKET_HEADER);
}
+ if (first_fec_protected_packet_offset >= header->packet_sequence_number) {
+ set_detailed_error("First fec protected packet offset must be less "
+ "than the sequence number.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
header->fec_group =
header->packet_sequence_number - first_fec_protected_packet_offset;
}
@@ -834,58 +897,112 @@ bool QuicFramer::ProcessFrameData() {
set_detailed_error("Unable to read frame type.");
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
+
+ if (quic_version_ >= QUIC_VERSION_7) {
+ if ((frame_type & kQuicFrameType0BitMask) == 0) {
+ QuicStreamFrame frame;
+ if (!ProcessStreamFrame(frame_type, &frame)) {
+ return RaiseError(QUIC_INVALID_FRAME_DATA);
+ }
+ if (!visitor_->OnStreamFrame(frame)) {
+ DLOG(INFO) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+
+ frame_type >>= 1;
+ if ((frame_type & kQuicFrameType0BitMask) == 0) {
+ QuicAckFrame frame;
+ if (!ProcessAckFrame(&frame)) {
+ return RaiseError(QUIC_INVALID_FRAME_DATA);
+ }
+ if (!visitor_->OnAckFrame(frame)) {
+ DLOG(INFO) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+
+ frame_type >>= 1;
+ if ((frame_type & kQuicFrameType0BitMask) == 0) {
+ QuicCongestionFeedbackFrame frame;
+ if (!ProcessQuicCongestionFeedbackFrame(&frame)) {
+ return RaiseError(QUIC_INVALID_FRAME_DATA);
+ }
+ if (!visitor_->OnCongestionFeedbackFrame(frame)) {
+ DLOG(INFO) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+
+ frame_type >>= 1;
+ }
+
switch (frame_type) {
case PADDING_FRAME:
// We're done with the packet
return true;
+ // STREAM_FRAME, ACK_FRAME, and CONGESTION_FEEDBACK handled above for
+ // QUIC_VERSION_7 and later.
case STREAM_FRAME: {
QuicStreamFrame frame;
- if (!ProcessStreamFrame(&frame)) {
+ if (!ProcessV6StreamFrame(&frame)) {
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
if (!visitor_->OnStreamFrame(frame)) {
- DLOG(INFO) << "Visitor asked to stopped further processing.";
+ DLOG(INFO) << "Visitor asked to stop further processing.";
// Returning true since there was no parsing error.
return true;
}
- break;
+ continue;
}
+
case ACK_FRAME: {
QuicAckFrame frame;
if (!ProcessAckFrame(&frame)) {
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
if (!visitor_->OnAckFrame(frame)) {
- DLOG(INFO) << "Visitor asked to stopped further processing.";
+ DLOG(INFO) << "Visitor asked to stop further processing.";
// Returning true since there was no parsing error.
+ // TODO(ianswett): Consider continuing to process frames, since there
+ // was not a parsing error.
return true;
}
- break;
+ continue;
}
+
case CONGESTION_FEEDBACK_FRAME: {
QuicCongestionFeedbackFrame frame;
if (!ProcessQuicCongestionFeedbackFrame(&frame)) {
return RaiseError(QUIC_INVALID_FRAME_DATA);
}
if (!visitor_->OnCongestionFeedbackFrame(frame)) {
- DLOG(INFO) << "Visitor asked to stopped further processing.";
+ DLOG(INFO) << "Visitor asked to stop further processing.";
// Returning true since there was no parsing error.
return true;
}
- break;
+ continue;
}
+
case RST_STREAM_FRAME: {
QuicRstStreamFrame frame;
if (!ProcessRstStreamFrame(&frame)) {
return RaiseError(QUIC_INVALID_RST_STREAM_DATA);
}
if (!visitor_->OnRstStreamFrame(frame)) {
- DLOG(INFO) << "Visitor asked to stopped further processing.";
+ DLOG(INFO) << "Visitor asked to stop further processing.";
// Returning true since there was no parsing error.
return true;
}
- break;
+ continue;
}
+
case CONNECTION_CLOSE_FRAME: {
QuicConnectionCloseFrame frame;
if (!ProcessConnectionCloseFrame(&frame)) {
@@ -893,42 +1010,90 @@ bool QuicFramer::ProcessFrameData() {
}
if (!visitor_->OnAckFrame(frame.ack_frame)) {
- DLOG(INFO) << "Visitor asked to stopped further processing.";
+ DLOG(INFO) << "Visitor asked to stop further processing.";
// Returning true since there was no parsing error.
return true;
}
if (!visitor_->OnConnectionCloseFrame(frame)) {
- DLOG(INFO) << "Visitor asked to stopped further processing.";
+ DLOG(INFO) << "Visitor asked to stop further processing.";
// Returning true since there was no parsing error.
return true;
}
- break;
+ continue;
}
+
case GOAWAY_FRAME: {
QuicGoAwayFrame goaway_frame;
if (!ProcessGoAwayFrame(&goaway_frame)) {
return RaiseError(QUIC_INVALID_GOAWAY_DATA);
}
if (!visitor_->OnGoAwayFrame(goaway_frame)) {
- DLOG(INFO) << "Visitor asked to stopped further processing.";
+ DLOG(INFO) << "Visitor asked to stop further processing.";
// Returning true since there was no parsing error.
return true;
}
- break;
+ continue;
}
- default:
- set_detailed_error("Illegal frame type.");
- DLOG(WARNING) << "Illegal frame type: "
- << static_cast<int>(frame_type);
- return RaiseError(QUIC_INVALID_FRAME_DATA);
+
+ set_detailed_error("Illegal frame type.");
+ DLOG(WARNING) << "Illegal frame type: "
+ << static_cast<int>(frame_type);
+ return RaiseError(QUIC_INVALID_FRAME_DATA);
}
}
return true;
}
-bool QuicFramer::ProcessStreamFrame(QuicStreamFrame* frame) {
+bool QuicFramer::ProcessStreamFrame(uint8 frame_type,
+ QuicStreamFrame* frame) {
+ uint8 stream_flags = frame_type >> 1;
+ // Read from right to left: StreamID, Offset, Data Length, Fin.
+ const uint8 stream_id_length = (stream_flags & kQuicStreamIDLengthMask) + 1;
+ stream_flags >>= kQuicStreamIdShift;
+
+ uint8 offset_length = (stream_flags & kQuicStreamOffsetMask);
+ // There is no encoding for 1 byte, only 0 and 2 through 8.
+ if (offset_length > 0) {
+ offset_length += 1;
+ }
+ stream_flags >>= kQuicStreamOffsetShift;
+
+ bool has_data_length =
+ (stream_flags & kQuicStreamDataLengthMask) == kQuicStreamDataLengthMask;
+ stream_flags >>= kQuicStreamDataLengthShift;
+
+ frame->fin = (stream_flags & kQuicStreamFinMask) == kQuicStreamFinShift;
+
+ frame->stream_id = 0;
+ if (!reader_->ReadBytes(&frame->stream_id, stream_id_length)) {
+ set_detailed_error("Unable to read stream_id.");
+ return false;
+ }
+
+ frame->offset = 0;
+ if (!reader_->ReadBytes(&frame->offset, offset_length)) {
+ set_detailed_error("Unable to read offset.");
+ return false;
+ }
+
+ if (has_data_length) {
+ if (!reader_->ReadStringPiece16(&frame->data)) {
+ set_detailed_error("Unable to read frame data.");
+ return false;
+ }
+ } else {
+ if (!reader_->ReadStringPiece(&frame->data, reader_->BytesRemaining())) {
+ set_detailed_error("Unable to read frame data.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool QuicFramer::ProcessV6StreamFrame(QuicStreamFrame* frame) {
if (!reader_->ReadUInt32(&frame->stream_id)) {
set_detailed_error("Unable to read stream_id.");
return false;
@@ -1361,12 +1526,14 @@ bool QuicFramer::DecryptPayload(const QuicPacketHeader& header,
return true;
}
-size_t QuicFramer::ComputeFrameLength(const QuicFrame& frame, bool last_frame) {
+size_t QuicFramer::ComputeFrameLength(const QuicFrame& frame,
+ bool last_frame_in_packet) {
switch (frame.type) {
case STREAM_FRAME:
- return GetMinStreamFrameSize(frame.stream_frame->stream_id,
+ return GetMinStreamFrameSize(quic_version_,
+ frame.stream_frame->stream_id,
frame.stream_frame->offset,
- last_frame) +
+ last_frame_in_packet) +
frame.stream_frame->data.size();
case ACK_FRAME: {
const QuicAckFrame& ack = *frame.ack_frame;
@@ -1432,6 +1599,59 @@ size_t QuicFramer::ComputeFrameLength(const QuicFrame& frame, bool last_frame) {
return 0;
}
+bool QuicFramer::AppendTypeByte(const QuicFrame& frame,
+ bool last_frame_in_packet,
+ QuicDataWriter* writer) {
+ if (quic_version_ == QUIC_VERSION_6) {
+ return writer->WriteUInt8(frame.type);
+ }
+
+ uint8 type_byte = 0;
+ switch (frame.type) {
+ case STREAM_FRAME: {
+ if (frame.stream_frame == NULL) {
+ LOG(DFATAL) << "Failed to append STREAM frame with no stream_frame.";
+ }
+ // Fin bit.
+ type_byte |= frame.stream_frame->fin ? kQuicStreamFinMask : 0;
+
+ // Data Length bit.
+ type_byte <<= kQuicStreamDataLengthShift;
+ type_byte |= last_frame_in_packet ? 0 : kQuicStreamDataLengthMask;
+
+ // Offset 3 bits.
+ type_byte <<= kQuicStreamOffsetShift;
+ const size_t offset_len = GetStreamOffsetSize(frame.stream_frame->offset);
+ if (offset_len > 0) {
+ type_byte |= offset_len - 1;
+ }
+
+ // stream id 2 bits.
+ type_byte <<= kQuicStreamIdShift;
+ type_byte |= GetStreamIdSize(frame.stream_frame->stream_id) - 1;
+
+ type_byte <<= 1; // Leaves the last bit as a 0.
+ break;
+ }
+ case ACK_FRAME: {
+ // TODO(ianswett): Use extra 5 bits in the ack framing.
+ type_byte = 0x01;
+ break;
+ }
+ case CONGESTION_FEEDBACK_FRAME: {
+ // TODO(ianswett): Use extra 5 bits in the congestion feedback framing.
+ type_byte = 0x03;
+ break;
+ }
+ default:
+ type_byte =
+ frame.type << kQuicDefaultFrameTypeShift | kQuicDefaultFrameTypeMask;
+ break;
+ }
+
+ return writer->WriteUInt8(type_byte);
+}
+
// static
bool QuicFramer::AppendPacketSequenceNumber(
QuicSequenceNumberLength sequence_number_length,
@@ -1467,6 +1687,27 @@ bool QuicFramer::AppendPacketSequenceNumber(
bool QuicFramer::AppendStreamFramePayload(
const QuicStreamFrame& frame,
+ bool last_frame_in_packet,
+ QuicDataWriter* writer) {
+ if (!writer->WriteBytes(&frame.stream_id, GetStreamIdSize(frame.stream_id))) {
+ return false;
+ }
+ if (!writer->WriteBytes(&frame.offset, GetStreamOffsetSize(frame.offset))) {
+ return false;
+ }
+ if (!last_frame_in_packet) {
+ if (!writer->WriteUInt16(frame.data.size())) {
+ return false;
+ }
+ }
+ if (!writer->WriteBytes(frame.data.data(), frame.data.size())) {
+ return false;
+ }
+ return true;
+}
+
+bool QuicFramer::AppendV6StreamFramePayload(
+ const QuicStreamFrame& frame,
QuicDataWriter* writer) {
if (!writer->WriteUInt32(frame.stream_id)) {
return false;
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index b62d56f..f2de9da 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -33,12 +33,13 @@ const size_t kQuicErrorCodeSize = 4;
// Number of bytes reserved to denote the length of error details field.
const size_t kQuicErrorDetailsLengthSize = 2;
-// Number of bytes reserved for stream id
-const size_t kQuicStreamIdSize = 4;
+// Maximum number of bytes reserved for stream id.
+const size_t kQuicMaxStreamIdSize = 4;
// Number of bytes reserved for fin flag in stream frame.
+// TODO(ianswett): Remove once QUIC_VERSION_6 and before are removed.
const size_t kQuicStreamFinSize = 1;
-// Number of bytes reserved for byte offset in stream frame.
-const size_t kQuicStreamOffsetSize = 8;
+// Maximum number of bytes reserved for byte offset in stream frame.
+const size_t kQuicMaxStreamOffsetSize = 8;
// Number of bytes reserved to store payload length in stream frame.
const size_t kQuicStreamPayloadLengthSize = 2;
@@ -226,12 +227,11 @@ class NET_EXPORT_PRIVATE QuicFramer {
bool ProcessRevivedPacket(QuicPacketHeader* header,
base::StringPiece payload);
- // Size in bytes of all stream frame fields without the payload.
- static size_t GetMinStreamFrameSize();
- // Size in bytes of all stream frame fields without the payload.
- static size_t GetMinStreamFrameSize(QuicStreamId stream_id,
+ // Largest size in bytes of all stream frame fields without the payload.
+ static size_t GetMinStreamFrameSize(QuicVersion version,
+ QuicStreamId stream_id,
QuicStreamOffset offset,
- bool last_frame);
+ bool last_frame_in_packet);
// Size in bytes of all ack frame fields without the missing packets.
static size_t GetMinAckFrameSize();
// Size in bytes of all reset stream frame without the error details.
@@ -249,7 +249,10 @@ class NET_EXPORT_PRIVATE QuicFramer {
// Size in bytes required to serialize the stream offset.
static size_t GetStreamOffsetSize(QuicStreamOffset offset);
// Size in bytes required for a serialized version negotiation packet
- size_t GetVersionNegotiationPacketSize(size_t number_versions);
+ static size_t GetVersionNegotiationPacketSize(size_t number_versions);
+
+
+ static bool CanTruncate(const QuicFrame& frame, size_t free_bytes);
// Returns the number of bytes added to the packet for the specified frame,
// and 0 if the frame doesn't fit. Includes the header size for the first
@@ -269,27 +272,27 @@ class NET_EXPORT_PRIVATE QuicFramer {
// and is populated with the fields in |header| and |frames|, or is NULL if
// the packet could not be created.
// TODO(ianswett): Used for testing only.
- SerializedPacket ConstructFrameDataPacket(const QuicPacketHeader& header,
- const QuicFrames& frames);
+ SerializedPacket BuildUnsizedDataPacket(const QuicPacketHeader& header,
+ const QuicFrames& frames);
// Returns a SerializedPacket whose |packet| member is owned by the caller,
// is created from the first |num_frames| frames, or is NULL if the packet
// could not be created. The packet must be of size |packet_size|.
- SerializedPacket ConstructFrameDataPacket(const QuicPacketHeader& header,
- const QuicFrames& frames,
- size_t packet_size);
+ SerializedPacket BuildDataPacket(const QuicPacketHeader& header,
+ const QuicFrames& frames,
+ size_t packet_size);
// Returns a SerializedPacket whose |packet| member is owned by the caller,
// and is populated with the fields in |header| and |fec|, or is NULL if the
// packet could not be created.
- SerializedPacket ConstructFecPacket(const QuicPacketHeader& header,
- const QuicFecData& fec);
+ SerializedPacket BuildFecPacket(const QuicPacketHeader& header,
+ const QuicFecData& fec);
// Returns a new public reset packet, owned by the caller.
- static QuicEncryptedPacket* ConstructPublicResetPacket(
+ static QuicEncryptedPacket* BuildPublicResetPacket(
const QuicPublicResetPacket& packet);
- QuicEncryptedPacket* ConstructVersionNegotiationPacket(
+ QuicEncryptedPacket* BuildVersionNegotiationPacket(
const QuicPacketPublicHeader& header,
const QuicVersionVector& supported_versions);
@@ -361,7 +364,8 @@ class NET_EXPORT_PRIVATE QuicFramer {
QuicSequenceNumberLength sequence_number_length,
QuicPacketSequenceNumber* sequence_number);
bool ProcessFrameData();
- bool ProcessStreamFrame(QuicStreamFrame* frame);
+ bool ProcessStreamFrame(uint8 frame_type, QuicStreamFrame* frame);
+ bool ProcessV6StreamFrame(QuicStreamFrame* frame);
bool ProcessAckFrame(QuicAckFrame* frame);
bool ProcessReceivedInfo(ReceivedPacketInfo* received_info);
bool ProcessSentInfo(SentPacketInfo* sent_info);
@@ -381,15 +385,21 @@ class NET_EXPORT_PRIVATE QuicFramer {
QuicPacketSequenceNumber packet_sequence_number) const;
// Computes the wire size in bytes of the payload of |frame|.
- size_t ComputeFrameLength(const QuicFrame& frame, bool last_frame);
+ size_t ComputeFrameLength(const QuicFrame& frame, bool last_frame_in_packet);
static bool AppendPacketSequenceNumber(
QuicSequenceNumberLength sequence_number_length,
QuicPacketSequenceNumber packet_sequence_number,
QuicDataWriter* writer);
+ bool AppendTypeByte(const QuicFrame& frame,
+ bool last_frame_in_packet,
+ QuicDataWriter* writer);
bool AppendStreamFramePayload(const QuicStreamFrame& frame,
+ bool last_frame_in_packet,
QuicDataWriter* builder);
+ bool AppendV6StreamFramePayload(const QuicStreamFrame& frame,
+ QuicDataWriter* builder);
bool AppendAckFramePayload(const QuicAckFrame& frame,
QuicDataWriter* builder);
bool AppendQuicCongestionFeedbackFramePayload(
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index b7a4e30..513e730 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -43,6 +43,8 @@ const size_t kGuidOffset = kPublicFlagsSize;
// Index into the version string in the header. (if present).
const size_t kVersionOffset = kGuidOffset + PACKET_8BYTE_GUID;
+// Size in bytes of the stream frame fields for an arbitrary StreamID and
+// offset and the last frame in a packet.
// Index into the sequence number offset in the header.
size_t GetSequenceNumberOffset(QuicGuidLength guid_length,
bool include_version) {
@@ -317,8 +319,8 @@ class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> {
framer_.set_visitor(&visitor_);
framer_.set_received_entropy_calculator(&entropy_calculator_);
- QuicVersion version = GetParam();
- framer_.set_version(version);
+ version_ = GetParam();
+ framer_.set_version(version_);
}
bool CheckEncryption(QuicPacketSequenceNumber sequence_number,
@@ -412,16 +414,17 @@ class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> {
test::TestEncrypter* encrypter_;
test::TestDecrypter* decrypter_;
+ QuicVersion version_;
QuicTime start_;
QuicFramer framer_;
test::TestQuicVisitor visitor_;
test::TestEntropyCalculator entropy_calculator_;
};
-// Run all framer tests with QUIC version 6.
+// Run all framer tests with QUIC version 6 and 7.
INSTANTIATE_TEST_CASE_P(QuicFramerTests,
QuicFramerTest,
- ::testing::Values(QUIC_VERSION_6));
+ ::testing::Values(QUIC_VERSION_6, QUIC_VERSION_7));
TEST_P(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearEpochStart) {
// A few quick manual sanity checks
@@ -778,7 +781,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith0ByteGuid) {
TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
// Set a specific version.
- framer_.set_version(QUIC_VERSION_6);
+ framer_.set_version(QUIC_VERSION_7);
unsigned char packet[] = {
// public flags (version)
@@ -787,7 +790,7 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
- 'Q', '0', '0', '6',
+ 'Q', '0', '0', '7',
// packet sequence number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
@@ -803,7 +806,7 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
visitor_.header_->public_header.guid);
EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
EXPECT_TRUE(visitor_.header_->public_header.version_flag);
- EXPECT_EQ(QUIC_VERSION_6, visitor_.header_->public_header.versions[0]);
+ EXPECT_EQ(QUIC_VERSION_7, visitor_.header_->public_header.versions[0]);
EXPECT_FALSE(visitor_.header_->fec_flag);
EXPECT_FALSE(visitor_.header_->entropy_flag);
EXPECT_EQ(0, visitor_.header_->entropy_hash);
@@ -1039,7 +1042,7 @@ TEST_P(QuicFramerTest, InvalidPublicFlag) {
TEST_P(QuicFramerTest, InvalidPublicFlagWithMatchingVersions) {
// Set a specific version.
- framer_.set_version(QUIC_VERSION_6);
+ framer_.set_version(QUIC_VERSION_7);
unsigned char packet[] = {
// public flags (8 byte guid and version flag and an unknown flag)
@@ -1048,7 +1051,7 @@ TEST_P(QuicFramerTest, InvalidPublicFlagWithMatchingVersions) {
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
- 'Q', '0', '0', '6',
+ 'Q', '0', '0', '7',
// packet sequence number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
@@ -1095,7 +1098,7 @@ TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) {
0x00,
// frame type (padding frame)
- 0x00,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x00 : 0x07),
};
QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
EXPECT_TRUE(framer_.ProcessPacket(encrypted));
@@ -1142,6 +1145,28 @@ TEST_P(QuicFramerTest, InvalidPrivateFlag) {
QUIC_INVALID_PACKET_HEADER);
};
+TEST_P(QuicFramerTest, InvalidFECGroupOffset) {
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ // private flags (fec group)
+ 0x02,
+ // first fec protected packet offset
+ 0x10
+ };
+ CheckProcessingFails(packet,
+ arraysize(packet),
+ "First fec protected packet offset must be less "
+ "than the sequence number.",
+ QUIC_INVALID_PACKET_HEADER);
+};
+
TEST_P(QuicFramerTest, PaddingFrame) {
unsigned char packet[] = {
// public flags (8 byte guid)
@@ -1156,7 +1181,7 @@ TEST_P(QuicFramerTest, PaddingFrame) {
0x00,
// frame type (padding frame)
- 0x00,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x00 : 0x07),
// Ignored data (which in this case is a stream frame)
0x01,
0x04, 0x03, 0x02, 0x01,
@@ -1185,7 +1210,10 @@ TEST_P(QuicFramerTest, PaddingFrame) {
"Unable to read frame type.", QUIC_INVALID_FRAME_DATA);
}
-TEST_P(QuicFramerTest, StreamFrame) {
+TEST_P(QuicFramerTest, StreamFrameVersion6) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_6);
+
unsigned char packet[] = {
// public flags (8 byte guid)
0x3C,
@@ -1232,17 +1260,17 @@ TEST_P(QuicFramerTest, StreamFrame) {
EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
// Now test framing boundaries
- for (size_t i = 0; i < QuicFramer::GetMinStreamFrameSize(); ++i) {
+ for (size_t i = 0; i < GetMinStreamFrameSize(framer_.version()); ++i) {
string expected_error;
if (i < kQuicFrameTypeSize) {
expected_error = "Unable to read frame type.";
- } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize) {
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
expected_error = "Unable to read stream_id.";
- } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize +
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
kQuicStreamFinSize) {
expected_error = "Unable to read fin.";
- } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize +
- kQuicStreamFinSize + kQuicStreamOffsetSize) {
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
+ kQuicStreamFinSize + kQuicMaxStreamOffsetSize) {
expected_error = "Unable to read offset.";
} else {
expected_error = "Unable to read frame data.";
@@ -1255,7 +1283,290 @@ TEST_P(QuicFramerTest, StreamFrame) {
}
}
-TEST_P(QuicFramerTest, StreamFrameWithVersion) {
+TEST_P(QuicFramerTest, StreamFrame) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_7);
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xFE,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+
+ 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));
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+ EXPECT_EQ(static_cast<uint64>(0x01020304),
+ visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654),
+ visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
+
+ // Now test framing boundaries
+ for (size_t i = 0; i < GetMinStreamFrameSize(framer_.version()); ++i) {
+ string expected_error;
+ if (i < kQuicFrameTypeSize) {
+ expected_error = "Unable to read frame type.";
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
+ expected_error = "Unable to read stream_id.";
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
+ expected_error = "Unable to read fin.";
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
+ kQuicMaxStreamOffsetSize) {
+ expected_error = "Unable to read offset.";
+ } else {
+ expected_error = "Unable to read frame data.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_FRAME_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_7);
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xFC,
+ // stream id
+ 0x04, 0x03, 0x02,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+
+ 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));
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+ EXPECT_EQ(static_cast<uint64>(0x00020304),
+ visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654),
+ visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
+
+ // Now test framing boundaries
+ const size_t stream_id_size = 3;
+ for (size_t i = 0; i < GetMinStreamFrameSize(framer_.version()); ++i) {
+ string expected_error;
+ if (i < kQuicFrameTypeSize) {
+ expected_error = "Unable to read frame type.";
+ } else if (i < kQuicFrameTypeSize + stream_id_size) {
+ expected_error = "Unable to read stream_id.";
+ } else if (i < kQuicFrameTypeSize + stream_id_size - 1) {
+ expected_error = "Unable to read fin.";
+ } else if (i < kQuicFrameTypeSize + stream_id_size +
+ kQuicMaxStreamOffsetSize) {
+ expected_error = "Unable to read offset.";
+ } else {
+ expected_error = "Unable to read frame data.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_FRAME_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_7);
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xFA,
+ // stream id
+ 0x04, 0x03,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+
+ 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));
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+ EXPECT_EQ(static_cast<uint64>(0x00000304),
+ visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654),
+ visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
+
+ // Now test framing boundaries
+ const size_t stream_id_size = 2;
+ for (size_t i = 0; i < GetMinStreamFrameSize(framer_.version()); ++i) {
+ string expected_error;
+ if (i < kQuicFrameTypeSize) {
+ expected_error = "Unable to read frame type.";
+ } else if (i < kQuicFrameTypeSize + stream_id_size) {
+ expected_error = "Unable to read stream_id.";
+ } else if (i < kQuicFrameTypeSize + stream_id_size - 1) {
+ expected_error = "Unable to read fin.";
+ } else if (i < kQuicFrameTypeSize + stream_id_size +
+ kQuicMaxStreamOffsetSize) {
+ expected_error = "Unable to read offset.";
+ } else {
+ expected_error = "Unable to read frame data.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_FRAME_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_7);
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xF8,
+ // stream id
+ 0x04,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+
+ 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));
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+ EXPECT_EQ(static_cast<uint64>(0x00000004),
+ visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654),
+ visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
+
+ // Now test framing boundaries
+ const size_t stream_id_size = 1;
+ for (size_t i = 0; i < GetMinStreamFrameSize(framer_.version()); ++i) {
+ string expected_error;
+ if (i < kQuicFrameTypeSize) {
+ expected_error = "Unable to read frame type.";
+ } else if (i < kQuicFrameTypeSize + stream_id_size) {
+ expected_error = "Unable to read stream_id.";
+ } else if (i < kQuicFrameTypeSize + stream_id_size - 1) {
+ expected_error = "Unable to read fin.";
+ } else if (i < kQuicFrameTypeSize + stream_id_size +
+ kQuicMaxStreamOffsetSize) {
+ expected_error = "Unable to read offset.";
+ } else {
+ expected_error = "Unable to read frame data.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_FRAME_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, StreamFrameWithVersion6) {
// Set a specific version.
framer_.set_version(QUIC_VERSION_6);
@@ -1309,17 +1620,89 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) {
EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
// Now test framing boundaries
- for (size_t i = 0; i < QuicFramer::GetMinStreamFrameSize(); ++i) {
+ for (size_t i = 0; i < GetMinStreamFrameSize(framer_.version()); ++i) {
string expected_error;
if (i < kQuicFrameTypeSize) {
expected_error = "Unable to read frame type.";
- } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize) {
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
expected_error = "Unable to read stream_id.";
- } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize +
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
kQuicStreamFinSize) {
expected_error = "Unable to read fin.";
- } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize +
- kQuicStreamFinSize + kQuicStreamOffsetSize) {
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
+ kQuicStreamFinSize + kQuicMaxStreamOffsetSize) {
+ expected_error = "Unable to read offset.";
+ } else {
+ expected_error = "Unable to read frame data.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(PACKET_8BYTE_GUID, kIncludeVersion,
+ PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
+ expected_error, QUIC_INVALID_FRAME_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, StreamFrameWithVersion) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_7);
+
+ unsigned char packet[] = {
+ // public flags (version, 8 byte guid)
+ 0x3D,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', '0', '7',
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xFE,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+
+ 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(visitor_.header_.get()->public_header.version_flag);
+ EXPECT_EQ(QUIC_VERSION_7, visitor_.header_.get()->public_header.versions[0]);
+ EXPECT_TRUE(CheckDecryption(encrypted, kIncludeVersion));
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+ EXPECT_EQ(static_cast<uint64>(0x01020304),
+ visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654),
+ visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
+
+ // Now test framing boundaries
+ for (size_t i = 0; i < GetMinStreamFrameSize(framer_.version()); ++i) {
+ string expected_error;
+ if (i < kQuicFrameTypeSize) {
+ expected_error = "Unable to read frame type.";
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
+ expected_error = "Unable to read stream_id.";
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
+ kQuicMaxStreamOffsetSize) {
expected_error = "Unable to read offset.";
} else {
expected_error = "Unable to read frame data.";
@@ -1347,12 +1730,10 @@ TEST_P(QuicFramerTest, RejectPacket) {
// private flags
0x00,
- // frame type (stream frame)
- 0x01,
+ // frame type (stream frame with fin)
+ 0xFE,
// stream id
0x04, 0x03, 0x02, 0x01,
- // fin
- 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
@@ -1376,13 +1757,14 @@ TEST_P(QuicFramerTest, RejectPacket) {
}
TEST_P(QuicFramerTest, RevivedStreamFrame) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_7);
+
unsigned char payload[] = {
- // frame type (stream frame)
- 0x01,
+ // frame type (stream frame with fin)
+ 0xFE,
// stream id
0x04, 0x03, 0x02, 0x01,
- // fin
- 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
@@ -1432,8 +1814,10 @@ TEST_P(QuicFramerTest, RevivedStreamFrame) {
visitor_.stream_frames_[0]->offset);
EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
}
+TEST_P(QuicFramerTest, StreamFrameInFecGroupVersion6) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_6);
-TEST_P(QuicFramerTest, StreamFrameInFecGroup) {
unsigned char packet[] = {
// public flags (8 byte guid)
0x3C,
@@ -1489,6 +1873,63 @@ TEST_P(QuicFramerTest, StreamFrameInFecGroup) {
EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
}
+TEST_P(QuicFramerTest, StreamFrameInFecGroup) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_7);
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x12, 0x34,
+ // private flags (fec group)
+ 0x02,
+ // first fec protected packet offset
+ 0x02,
+
+ // frame type (stream frame with fin)
+ 0xFE,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+
+ 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(IN_FEC_GROUP, visitor_.header_->is_in_fec_group);
+ EXPECT_EQ(GG_UINT64_C(0x341256789ABA),
+ visitor_.header_->fec_group);
+ const size_t fec_offset = GetStartOfFecProtectedData(
+ PACKET_8BYTE_GUID, !kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER);
+ EXPECT_EQ(
+ string(AsChars(packet) + fec_offset, arraysize(packet) - fec_offset),
+ visitor_.fec_protected_payload_);
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+ EXPECT_EQ(GG_UINT64_C(0x01020304), visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654),
+ visitor_.stream_frames_[0]->offset);
+ EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
+}
+
TEST_P(QuicFramerTest, AckFrame) {
unsigned char packet[] = {
// public flags (8 byte guid)
@@ -1503,7 +1944,7 @@ TEST_P(QuicFramerTest, AckFrame) {
0x00,
// frame type (ack frame)
- 0x02,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x02 : 0x01),
// entropy hash of sent packets till least awaiting - 1.
0xAB,
// least packet sequence number awaiting an ack
@@ -1835,7 +2276,7 @@ TEST_P(QuicFramerTest, RstStreamFrame) {
0x00,
// frame type (rst stream frame)
- 0x04,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x04 : 0x27),
// stream id
0x04, 0x03, 0x02, 0x01,
// error code
@@ -1864,9 +2305,9 @@ TEST_P(QuicFramerTest, RstStreamFrame) {
// Now test framing boundaries
for (size_t i = 2; i < 24; ++i) {
string expected_error;
- if (i < kQuicFrameTypeSize + kQuicStreamIdSize) {
+ if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
expected_error = "Unable to read stream_id.";
- } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize +
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
kQuicErrorCodeSize) {
expected_error = "Unable to read rst stream error code.";
} else {
@@ -1894,7 +2335,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) {
0x00,
// frame type (connection close frame)
- 0x05,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x05 : 0x2F),
// error code
0x11, 0x00, 0x00, 0x00,
@@ -1981,7 +2422,7 @@ TEST_P(QuicFramerTest, GoAwayFrame) {
0x00,
// frame type (go away frame)
- 0x06,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x06 : 0x37),
// error code
0x09, 0x00, 0x00, 0x00,
// stream id
@@ -2015,7 +2456,7 @@ TEST_P(QuicFramerTest, GoAwayFrame) {
if (i < kQuicFrameTypeSize + kQuicErrorCodeSize) {
expected_error = "Unable to read go away error code.";
} else if (i < kQuicFrameTypeSize + kQuicErrorCodeSize +
- kQuicStreamIdSize) {
+ kQuicMaxStreamIdSize) {
expected_error = "Unable to read last good stream id.";
} else {
expected_error = "Unable to read goaway reason.";
@@ -2082,7 +2523,7 @@ TEST_P(QuicFramerTest, PublicResetPacket) {
TEST_P(QuicFramerTest, VersionNegotiationPacket) {
// Set a specific version.
- framer_.set_version(QUIC_VERSION_6);
+ framer_.set_version(QUIC_VERSION_7);
unsigned char packet[] = {
// public flags (version, 8 byte guid)
@@ -2091,7 +2532,7 @@ TEST_P(QuicFramerTest, VersionNegotiationPacket) {
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
- 'Q', '0', '0', '6',
+ 'Q', '0', '0', '7',
'Q', '2', '.', '0',
};
@@ -2102,7 +2543,7 @@ TEST_P(QuicFramerTest, VersionNegotiationPacket) {
ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
ASSERT_TRUE(visitor_.version_negotiation_packet_.get());
EXPECT_EQ(2u, visitor_.version_negotiation_packet_->versions.size());
- EXPECT_EQ(QUIC_VERSION_6,
+ EXPECT_EQ(QUIC_VERSION_7,
visitor_.version_negotiation_packet_->versions[0]);
for (size_t i = 0; i <= kPublicFlagsSize + PACKET_8BYTE_GUID; ++i) {
@@ -2157,7 +2598,7 @@ TEST_P(QuicFramerTest, FecPacket) {
EXPECT_EQ("abcdefghijklmnop", fec_data.redundancy);
}
-TEST_P(QuicFramerTest, ConstructPaddingFramePacket) {
+TEST_P(QuicFramerTest, BuildPaddingFramePacket) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2185,7 +2626,7 @@ TEST_P(QuicFramerTest, ConstructPaddingFramePacket) {
0x00,
// frame type (padding frame)
- 0x00,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x00 : 0x07),
};
uint64 header_size =
@@ -2194,7 +2635,7 @@ TEST_P(QuicFramerTest, ConstructPaddingFramePacket) {
memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1);
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2202,7 +2643,7 @@ TEST_P(QuicFramerTest, ConstructPaddingFramePacket) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, Construct4ByteSequenceNumberPaddingFramePacket) {
+TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2230,7 +2671,7 @@ TEST_P(QuicFramerTest, Construct4ByteSequenceNumberPaddingFramePacket) {
0x00,
// frame type (padding frame)
- 0x00,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x00 : 0x07),
};
uint64 header_size =
@@ -2239,7 +2680,7 @@ TEST_P(QuicFramerTest, Construct4ByteSequenceNumberPaddingFramePacket) {
memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1);
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2247,7 +2688,7 @@ TEST_P(QuicFramerTest, Construct4ByteSequenceNumberPaddingFramePacket) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, Construct2ByteSequenceNumberPaddingFramePacket) {
+TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2275,7 +2716,7 @@ TEST_P(QuicFramerTest, Construct2ByteSequenceNumberPaddingFramePacket) {
0x00,
// frame type (padding frame)
- 0x00,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x00 : 0x07),
};
uint64 header_size =
@@ -2284,7 +2725,7 @@ TEST_P(QuicFramerTest, Construct2ByteSequenceNumberPaddingFramePacket) {
memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1);
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2292,7 +2733,7 @@ TEST_P(QuicFramerTest, Construct2ByteSequenceNumberPaddingFramePacket) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, Construct1ByteSequenceNumberPaddingFramePacket) {
+TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2320,7 +2761,7 @@ TEST_P(QuicFramerTest, Construct1ByteSequenceNumberPaddingFramePacket) {
0x00,
// frame type (padding frame)
- 0x00,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x00 : 0x07),
};
uint64 header_size =
@@ -2329,7 +2770,7 @@ TEST_P(QuicFramerTest, Construct1ByteSequenceNumberPaddingFramePacket) {
memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1);
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2337,7 +2778,10 @@ TEST_P(QuicFramerTest, Construct1ByteSequenceNumberPaddingFramePacket) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, ConstructStreamFramePacket) {
+TEST_P(QuicFramerTest, BuildStreamFramePacketVersion6) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_6);
+
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2386,7 +2830,63 @@ TEST_P(QuicFramerTest, ConstructStreamFramePacket) {
};
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
+ ASSERT_TRUE(data != NULL);
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildStreamFramePacket) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_7);
+
+ 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(0x77123456789ABC);
+ header.fec_group = 0;
+
+ QuicStreamFrame stream_frame;
+ stream_frame.stream_id = 0x01020304;
+ stream_frame.fin = true;
+ stream_frame.offset = GG_UINT64_C(0xBA98FEDC32107654);
+ stream_frame.data = "hello world!";
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&stream_frame));
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (stream frame with fin and no length)
+ 0xBE,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+
+ scoped_ptr<QuicPacket> data(
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2394,7 +2894,7 @@ TEST_P(QuicFramerTest, ConstructStreamFramePacket) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) {
+TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2414,7 +2914,7 @@ TEST_P(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) {
frames.push_back(QuicFrame(&stream_frame));
// Set a specific version.
- framer_.set_version(QUIC_VERSION_6);
+ framer_.set_version(QUIC_VERSION_7);
unsigned char packet[] = {
// public flags (version, 8 byte guid)
0x3D,
@@ -2422,24 +2922,20 @@ TEST_P(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) {
0x10, 0x32, 0x54, 0x76,
0x98, 0xBA, 0xDC, 0xFE,
// version tag
- 'Q', '0', '0', '6',
+ 'Q', '0', '0', '7',
// packet sequence number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
// private flags (entropy)
0x01,
- // frame type (stream frame)
- 0x01,
+ // frame type (stream frame with fin and no length)
+ 0xBE,
// stream id
0x04, 0x03, 0x02, 0x01,
- // fin
- 0x01,
// offset
0x54, 0x76, 0x10, 0x32,
0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
// data
'h', 'e', 'l', 'l',
'o', ' ', 'w', 'o',
@@ -2448,7 +2944,7 @@ TEST_P(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) {
QuicFramerPeer::SetIsServer(&framer_, false);
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2456,7 +2952,7 @@ TEST_P(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, ConstructVersionNegotiationPacket) {
+TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
QuicPacketPublicHeader header;
header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.reset_flag = false;
@@ -2470,21 +2966,21 @@ TEST_P(QuicFramerTest, ConstructVersionNegotiationPacket) {
0x98, 0xBA, 0xDC, 0xFE,
// version tag
'Q', '0', '0', '6',
- // 'Q', '0', '0', '7',
+ 'Q', '0', '0', '7',
};
QuicVersionVector versions;
versions.push_back(QUIC_VERSION_6);
- // versions.push_back(QUIC_VERSION_7);
+ versions.push_back(QUIC_VERSION_7);
scoped_ptr<QuicEncryptedPacket> data(
- framer_.ConstructVersionNegotiationPacket(header, versions));
+ framer_.BuildVersionNegotiationPacket(header, versions));
test::CompareCharArraysWithHexError("constructed packet",
data->data(), data->length(),
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, ConstructAckFramePacket) {
+TEST_P(QuicFramerTest, BuildAckFramePacket) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2519,7 +3015,7 @@ TEST_P(QuicFramerTest, ConstructAckFramePacket) {
0x01,
// frame type (ack frame)
- 0x02,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x02 : 0x01),
// entropy hash of sent packets till least awaiting - 1.
0x14,
// least packet sequence number awaiting an ack
@@ -2540,7 +3036,7 @@ TEST_P(QuicFramerTest, ConstructAckFramePacket) {
};
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2548,7 +3044,7 @@ TEST_P(QuicFramerTest, ConstructAckFramePacket) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) {
+TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketTCP) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2589,7 +3085,7 @@ TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) {
};
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2597,7 +3093,7 @@ TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketTCP) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) {
+TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketInterArrival) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2662,7 +3158,7 @@ TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) {
};
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2670,7 +3166,7 @@ TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketInterArrival) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) {
+TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketFixRate) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2709,7 +3205,7 @@ TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) {
};
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2717,7 +3213,7 @@ TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketFixRate) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketInvalidFeedback) {
+TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketInvalidFeedback) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2735,11 +3231,11 @@ TEST_P(QuicFramerTest, ConstructCongestionFeedbackFramePacketInvalidFeedback) {
frames.push_back(QuicFrame(&congestion_feedback_frame));
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data == NULL);
}
-TEST_P(QuicFramerTest, ConstructRstFramePacket) {
+TEST_P(QuicFramerTest, BuildRstFramePacket) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2767,7 +3263,7 @@ TEST_P(QuicFramerTest, ConstructRstFramePacket) {
0x00,
// frame type (rst stream frame)
- 0x04,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x04 : 0x27),
// stream id
0x04, 0x03, 0x02, 0x01,
// error code
@@ -2785,7 +3281,7 @@ TEST_P(QuicFramerTest, ConstructRstFramePacket) {
frames.push_back(QuicFrame(&rst_frame));
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2793,7 +3289,7 @@ TEST_P(QuicFramerTest, ConstructRstFramePacket) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, ConstructCloseFramePacket) {
+TEST_P(QuicFramerTest, BuildCloseFramePacket) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2830,7 +3326,7 @@ TEST_P(QuicFramerTest, ConstructCloseFramePacket) {
0x01,
// frame type (connection close frame)
- 0x05,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x05 : 0x2F),
// error code
0x08, 0x07, 0x06, 0x05,
// error details length
@@ -2862,7 +3358,7 @@ TEST_P(QuicFramerTest, ConstructCloseFramePacket) {
};
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2870,7 +3366,7 @@ TEST_P(QuicFramerTest, ConstructCloseFramePacket) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, ConstructGoAwayPacket) {
+TEST_P(QuicFramerTest, BuildGoAwayPacket) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2901,7 +3397,7 @@ TEST_P(QuicFramerTest, ConstructGoAwayPacket) {
0x01,
// frame type (go away frame)
- 0x06,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x06 : 0x37),
// error code
0x08, 0x07, 0x06, 0x05,
// stream id
@@ -2916,7 +3412,7 @@ TEST_P(QuicFramerTest, ConstructGoAwayPacket) {
};
scoped_ptr<QuicPacket> data(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2924,7 +3420,7 @@ TEST_P(QuicFramerTest, ConstructGoAwayPacket) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, ConstructPublicResetPacket) {
+TEST_P(QuicFramerTest, BuildPublicResetPacket) {
QuicPublicResetPacket reset_packet;
reset_packet.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
reset_packet.public_header.reset_flag = true;
@@ -2947,7 +3443,7 @@ TEST_P(QuicFramerTest, ConstructPublicResetPacket) {
};
scoped_ptr<QuicEncryptedPacket> data(
- framer_.ConstructPublicResetPacket(reset_packet));
+ framer_.BuildPublicResetPacket(reset_packet));
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -2955,7 +3451,7 @@ TEST_P(QuicFramerTest, ConstructPublicResetPacket) {
AsChars(packet), arraysize(packet));
}
-TEST_P(QuicFramerTest, ConstructFecPacket) {
+TEST_P(QuicFramerTest, BuildFecPacket) {
QuicPacketHeader header;
header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
header.public_header.reset_flag = false;
@@ -2992,7 +3488,7 @@ TEST_P(QuicFramerTest, ConstructFecPacket) {
};
scoped_ptr<QuicPacket> data(
- framer_.ConstructFecPacket(header, fec_data).packet);
+ framer_.BuildFecPacket(header, fec_data).packet);
ASSERT_TRUE(data != NULL);
test::CompareCharArraysWithHexError("constructed packet",
@@ -3120,7 +3616,7 @@ TEST_P(QuicFramerTest, DISABLED_Truncation) {
frames.push_back(frame);
scoped_ptr<QuicPacket> raw_ack_packet(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(raw_ack_packet != NULL);
scoped_ptr<QuicEncryptedPacket> ack_packet(
@@ -3134,7 +3630,7 @@ TEST_P(QuicFramerTest, DISABLED_Truncation) {
frames.push_back(frame);
scoped_ptr<QuicPacket> raw_close_packet(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(raw_close_packet != NULL);
scoped_ptr<QuicEncryptedPacket> close_packet(
@@ -3176,7 +3672,7 @@ TEST_P(QuicFramerTest, CleanTruncation) {
frames.push_back(frame);
scoped_ptr<QuicPacket> raw_ack_packet(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(raw_ack_packet != NULL);
scoped_ptr<QuicEncryptedPacket> ack_packet(
@@ -3190,7 +3686,7 @@ TEST_P(QuicFramerTest, CleanTruncation) {
frames.push_back(frame);
scoped_ptr<QuicPacket> raw_close_packet(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(raw_close_packet != NULL);
scoped_ptr<QuicEncryptedPacket> close_packet(
@@ -3212,7 +3708,7 @@ TEST_P(QuicFramerTest, CleanTruncation) {
size_t original_raw_length = raw_ack_packet->length();
raw_ack_packet.reset(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(raw_ack_packet != NULL);
EXPECT_EQ(original_raw_length, raw_ack_packet->length());
@@ -3223,12 +3719,15 @@ TEST_P(QuicFramerTest, CleanTruncation) {
original_raw_length = raw_close_packet->length();
raw_close_packet.reset(
- framer_.ConstructFrameDataPacket(header, frames).packet);
+ framer_.BuildUnsizedDataPacket(header, frames).packet);
ASSERT_TRUE(raw_ack_packet != NULL);
EXPECT_EQ(original_raw_length, raw_close_packet->length());
}
-TEST_P(QuicFramerTest, EntropyFlagTest) {
+TEST_P(QuicFramerTest, EntropyFlagTestVersion6) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_6);
+
unsigned char packet[] = {
// public flags (8 byte guid)
0x3C,
@@ -3267,7 +3766,48 @@ TEST_P(QuicFramerTest, EntropyFlagTest) {
EXPECT_FALSE(visitor_.header_->fec_flag);
};
-TEST_P(QuicFramerTest, FecEntropyTest) {
+TEST_P(QuicFramerTest, EntropyFlagTest) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_7);
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (Entropy)
+ 0x01,
+
+ // frame type (stream frame with fin and no length)
+ 0xBE,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+
+ 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(visitor_.header_->entropy_flag);
+ EXPECT_EQ(1 << 4, visitor_.header_->entropy_hash);
+ EXPECT_FALSE(visitor_.header_->fec_flag);
+};
+
+TEST_P(QuicFramerTest, FecEntropyTestVersion6) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_6);
+
unsigned char packet[] = {
// public flags (8 byte guid)
0x3C,
@@ -3308,7 +3848,50 @@ TEST_P(QuicFramerTest, FecEntropyTest) {
EXPECT_EQ(1 << 4, visitor_.header_->entropy_hash);
};
-TEST_P(QuicFramerTest, StopPacketProcessing) {
+TEST_P(QuicFramerTest, FecEntropyTest) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_7);
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (Entropy & fec group & FEC)
+ 0x07,
+ // first fec protected packet offset
+ 0xFF,
+
+ // frame type (stream frame with fin and no length)
+ 0xBE,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+
+ 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(visitor_.header_->fec_flag);
+ EXPECT_TRUE(visitor_.header_->entropy_flag);
+ EXPECT_EQ(1 << 4, visitor_.header_->entropy_hash);
+};
+
+TEST_P(QuicFramerTest, StopPacketProcessingVersion6) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_6);
+
unsigned char packet[] = {
// public flags (8 byte guid)
0x3C,
@@ -3369,6 +3952,68 @@ TEST_P(QuicFramerTest, StopPacketProcessing) {
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
}
+TEST_P(QuicFramerTest, StopPacketProcessing) {
+ // Set a specific version.
+ framer_.set_version(QUIC_VERSION_7);
+
+ unsigned char packet[] = {
+ // public flags (8 byte guid)
+ 0x3C,
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Entropy
+ 0x01,
+
+ // frame type (stream frame with fin)
+ 0xFE,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+
+ // frame type (ack frame)
+ 0x02,
+ // entropy hash of sent packets till least awaiting - 1.
+ 0x14,
+ // least packet sequence number awaiting an ack
+ 0xA0, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // entropy hash of all received packets.
+ 0x43,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // num missing packets
+ 0x01,
+ // missing packet
+ 0xBE, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ };
+
+ MockFramerVisitor visitor;
+ framer_.set_visitor(&visitor);
+ EXPECT_CALL(visitor, OnPacket());
+ EXPECT_CALL(visitor, OnPacketHeader(_));
+ EXPECT_CALL(visitor, OnStreamFrame(_)).WillOnce(Return(false));
+ EXPECT_CALL(visitor, OnAckFrame(_)).Times(0);
+ EXPECT_CALL(visitor, OnPacketComplete());
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+}
+
TEST_P(QuicFramerTest, ConnectionCloseWithInvalidAck) {
unsigned char packet[] = {
// public flags (8 byte guid)
@@ -3383,7 +4028,7 @@ TEST_P(QuicFramerTest, ConnectionCloseWithInvalidAck) {
0x00,
// frame type (connection close frame)
- 0x05,
+ static_cast<unsigned char>((version_ == QUIC_VERSION_6) ? 0x05 : 0x2F),
// error code
0x11, 0x00, 0x00, 0x00,
// error details length
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 9f3a69c..997dc95 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -288,7 +288,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
QuicFrames frames;
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
- framer_.ConstructFrameDataPacket(header_, frames).packet);
+ framer_.BuildUnsizedDataPacket(header_, frames).packet);
return framer_.EncryptPacket(
ENCRYPTION_NONE, header.packet_sequence_number, *packet);
}
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 8ea2d10..0722b58 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -146,7 +146,7 @@ class QuicNetworkTransactionTest : public PlatformTest {
frames.push_back(QuicFrame(&ack));
frames.push_back(QuicFrame(&feedback));
scoped_ptr<QuicPacket> packet(
- framer.ConstructFrameDataPacket(header, frames).packet);
+ framer.BuildUnsizedDataPacket(header, frames).packet);
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
ENCRYPTION_NONE, header.packet_sequence_number, *packet));
}
@@ -197,7 +197,7 @@ class QuicNetworkTransactionTest : public PlatformTest {
QuicFrames frames;
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
- framer.ConstructFrameDataPacket(header, frames).packet);
+ framer.BuildUnsizedDataPacket(header, frames).packet);
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
ENCRYPTION_NONE, header.packet_sequence_number, *packet));
}
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index eec8ab3..19e58c3 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -77,12 +77,15 @@ void QuicPacketCreator::StopSendingVersion() {
}
}
-bool QuicPacketCreator::HasRoomForStreamFrame() const {
- return BytesFree() > QuicFramer::GetMinStreamFrameSize();
+bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id,
+ QuicStreamOffset offset) const {
+ return BytesFree() >
+ QuicFramer::GetMinStreamFrameSize(framer_->version(), id, offset, true);
}
// static
size_t QuicPacketCreator::StreamFramePacketOverhead(
+ QuicVersion version,
QuicGuidLength guid_length,
bool include_version,
QuicSequenceNumberLength sequence_number_length,
@@ -90,7 +93,7 @@ size_t QuicPacketCreator::StreamFramePacketOverhead(
return GetPacketHeaderSize(guid_length, include_version,
sequence_number_length, is_in_fec_group) +
// Assumes this is a stream with a single lone packet.
- QuicFramer::GetMinStreamFrameSize(1, 0, true);
+ QuicFramer::GetMinStreamFrameSize(version, 1u, 0u, true);
}
size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
@@ -100,17 +103,17 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
QuicFrame* frame) {
DCHECK_GT(options_.max_packet_length,
StreamFramePacketOverhead(
- PACKET_8BYTE_GUID, kIncludeVersion,
+ framer_->version(), PACKET_8BYTE_GUID, kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, IN_FEC_GROUP));
- DCHECK(HasRoomForStreamFrame());
+ DCHECK(HasRoomForStreamFrame(id, offset));
const size_t free_bytes = BytesFree();
size_t bytes_consumed = 0;
if (data.size() != 0) {
size_t min_last_stream_frame_size =
- QuicFramer::GetMinStreamFrameSize(id, offset, true);
- // Comparing against the last stream frame size including the length
+ QuicFramer::GetMinStreamFrameSize(framer_->version(), id, offset, true);
+ // Comparing against the last stream frame size including the frame length
// guarantees that all the bytes will fit. Otherwise there is a
// discontinuity where the packet goes one byte over due to the length data.
if (data.size() + min_last_stream_frame_size + kQuicStreamPayloadLengthSize
@@ -119,6 +122,7 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
bytes_consumed =
min<size_t>(free_bytes - min_last_stream_frame_size, data.size());
} else {
+ DCHECK_LT(data.size(), BytesFree());
bytes_consumed = data.size();
}
@@ -171,7 +175,7 @@ SerializedPacket QuicPacketCreator::SerializePacket() {
QuicPacketHeader header;
FillPacketHeader(fec_group_number_, false, false, &header);
- SerializedPacket serialized = framer_->ConstructFrameDataPacket(
+ SerializedPacket serialized = framer_->BuildDataPacket(
header, queued_frames_, packet_size_);
queued_frames_.clear();
packet_size_ = GetPacketHeaderSize(options_.send_guid_length,
@@ -192,7 +196,7 @@ SerializedPacket QuicPacketCreator::SerializeFec() {
QuicFecData fec_data;
fec_data.fec_group = fec_group_->min_protected_packet();
fec_data.redundancy = fec_group_->payload_parity();
- SerializedPacket serialized = framer_->ConstructFecPacket(header, fec_data);
+ SerializedPacket serialized = framer_->BuildFecPacket(header, fec_data);
fec_group_.reset(NULL);
fec_group_number_ = 0;
// Reset packet_size_, since the next packet may not have an FEC group.
@@ -221,7 +225,7 @@ QuicEncryptedPacket* QuicPacketCreator::SerializeVersionNegotiationPacket(
header.version_flag = true;
header.versions = supported_versions;
QuicEncryptedPacket* encrypted =
- framer_->ConstructVersionNegotiationPacket(header, supported_versions);
+ framer_->BuildVersionNegotiationPacket(header, supported_versions);
DCHECK(encrypted);
DCHECK_GE(options_.max_packet_length, encrypted->length());
return encrypted;
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index 6c21a94..a1d74fa 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -71,12 +71,13 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
// The overhead the framing will add for a packet with one frame.
static size_t StreamFramePacketOverhead(
+ QuicVersion version,
QuicGuidLength guid_length,
bool include_version,
QuicSequenceNumberLength sequence_number_length,
InFecGroup is_in_fec_group);
- bool HasRoomForStreamFrame() const;
+ bool HasRoomForStreamFrame(QuicStreamId id, QuicStreamOffset offset) const;
// Converts a raw payload to a frame which fits into the currently open
// packet if there is one. Returns the number of bytes consumed from data.
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index b55f350..1d793d2 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -177,6 +177,35 @@ TEST_F(QuicPacketCreatorTest, CreateStreamFrameFinOnly) {
delete frame.stream_frame;
}
+TEST_F(QuicPacketCreatorTest, CreateAllFreeBytesForStreamFrames) {
+ QuicStreamId kStreamId = 1u;
+ QuicStreamOffset kOffset = 1u;
+ for (int i = 0; i < 100; ++i) {
+ creator_.options()->max_packet_length = i;
+ const size_t max_plaintext_size = client_framer_.GetMaxPlaintextSize(i);
+ const bool should_have_room = max_plaintext_size >
+ (QuicFramer::GetMinStreamFrameSize(
+ client_framer_.version(), kStreamId, kOffset, true) +
+ GetPacketHeaderSize(creator_.options()->send_guid_length,
+ kIncludeVersion,
+ creator_.options()->send_sequence_number_length,
+ NOT_IN_FEC_GROUP));
+ ASSERT_EQ(should_have_room,
+ creator_.HasRoomForStreamFrame(kStreamId, kOffset));
+ if (should_have_room) {
+ QuicFrame frame;
+ size_t bytes_consumed = creator_.CreateStreamFrame(
+ kStreamId, "testdata", kOffset, false, &frame);
+ EXPECT_LT(0u, bytes_consumed);
+ ASSERT_TRUE(creator_.AddSavedFrame(frame));
+ SerializedPacket serialized_packet = creator_.SerializePacket();
+ ASSERT_TRUE(serialized_packet.packet);
+ delete serialized_packet.packet;
+ delete serialized_packet.retransmittable_frames;
+ }
+ }
+}
+
TEST_F(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) {
QuicPacketCreatorPeer::SetIsServer(&creator_, true);
QuicVersionVector versions;
@@ -226,6 +255,7 @@ TEST_P(QuicPacketCreatorTest, CreateStreamFrameTooLarge) {
// A string larger than fits into a frame.
size_t payload_length;
creator_.options()->max_packet_length = GetPacketLengthForOneStream(
+ client_framer_.version(),
QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
NOT_IN_FEC_GROUP, &payload_length);
QuicFrame frame;
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index 34ed0a0..7600010 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -89,7 +89,7 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id,
DCHECK(data.empty() || packet_creator_->BytesFree() == 0u);
// TODO(ianswett): Restore packet reordering.
- if (should_flush_ || !packet_creator_->HasRoomForStreamFrame()) {
+ if (should_flush_ || !packet_creator_->HasRoomForStreamFrame(id, offset)) {
SerializeAndSendPacket();
}
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index abbbadf..6d21710 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -127,8 +127,8 @@ QuicTag QuicVersionToQuicTag(const QuicVersion version) {
switch (version) {
case QUIC_VERSION_6:
return MakeQuicTag('Q', '0', '0', '6');
- // case QUIC_VERSION_7
- // return MakeQuicTag('Q', '0', '0', '7');
+ case QUIC_VERSION_7:
+ return MakeQuicTag('Q', '0', '0', '7');
default:
// This shold be an ERROR because we should never attempt to convert an
// invalid QuicVersion to be written to the wire.
@@ -139,12 +139,12 @@ QuicTag QuicVersionToQuicTag(const QuicVersion version) {
QuicVersion QuicTagToQuicVersion(const QuicTag version_tag) {
const QuicTag quic_tag_v6 = MakeQuicTag('Q', '0', '0', '6');
- // const QuicTag quic_tag_v7 = MakeQuicTag('Q', '0', '0', '7');
+ const QuicTag quic_tag_v7 = MakeQuicTag('Q', '0', '0', '7');
if (version_tag == quic_tag_v6) {
return QUIC_VERSION_6;
- // } else if (version_tag == quic_tag_v7) {
- // return QUIC_VERSION_7;
+ } else if (version_tag == quic_tag_v7) {
+ return QUIC_VERSION_7;
} else {
// Reading from the client so this should not be considered an ERROR.
DLOG(INFO) << "Unsupported QuicTag version: "
@@ -159,8 +159,8 @@ string QuicVersionToString(const QuicVersion version) {
switch (version) {
case QUIC_VERSION_6:
return "QUIC_VERSION_6";
- // case QUIC_VERSION_7:
- // return "QUIC_VERSION_7";
+ case QUIC_VERSION_7:
+ return "QUIC_VERSION_7";
default:
return "QUIC_VERSION_UNSUPPORTED";
}
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 8b17cd5..fe4da4c 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -186,14 +186,16 @@ enum QuicVersion {
// Special case to indicate unknown/unsupported QUIC version.
QUIC_VERSION_UNSUPPORTED = 0,
- QUIC_VERSION_6 = 6, // Current version.
+ QUIC_VERSION_6 = 6,
+ QUIC_VERSION_7 = 7, // Current version.
};
// This vector contains QUIC versions which we currently support.
// This should be ordered such that the highest supported version is the first
// element, with subsequent elements in descending order (versions can be
// skipped as necessary).
-static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_6};
+static const QuicVersion kSupportedQuicVersions[] =
+ {QUIC_VERSION_7, QUIC_VERSION_6};
typedef std::vector<QuicVersion> QuicVersionVector;
diff --git a/net/quic/quic_protocol_test.cc b/net/quic/quic_protocol_test.cc
index a22cb62..877f03d 100644
--- a/net/quic/quic_protocol_test.cc
+++ b/net/quic/quic_protocol_test.cc
@@ -135,10 +135,10 @@ TEST(QuicProtocolTest, QuicVersionToString) {
QuicVersion single_version[] = {QUIC_VERSION_6};
EXPECT_EQ("QUIC_VERSION_6,", QuicVersionArrayToString(single_version,
arraysize(single_version)));
- // QuicVersion multiple_versions[] = {QUIC_VERSION_7, QUIC_VERSION_6};
- // EXPECT_EQ("QUIC_VERSION_7,QUIC_VERSION_6,",
- // QuicVersionArrayToString(multiple_versions,
- // arraysize(multiple_versions)));
+ QuicVersion multiple_versions[] = {QUIC_VERSION_7, QUIC_VERSION_6};
+ EXPECT_EQ("QUIC_VERSION_7,QUIC_VERSION_6,",
+ QuicVersionArrayToString(multiple_versions,
+ arraysize(multiple_versions)));
}
} // namespace
diff --git a/net/quic/quic_received_entropy_manager.cc b/net/quic/quic_received_entropy_manager.cc
deleted file mode 100644
index 57020eb..0000000
--- a/net/quic/quic_received_entropy_manager.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_received_entropy_manager.h"
-
-#include "base/logging.h"
-#include "net/base/linked_hash_map.h"
-
-using std::make_pair;
-using std::max;
-using std::min;
-
-namespace net {
-
-QuicReceivedEntropyManager::QuicReceivedEntropyManager()
- : packets_entropy_hash_(0),
- largest_sequence_number_(0) {}
-
-QuicReceivedEntropyManager::~QuicReceivedEntropyManager() {}
-
-QuicPacketSequenceNumber
-QuicReceivedEntropyManager::LargestSequenceNumber() const {
- if (packets_entropy_.empty()) {
- return 0;
- }
- return packets_entropy_.rbegin()->first;
-}
-
-void QuicReceivedEntropyManager::RecordPacketEntropyHash(
- QuicPacketSequenceNumber sequence_number,
- QuicPacketEntropyHash entropy_hash) {
- if (sequence_number < largest_sequence_number_) {
- DLOG(INFO) << "Ignoring received packet entropy for sequence_number:"
- << sequence_number << " less than largest_peer_sequence_number:"
- << largest_sequence_number_;
- return;
- }
- packets_entropy_.insert(make_pair(sequence_number, entropy_hash));
- packets_entropy_hash_ ^= entropy_hash;
- DVLOG(2) << "setting cumulative received entropy hash to: "
- << static_cast<int>(packets_entropy_hash_)
- << " updated with sequence number " << sequence_number
- << " entropy hash: " << static_cast<int>(entropy_hash);
-}
-
-QuicPacketEntropyHash QuicReceivedEntropyManager::EntropyHash(
- QuicPacketSequenceNumber sequence_number) const {
- DCHECK_LE(sequence_number, LargestSequenceNumber());
- DCHECK_GE(sequence_number, largest_sequence_number_);
- if (sequence_number == LargestSequenceNumber()) {
- return packets_entropy_hash_;
- }
-
- ReceivedEntropyMap::const_iterator it =
- packets_entropy_.upper_bound(sequence_number);
- // When this map is empty we should only query entropy for
- // |largest_received_sequence_number_|.
- LOG_IF(WARNING, it != packets_entropy_.end())
- << "largest_received: " << LargestSequenceNumber()
- << " sequence_number: " << sequence_number;
-
- // TODO(satyamshekhar): Make this O(1).
- QuicPacketEntropyHash hash = packets_entropy_hash_;
- for (; it != packets_entropy_.end(); ++it) {
- hash ^= it->second;
- }
- return hash;
-}
-
-void QuicReceivedEntropyManager::RecalculateEntropyHash(
- QuicPacketSequenceNumber peer_least_unacked,
- QuicPacketEntropyHash entropy_hash) {
- DLOG_IF(WARNING, peer_least_unacked > LargestSequenceNumber())
- << "Prematurely updating the entropy manager before registering the "
- << "entropy of the containing packet creates a temporary inconsistency.";
- if (peer_least_unacked < largest_sequence_number_) {
- DLOG(INFO) << "Ignoring received peer_least_unacked:" << peer_least_unacked
- << " less than largest_peer_sequence_number:"
- << largest_sequence_number_;
- return;
- }
- largest_sequence_number_ = peer_least_unacked;
- packets_entropy_hash_ = entropy_hash;
- ReceivedEntropyMap::iterator it =
- packets_entropy_.lower_bound(peer_least_unacked);
- // TODO(satyamshekhar): Make this O(1).
- for (; it != packets_entropy_.end(); ++it) {
- packets_entropy_hash_ ^= it->second;
- }
- // Discard entropies before least unacked.
- packets_entropy_.erase(
- packets_entropy_.begin(),
- packets_entropy_.lower_bound(
- min(peer_least_unacked, LargestSequenceNumber())));
-}
-
-} // namespace net
diff --git a/net/quic/quic_received_entropy_manager.h b/net/quic/quic_received_entropy_manager.h
deleted file mode 100644
index d969834..0000000
--- a/net/quic/quic_received_entropy_manager.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2013 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.
-//
-// Manages the packet entropy calculation for both sent and received packets
-// for a connection.
-
-#ifndef NET_QUIC_QUIC_RECEIVED_ENTROPY_MANAGER_H_
-#define NET_QUIC_QUIC_RECEIVED_ENTROPY_MANAGER_H_
-
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-// Records all received packets by a connection to track the cumulative
-// entropy of received packets. Also, called by the framer when it truncates
-// an ack frame to calculate the correct entropy value for the ack frame being
-// serialized.
-class NET_EXPORT_PRIVATE QuicReceivedEntropyManager :
- public QuicReceivedEntropyHashCalculatorInterface {
- public:
- QuicReceivedEntropyManager();
- virtual ~QuicReceivedEntropyManager();
-
- // Record the received entropy hash against |sequence_number|.
- void RecordPacketEntropyHash(QuicPacketSequenceNumber sequence_number,
- QuicPacketEntropyHash entropy_hash);
-
- // QuicReceivedEntropyHashCalculatorInterface
- // Called by QuicFramer, when the outgoing ack gets truncated, to recalculate
- // the received entropy hash for the truncated ack frame.
- virtual QuicPacketEntropyHash EntropyHash(
- QuicPacketSequenceNumber sequence_number) const OVERRIDE;
-
- QuicPacketSequenceNumber LargestSequenceNumber() const;
-
- // Recalculate the entropy hash and clears old packet entropies,
- // now that the sender sent us the |entropy_hash| for packets up to,
- // but not including, |peer_least_unacked|.
- void RecalculateEntropyHash(QuicPacketSequenceNumber peer_least_unacked,
- QuicPacketEntropyHash entropy_hash);
-
- QuicPacketEntropyHash packets_entropy_hash() const {
- return packets_entropy_hash_;
- }
-
- private:
- typedef std::map<QuicPacketSequenceNumber,
- QuicPacketEntropyHash> ReceivedEntropyMap;
-
- // TODO(satyamshekhar): Can be optimized using an interval set like data
- // structure.
- // Map of received sequence numbers to their corresponding entropy.
- // Every received packet has an entry, and packets without the entropy bit set
- // have an entropy value of 0.
- // TODO(ianswett): When the entropy flag is off, the entropy should not be 0.
- ReceivedEntropyMap packets_entropy_;
-
- // Cumulative hash of entropy of all received packets.
- QuicPacketEntropyHash packets_entropy_hash_;
-
- // The largest sequence number cleared by RecalculateEntropyHash.
- // Received entropy cannot be calculated for numbers less than it.
- QuicPacketSequenceNumber largest_sequence_number_;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_RECEIVED_ENTROPY_MANAGER_H_
diff --git a/net/quic/quic_received_entropy_manager_test.cc b/net/quic/quic_received_entropy_manager_test.cc
deleted file mode 100644
index c857315e..0000000
--- a/net/quic/quic_received_entropy_manager_test.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_received_entropy_manager.h"
-
-#include <algorithm>
-#include <vector>
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::make_pair;
-using std::pair;
-using std::vector;
-
-namespace net {
-namespace test {
-namespace {
-
-class QuicReceivedEntropyManagerTest : public ::testing::Test {
- protected:
- QuicReceivedEntropyManager entropy_manager_;
-};
-
-TEST_F(QuicReceivedEntropyManagerTest, ReceivedPacketEntropyHash) {
- vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies;
- entropies.push_back(make_pair(1, 12));
- entropies.push_back(make_pair(7, 1));
- entropies.push_back(make_pair(2, 33));
- entropies.push_back(make_pair(5, 3));
- entropies.push_back(make_pair(8, 34));
-
- for (size_t i = 0; i < entropies.size(); ++i) {
- entropy_manager_.RecordPacketEntropyHash(entropies[i].first,
- entropies[i].second);
- }
-
- sort(entropies.begin(), entropies.end());
-
- QuicPacketEntropyHash hash = 0;
- size_t index = 0;
- for (size_t i = 1; i <= (*entropies.rbegin()).first; ++i) {
- if (entropies[index].first == i) {
- hash ^= entropies[index].second;
- ++index;
- }
- EXPECT_EQ(hash, entropy_manager_.EntropyHash(i));
- }
-}
-
-TEST_F(QuicReceivedEntropyManagerTest, EntropyHashBelowLeastObserved) {
- EXPECT_EQ(0, entropy_manager_.EntropyHash(0));
- entropy_manager_.RecordPacketEntropyHash(4, 5);
- EXPECT_EQ(0, entropy_manager_.EntropyHash(3));
-}
-
-TEST_F(QuicReceivedEntropyManagerTest, EntropyHashAboveLargestObserved) {
- EXPECT_EQ(0, entropy_manager_.EntropyHash(0));
- entropy_manager_.RecordPacketEntropyHash(4, 5);
- EXPECT_EQ(0, entropy_manager_.EntropyHash(3));
-}
-
-TEST_F(QuicReceivedEntropyManagerTest, RecalculateEntropyHash) {
- vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies;
- entropies.push_back(make_pair(1, 12));
- entropies.push_back(make_pair(2, 1));
- entropies.push_back(make_pair(3, 33));
- entropies.push_back(make_pair(4, 3));
- entropies.push_back(make_pair(5, 34));
- entropies.push_back(make_pair(6, 29));
-
- QuicPacketEntropyHash entropy_hash = 0;
- for (size_t i = 0; i < entropies.size(); ++i) {
- entropy_manager_.RecordPacketEntropyHash(entropies[i].first,
- entropies[i].second);
- entropy_hash ^= entropies[i].second;
- }
- EXPECT_EQ(entropy_hash, entropy_manager_.EntropyHash(6));
-
- // Now set the entropy hash up to 4 to be 100.
- entropy_hash ^= 100;
- for (size_t i = 0; i < 3; ++i) {
- entropy_hash ^= entropies[i].second;
- }
- entropy_manager_.RecalculateEntropyHash(4, 100);
- EXPECT_EQ(entropy_hash, entropy_manager_.EntropyHash(6));
-
- // Ensure it doesn't change with an old received sequence number or entropy.
- entropy_manager_.RecordPacketEntropyHash(1, 50);
- EXPECT_EQ(entropy_hash, entropy_manager_.EntropyHash(6));
-
- entropy_manager_.RecalculateEntropyHash(1, 50);
- EXPECT_EQ(entropy_hash, entropy_manager_.EntropyHash(6));
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/net/quic/quic_received_packet_manager.cc b/net/quic/quic_received_packet_manager.cc
index e69de29..f6f94cc 100644
--- a/net/quic/quic_received_packet_manager.cc
+++ b/net/quic/quic_received_packet_manager.cc
@@ -0,0 +1,188 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_received_packet_manager.h"
+
+#include "base/logging.h"
+#include "net/base/linked_hash_map.h"
+
+using std::make_pair;
+using std::max;
+using std::min;
+
+namespace net {
+
+QuicReceivedPacketManager::QuicReceivedPacketManager()
+ : packets_entropy_hash_(0),
+ largest_sequence_number_(0),
+ peer_largest_observed_packet_(0),
+ least_packet_awaited_by_peer_(1),
+ peer_least_packet_awaiting_ack_(0),
+ time_largest_observed_(QuicTime::Zero()) {
+ received_info_.largest_observed = 0;
+ received_info_.entropy_hash = 0;
+}
+
+QuicReceivedPacketManager::~QuicReceivedPacketManager() {}
+
+void QuicReceivedPacketManager::RecordPacketReceived(
+ const QuicPacketHeader& header, QuicTime receipt_time) {
+ QuicPacketSequenceNumber sequence_number = header.packet_sequence_number;
+ DCHECK(IsAwaitingPacket(sequence_number));
+
+ InsertMissingPacketsBetween(
+ &received_info_,
+ max(received_info_.largest_observed + 1, peer_least_packet_awaiting_ack_),
+ header.packet_sequence_number);
+
+ if (received_info_.largest_observed > header.packet_sequence_number) {
+ // We've gotten one of the out of order packets - remove it from our
+ // "missing packets" list.
+ DVLOG(1) << "Removing " << sequence_number << " from missing list";
+ received_info_.missing_packets.erase(sequence_number);
+ }
+ if (header.packet_sequence_number > received_info_.largest_observed) {
+ received_info_.largest_observed = header.packet_sequence_number;
+ time_largest_observed_ = receipt_time;
+ }
+ RecordPacketEntropyHash(sequence_number, header.entropy_hash);
+}
+
+bool QuicReceivedPacketManager::IsAwaitingPacket(
+ QuicPacketSequenceNumber sequence_number) {
+ return ::net::IsAwaitingPacket(received_info_, sequence_number);
+}
+
+void QuicReceivedPacketManager::UpdateReceivedPacketInfo(
+ ReceivedPacketInfo* received_info, QuicTime approximate_now) {
+ *received_info = received_info_;
+ received_info->entropy_hash = EntropyHash(received_info_.largest_observed);
+ if (time_largest_observed_ == QuicTime::Zero()) {
+ // We have not received any new higher sequence numbers since we sent our
+ // last ACK.
+ received_info->delta_time_largest_observed = QuicTime::Delta::Infinite();
+ } else {
+ received_info->delta_time_largest_observed =
+ approximate_now.Subtract(time_largest_observed_);
+
+ time_largest_observed_ = QuicTime::Zero();
+ }
+}
+
+void QuicReceivedPacketManager::RecordPacketEntropyHash(
+ QuicPacketSequenceNumber sequence_number,
+ QuicPacketEntropyHash entropy_hash) {
+ if (sequence_number < largest_sequence_number_) {
+ DLOG(INFO) << "Ignoring received packet entropy for sequence_number:"
+ << sequence_number << " less than largest_peer_sequence_number:"
+ << largest_sequence_number_;
+ return;
+ }
+ packets_entropy_.insert(make_pair(sequence_number, entropy_hash));
+ packets_entropy_hash_ ^= entropy_hash;
+ DVLOG(2) << "setting cumulative received entropy hash to: "
+ << static_cast<int>(packets_entropy_hash_)
+ << " updated with sequence number " << sequence_number
+ << " entropy hash: " << static_cast<int>(entropy_hash);
+}
+
+QuicPacketEntropyHash QuicReceivedPacketManager::EntropyHash(
+ QuicPacketSequenceNumber sequence_number) const {
+ DCHECK_LE(sequence_number, received_info_.largest_observed);
+ DCHECK_GE(sequence_number, largest_sequence_number_);
+ if (sequence_number == received_info_.largest_observed) {
+ return packets_entropy_hash_;
+ }
+
+ ReceivedEntropyMap::const_iterator it =
+ packets_entropy_.upper_bound(sequence_number);
+ // When this map is empty we should only query entropy for
+ // |largest_received_sequence_number_|.
+ LOG_IF(WARNING, it != packets_entropy_.end())
+ << "largest_received: " << received_info_.largest_observed
+ << " sequence_number: " << sequence_number;
+
+ // TODO(satyamshekhar): Make this O(1).
+ QuicPacketEntropyHash hash = packets_entropy_hash_;
+ for (; it != packets_entropy_.end(); ++it) {
+ hash ^= it->second;
+ }
+ return hash;
+}
+
+void QuicReceivedPacketManager::RecalculateEntropyHash(
+ QuicPacketSequenceNumber peer_least_unacked,
+ QuicPacketEntropyHash entropy_hash) {
+ DLOG_IF(WARNING, peer_least_unacked > received_info_.largest_observed)
+ << "Prematurely updating the entropy manager before registering the "
+ << "entropy of the containing packet creates a temporary inconsistency.";
+ if (peer_least_unacked < largest_sequence_number_) {
+ DLOG(INFO) << "Ignoring received peer_least_unacked:" << peer_least_unacked
+ << " less than largest_peer_sequence_number:"
+ << largest_sequence_number_;
+ return;
+ }
+ largest_sequence_number_ = peer_least_unacked;
+ packets_entropy_hash_ = entropy_hash;
+ ReceivedEntropyMap::iterator it =
+ packets_entropy_.lower_bound(peer_least_unacked);
+ // TODO(satyamshekhar): Make this O(1).
+ for (; it != packets_entropy_.end(); ++it) {
+ packets_entropy_hash_ ^= it->second;
+ }
+ // Discard entropies before least unacked.
+ packets_entropy_.erase(
+ packets_entropy_.begin(),
+ packets_entropy_.lower_bound(
+ min(peer_least_unacked, received_info_.largest_observed)));
+}
+
+void QuicReceivedPacketManager::UpdatePacketInformationReceivedByPeer(
+ const QuicAckFrame& incoming_ack) {
+ // ValidateAck should fail if largest_observed ever shrinks.
+ DCHECK_LE(peer_largest_observed_packet_,
+ incoming_ack.received_info.largest_observed);
+ peer_largest_observed_packet_ = incoming_ack.received_info.largest_observed;
+
+ if (incoming_ack.received_info.missing_packets.empty()) {
+ least_packet_awaited_by_peer_ = peer_largest_observed_packet_ + 1;
+ } else {
+ least_packet_awaited_by_peer_ =
+ *(incoming_ack.received_info.missing_packets.begin());
+ }
+}
+
+bool QuicReceivedPacketManager::DontWaitForPacketsBefore(
+ QuicPacketSequenceNumber least_unacked) {
+ size_t missing_packets_count = received_info_.missing_packets.size();
+ received_info_.missing_packets.erase(
+ received_info_.missing_packets.begin(),
+ received_info_.missing_packets.lower_bound(least_unacked));
+ return missing_packets_count != received_info_.missing_packets.size();
+}
+
+void QuicReceivedPacketManager::UpdatePacketInformationSentByPeer(
+ const QuicAckFrame& incoming_ack) {
+ // ValidateAck() should fail if peer_least_packet_awaiting_ack_ shrinks.
+ DCHECK_LE(peer_least_packet_awaiting_ack_,
+ incoming_ack.sent_info.least_unacked);
+ if (incoming_ack.sent_info.least_unacked > peer_least_packet_awaiting_ack_) {
+ bool missed_packets =
+ DontWaitForPacketsBefore(incoming_ack.sent_info.least_unacked);
+ if (missed_packets || incoming_ack.sent_info.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(incoming_ack.sent_info.least_unacked,
+ incoming_ack.sent_info.entropy_hash);
+ }
+ peer_least_packet_awaiting_ack_ = incoming_ack.sent_info.least_unacked;
+ }
+ DCHECK(received_info_.missing_packets.empty() ||
+ *received_info_.missing_packets.begin() >=
+ peer_least_packet_awaiting_ack_);
+}
+
+} // namespace net
diff --git a/net/quic/quic_received_packet_manager.h b/net/quic/quic_received_packet_manager.h
index e69de29..a762ae8 100644
--- a/net/quic/quic_received_packet_manager.h
+++ b/net/quic/quic_received_packet_manager.h
@@ -0,0 +1,124 @@
+// Copyright 2013 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.
+//
+// Manages the packet entropy calculation for both sent and received packets
+// for a connection.
+
+#ifndef NET_QUIC_QUIC_RECEIVED_PACKET_MANAGER_H_
+#define NET_QUIC_QUIC_RECEIVED_PACKET_MANAGER_H_
+
+#include "net/quic/quic_framer.h"
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+namespace test {
+class QuicReceivedPacketManagerPeer;
+} // namespace test
+
+// Records all received packets by a connection and tracks their entropy.
+// Also calculates the correct entropy for the framer when it truncates an ack
+// frame being serialized.
+class NET_EXPORT_PRIVATE QuicReceivedPacketManager :
+ public QuicReceivedEntropyHashCalculatorInterface {
+ public:
+ QuicReceivedPacketManager();
+ virtual ~QuicReceivedPacketManager();
+
+ // Updates the internal state concerning which packets have been acked.
+ void RecordPacketReceived(const QuicPacketHeader& header,
+ QuicTime receipt_time);
+
+ // Checks if we're still waiting for the packet with |sequence_number|.
+ bool IsAwaitingPacket(QuicPacketSequenceNumber sequence_number);
+
+ // Update the |received_info| for an outgoing ack.
+ void UpdateReceivedPacketInfo(ReceivedPacketInfo* received_info,
+ QuicTime approximate_now);
+
+ // QuicReceivedEntropyHashCalculatorInterface
+ // Called by QuicFramer, when the outgoing ack gets truncated, to recalculate
+ // the received entropy hash for the truncated ack frame.
+ virtual QuicPacketEntropyHash EntropyHash(
+ QuicPacketSequenceNumber sequence_number) const OVERRIDE;
+
+ // These two are called by OnAckFrame.
+ //
+ // Updates internal state based on |incoming_ack.received_info|.
+ void UpdatePacketInformationReceivedByPeer(const QuicAckFrame& incoming_ack);
+ // Updates internal state based on |incoming_ack.sent_info|.
+ void UpdatePacketInformationSentByPeer(const QuicAckFrame& incoming_ack);
+
+ QuicPacketSequenceNumber peer_largest_observed_packet() {
+ return peer_largest_observed_packet_;
+ }
+
+ QuicPacketSequenceNumber least_packet_awaited_by_peer() {
+ return least_packet_awaited_by_peer_;
+ }
+
+ QuicPacketSequenceNumber peer_least_packet_awaiting_ack() {
+ return peer_least_packet_awaiting_ack_;
+ }
+
+ private:
+ friend class test::QuicReceivedPacketManagerPeer;
+
+ typedef std::map<QuicPacketSequenceNumber,
+ QuicPacketEntropyHash> ReceivedEntropyMap;
+
+ // Record the received entropy hash against |sequence_number|.
+ void RecordPacketEntropyHash(QuicPacketSequenceNumber sequence_number,
+ QuicPacketEntropyHash entropy_hash);
+
+ // Recalculate the entropy hash and clears old packet entropies,
+ // now that the sender sent us the |entropy_hash| for packets up to,
+ // but not including, |peer_least_unacked|.
+ void RecalculateEntropyHash(QuicPacketSequenceNumber peer_least_unacked,
+ QuicPacketEntropyHash entropy_hash);
+
+ // Deletes all missing packets before least unacked. The connection won't
+ // process any packets with sequence number before |least_unacked| that it
+ // received after this call. Returns true if there were missing packets before
+ // |least_unacked| unacked, false otherwise.
+ bool DontWaitForPacketsBefore(QuicPacketSequenceNumber least_unacked);
+
+ // TODO(satyamshekhar): Can be optimized using an interval set like data
+ // structure.
+ // Map of received sequence numbers to their corresponding entropy.
+ // Every received packet has an entry, and packets without the entropy bit set
+ // have an entropy value of 0.
+ // TODO(ianswett): When the entropy flag is off, the entropy should not be 0.
+ ReceivedEntropyMap packets_entropy_;
+
+ // Cumulative hash of entropy of all received packets.
+ QuicPacketEntropyHash packets_entropy_hash_;
+
+ // The largest sequence number cleared by RecalculateEntropyHash.
+ // Received entropy cannot be calculated for numbers less than it.
+ QuicPacketSequenceNumber largest_sequence_number_;
+
+
+ // Track some peer state so we can do less bookkeeping.
+ // Largest sequence number that the peer has observed. Mostly received,
+ // missing in case of truncated acks.
+ QuicPacketSequenceNumber peer_largest_observed_packet_;
+ // Least sequence number which the peer is still waiting for.
+ QuicPacketSequenceNumber least_packet_awaited_by_peer_;
+ // Least sequence number of the the packet sent by the peer for which it
+ // hasn't received an ack.
+ QuicPacketSequenceNumber peer_least_packet_awaiting_ack_;
+
+ // Received packet information used to produce acks.
+ ReceivedPacketInfo received_info_;
+
+ // The time we received the largest_observed sequence number, or zero if
+ // no sequence numbers have been received since UpdateReceivedPacketInfo.
+ // Needed for calculating delta_time_largest_observed.
+ QuicTime time_largest_observed_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_RECEIVED_PACKET_MANAGER_H_
diff --git a/net/quic/quic_received_packet_manager_test.cc b/net/quic/quic_received_packet_manager_test.cc
index e69de29..76be470 100644
--- a/net/quic/quic_received_packet_manager_test.cc
+++ b/net/quic/quic_received_packet_manager_test.cc
@@ -0,0 +1,119 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_received_packet_manager.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "net/quic/test_tools/quic_received_packet_manager_peer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::make_pair;
+using std::pair;
+using std::vector;
+
+namespace net {
+namespace test {
+namespace {
+
+class QuicReceivedPacketManagerTest : public ::testing::Test {
+ protected:
+ void RecordPacketEntropyHash(QuicPacketSequenceNumber sequence_number,
+ QuicPacketEntropyHash entropy_hash) {
+ QuicPacketHeader header;
+ header.packet_sequence_number = sequence_number;
+ header.entropy_hash = entropy_hash;
+ received_manager_.RecordPacketReceived(header, QuicTime::Zero());;
+ }
+
+ QuicReceivedPacketManager received_manager_;
+};
+
+TEST_F(QuicReceivedPacketManagerTest, ReceivedPacketEntropyHash) {
+ vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies;
+ entropies.push_back(make_pair(1, 12));
+ entropies.push_back(make_pair(7, 1));
+ entropies.push_back(make_pair(2, 33));
+ entropies.push_back(make_pair(5, 3));
+ entropies.push_back(make_pair(8, 34));
+
+ for (size_t i = 0; i < entropies.size(); ++i) {
+ RecordPacketEntropyHash(entropies[i].first,
+ entropies[i].second);
+ }
+
+ sort(entropies.begin(), entropies.end());
+
+ QuicPacketEntropyHash hash = 0;
+ size_t index = 0;
+ for (size_t i = 1; i <= (*entropies.rbegin()).first; ++i) {
+ if (entropies[index].first == i) {
+ hash ^= entropies[index].second;
+ ++index;
+ }
+ EXPECT_EQ(hash, received_manager_.EntropyHash(i));
+ }
+}
+
+TEST_F(QuicReceivedPacketManagerTest, EntropyHashBelowLeastObserved) {
+ EXPECT_EQ(0, received_manager_.EntropyHash(0));
+ RecordPacketEntropyHash(4, 5);
+ EXPECT_EQ(0, received_manager_.EntropyHash(3));
+}
+
+TEST_F(QuicReceivedPacketManagerTest, EntropyHashAboveLargestObserved) {
+ EXPECT_EQ(0, received_manager_.EntropyHash(0));
+ RecordPacketEntropyHash(4, 5);
+ EXPECT_EQ(0, received_manager_.EntropyHash(3));
+}
+
+TEST_F(QuicReceivedPacketManagerTest, RecalculateEntropyHash) {
+ vector<pair<QuicPacketSequenceNumber, QuicPacketEntropyHash> > entropies;
+ entropies.push_back(make_pair(1, 12));
+ entropies.push_back(make_pair(2, 1));
+ entropies.push_back(make_pair(3, 33));
+ entropies.push_back(make_pair(4, 3));
+ entropies.push_back(make_pair(5, 34));
+ entropies.push_back(make_pair(6, 29));
+
+ QuicPacketEntropyHash entropy_hash = 0;
+ for (size_t i = 0; i < entropies.size(); ++i) {
+ RecordPacketEntropyHash(entropies[i].first, entropies[i].second);
+ entropy_hash ^= entropies[i].second;
+ }
+ EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(6));
+
+ // Now set the entropy hash up to 4 to be 100.
+ entropy_hash ^= 100;
+ for (size_t i = 0; i < 3; ++i) {
+ entropy_hash ^= entropies[i].second;
+ }
+ QuicReceivedPacketManagerPeer::RecalculateEntropyHash(
+ &received_manager_, 4, 100);
+ EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(6));
+
+ QuicReceivedPacketManagerPeer::RecalculateEntropyHash(
+ &received_manager_, 1, 50);
+ EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(6));
+}
+
+TEST_F(QuicReceivedPacketManagerTest, DontWaitForPacketsBefore) {
+ QuicPacketHeader header;
+ header.packet_sequence_number = 2u;
+ received_manager_.RecordPacketReceived(header, QuicTime::Zero());
+ header.packet_sequence_number = 7u;
+ received_manager_.RecordPacketReceived(header, QuicTime::Zero());
+ EXPECT_TRUE(received_manager_.IsAwaitingPacket(3u));
+ EXPECT_TRUE(received_manager_.IsAwaitingPacket(6u));
+ EXPECT_TRUE(QuicReceivedPacketManagerPeer::DontWaitForPacketsBefore(
+ &received_manager_, 4));
+ EXPECT_FALSE(received_manager_.IsAwaitingPacket(3u));
+ EXPECT_TRUE(received_manager_.IsAwaitingPacket(6u));
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 9785e27..9fb44d4 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -12,10 +12,13 @@
using base::StringPiece;
using base::hash_map;
using base::hash_set;
+using std::make_pair;
using std::vector;
namespace net {
+const size_t kMaxPrematurelyClosedStreamsTracked = 20;
+
#define ENDPOINT (is_server_ ? "Server: " : " Client: ")
// We want to make sure we delete any closed streams in a safe manner.
@@ -104,9 +107,21 @@ bool QuicSession::OnPacket(const IPEndPoint& self_address,
<< header.public_header.guid;
return false;
}
+
for (size_t i = 0; i < frames.size(); ++i) {
// TODO(rch) deal with the error case of stream id 0
- if (IsClosedStream(frames[i].stream_id)) continue;
+ if (IsClosedStream(frames[i].stream_id)) {
+ // If we get additional frames for a stream where we didn't process
+ // headers, it's highly likely our compression context will end up
+ // permanently out of sync with the peer's, so we give up and close the
+ // connection.
+ if (ContainsKey(prematurely_closed_streams_, frames[i].stream_id)) {
+ connection()->SendConnectionClose(
+ QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED);
+ return false;
+ }
+ continue;
+ }
ReliableQuicStream* stream = GetStream(frames[i].stream_id);
if (stream == NULL) return false;
@@ -218,6 +233,13 @@ void QuicSession::CloseStream(QuicStreamId stream_id) {
return;
}
ReliableQuicStream* stream = it->second;
+ if (!stream->headers_decompressed()) {
+ if (prematurely_closed_streams_.size() ==
+ kMaxPrematurelyClosedStreamsTracked) {
+ prematurely_closed_streams_.erase(prematurely_closed_streams_.begin());
+ }
+ prematurely_closed_streams_.insert(make_pair(stream->id(), true));
+ }
closed_streams_.push_back(it->second);
stream_map_.erase(it);
stream->OnClose();
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 1c9ab1b..3f0f99f 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -12,6 +12,7 @@
#include "base/compiler_specific.h"
#include "base/containers/hash_tables.h"
#include "net/base/ip_endpoint.h"
+#include "net/base/linked_hash_map.h"
#include "net/quic/blocked_list.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_crypto_stream.h"
@@ -172,6 +173,8 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
ReliableQuicStream* GetIncomingReliableStream(QuicStreamId stream_id);
+ ReliableQuicStream* GetStream(const QuicStreamId stream_id);
+
// This is called after every call other than OnConnectionClose from the
// QuicConnectionVisitor to allow post-processing once the work has been done.
// In this case, it deletes streams given that it's safe to do so (no other
@@ -204,10 +207,13 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
typedef base::hash_map<QuicStreamId, ReliableQuicStream*> ReliableStreamMap;
- ReliableQuicStream* GetStream(const QuicStreamId stream_id);
-
scoped_ptr<QuicConnection> connection_;
+ // Tracks the last 20 streams which closed without decompressing headers.
+ // This is for best-effort detection of an unrecoverable compression context.
+ // Ideally this would be a linked_hash_set as the boolean is unused.
+ linked_hash_map<QuicStreamId, bool> prematurely_closed_streams_;
+
// A shim to stand between the connection and the session, to handle stream
// deletions.
scoped_ptr<VisitorShim> visitor_shim_;
diff --git a/net/quic/quic_spdy_decompressor.cc b/net/quic/quic_spdy_decompressor.cc
index 23d4633..f8bd4c1 100644
--- a/net/quic/quic_spdy_decompressor.cc
+++ b/net/quic/quic_spdy_decompressor.cc
@@ -23,21 +23,6 @@ class SpdyFramerVisitor : public SpdyFramerVisitorInterface {
virtual void OnError(SpdyFramer* framer) OVERRIDE {
error_ = true;
}
- virtual void OnSynStream(SpdyStreamId stream_id,
- SpdyStreamId associated_stream_id,
- SpdyPriority priority,
- uint8 credential_slot,
- bool fin,
- bool unidirectional) OVERRIDE {}
- virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE {}
- virtual void OnHeaders(SpdyStreamId stream_id, bool fin) OVERRIDE {}
- virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id,
- const char* header_data,
- size_t len) OVERRIDE;
- virtual bool OnCredentialFrameData(const char* credential_data,
- size_t len) OVERRIDE {
- return false;
- }
virtual void OnDataFrameHeader(SpdyStreamId stream_id,
size_t length,
bool fin) OVERRIDE {}
@@ -45,16 +30,31 @@ class SpdyFramerVisitor : public SpdyFramerVisitorInterface {
const char* data,
size_t len,
bool fin) OVERRIDE {}
+ virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id,
+ const char* header_data,
+ size_t len) OVERRIDE;
+ virtual void OnSynStream(SpdyStreamId stream_id,
+ SpdyStreamId associated_stream_id,
+ SpdyPriority priority,
+ uint8 credential_slot,
+ bool fin,
+ bool unidirectional) OVERRIDE {}
+ virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE {}
+ virtual void OnRstStream(SpdyStreamId stream_id,
+ SpdyRstStreamStatus status) OVERRIDE {}
virtual void OnSetting(SpdySettingsIds id,
uint8 flags,
uint32 value) OVERRIDE {}
virtual void OnPing(uint32 unique_id) OVERRIDE {}
- virtual void OnRstStream(SpdyStreamId stream_id,
- SpdyRstStreamStatus status) OVERRIDE {}
virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
SpdyGoAwayStatus status) OVERRIDE {}
+ virtual void OnHeaders(SpdyStreamId stream_id, bool fin) OVERRIDE {}
virtual void OnWindowUpdate(SpdyStreamId stream_id,
uint32 delta_window_size) OVERRIDE {}
+ virtual bool OnCredentialFrameData(const char* credential_data,
+ size_t len) OVERRIDE {
+ return false;
+ }
virtual void OnPushPromise(SpdyStreamId stream_id,
SpdyStreamId promised_stream_id) OVERRIDE {}
void set_visitor(QuicSpdyDecompressor::Visitor* visitor) {
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index b51033f..2f46772 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -77,7 +77,7 @@ class QuicStreamFactoryTest : public ::testing::Test {
frames.push_back(QuicFrame(&ack));
frames.push_back(QuicFrame(&feedback));
scoped_ptr<QuicPacket> packet(
- framer.ConstructFrameDataPacket(header, frames).packet);
+ framer.BuildUnsizedDataPacket(header, frames).packet);
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
ENCRYPTION_NONE, header.packet_sequence_number, *packet));
}
@@ -110,7 +110,7 @@ class QuicStreamFactoryTest : public ::testing::Test {
QuicFrames frames;
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
- framer.ConstructFrameDataPacket(header, frames).packet);
+ framer.BuildUnsizedDataPacket(header, frames).packet);
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(
ENCRYPTION_NONE, header.packet_sequence_number, *packet));
}
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 3f5150b..352325d 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -116,6 +116,8 @@ class NET_EXPORT_PRIVATE ReliableQuicStream : public
// Gets the SSL connection information.
bool GetSSLInfo(SSLInfo* ssl_info);
+ bool headers_decompressed() const { return headers_decompressed_; }
+
protected:
// Returns a pair with the number of bytes consumed from data, and a boolean
// indicating if the fin bit was consumed. This does not indicate the data
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index 5548697..7167a22 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -124,7 +124,7 @@ TEST_F(ReliableQuicStreamTest, WriteAllData) {
connection_->options()->max_packet_length =
1 + QuicPacketCreator::StreamFramePacketOverhead(
- PACKET_8BYTE_GUID, !kIncludeVersion,
+ connection_->version(), PACKET_8BYTE_GUID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
// TODO(rch): figure out how to get StrEq working here.
//EXPECT_CALL(*session_, WriteData(kStreamId, StrEq(kData1), _, _)).WillOnce(
@@ -192,7 +192,7 @@ TEST_F(ReliableQuicStreamTest, WriteData) {
EXPECT_TRUE(write_blocked_list_->IsEmpty());
connection_->options()->max_packet_length =
1 + QuicPacketCreator::StreamFramePacketOverhead(
- PACKET_8BYTE_GUID, !kIncludeVersion,
+ connection_->version(), PACKET_8BYTE_GUID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
// TODO(rch): figure out how to get StrEq working here.
//EXPECT_CALL(*session_, WriteData(_, StrEq(kData1), _, _)).WillOnce(
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc
index 330aa06..bb6b3fc3 100644
--- a/net/quic/test_tools/quic_connection_peer.cc
+++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -34,10 +34,8 @@ void QuicConnectionPeer::SetSendAlgorithm(
}
// static
-QuicAckFrame* QuicConnectionPeer::GetOutgoingAck(
- QuicConnection* connection) {
- connection->UpdateOutgoingAck();
- return &connection->outgoing_ack_;
+QuicAckFrame* QuicConnectionPeer::CreateAckFrame(QuicConnection* connection) {
+ return connection->CreateAckFrame();
}
// static
@@ -106,7 +104,7 @@ bool QuicConnectionPeer::IsValidEntropy(
QuicPacketEntropyHash QuicConnectionPeer::ReceivedEntropyHash(
QuicConnection* connection,
QuicPacketSequenceNumber sequence_number) {
- return connection->received_entropy_manager_.EntropyHash(
+ return connection->received_packet_manager_.EntropyHash(
sequence_number);
}
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h
index 090a1f2..7ce3c5b3 100644
--- a/net/quic/test_tools/quic_connection_peer.h
+++ b/net/quic/test_tools/quic_connection_peer.h
@@ -36,7 +36,7 @@ class QuicConnectionPeer {
static void SetSendAlgorithm(QuicConnection* connection,
SendAlgorithmInterface* send_algorithm);
- static QuicAckFrame* GetOutgoingAck(QuicConnection* connection);
+ static QuicAckFrame* CreateAckFrame(QuicConnection* connection);
static QuicConnectionVisitorInterface* GetVisitor(
QuicConnection* connection);
diff --git a/net/quic/test_tools/quic_received_packet_manager_peer.cc b/net/quic/test_tools/quic_received_packet_manager_peer.cc
new file mode 100644
index 0000000..d25a209
--- /dev/null
+++ b/net/quic/test_tools/quic_received_packet_manager_peer.cc
@@ -0,0 +1,30 @@
+// Copyright 2013 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/test_tools/quic_received_packet_manager_peer.h"
+
+#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_received_packet_manager.h"
+
+namespace net {
+namespace test {
+
+// static
+void QuicReceivedPacketManagerPeer::RecalculateEntropyHash(
+ QuicReceivedPacketManager* received_packet_manager,
+ QuicPacketSequenceNumber peer_least_unacked,
+ QuicPacketEntropyHash entropy_hash) {
+ received_packet_manager->RecalculateEntropyHash(peer_least_unacked,
+ entropy_hash);
+}
+
+// static
+bool QuicReceivedPacketManagerPeer::DontWaitForPacketsBefore(
+ QuicReceivedPacketManager* received_packet_manager,
+ QuicPacketSequenceNumber least_unacked) {
+ return received_packet_manager->DontWaitForPacketsBefore(least_unacked);
+}
+
+} // namespace test
+} // namespace net
diff --git a/net/quic/test_tools/quic_received_packet_manager_peer.h b/net/quic/test_tools/quic_received_packet_manager_peer.h
new file mode 100644
index 0000000..4607a0c
--- /dev/null
+++ b/net/quic/test_tools/quic_received_packet_manager_peer.h
@@ -0,0 +1,35 @@
+// Copyright 2013 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_TEST_TOOLS_QUIC_RECEIVED_PACKET_MANAGER_PEER_H_
+#define NET_QUIC_TEST_TOOLS_QUIC_RECEIVED_PACKET_MANAGER_PEER_H_
+
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+class QuicReceivedPacketManager;
+
+namespace test {
+
+class QuicReceivedPacketManagerPeer {
+ public:
+ static void RecalculateEntropyHash(
+ QuicReceivedPacketManager* received_packet_manager,
+ QuicPacketSequenceNumber peer_least_unacked,
+ QuicPacketEntropyHash entropy_hash);
+
+ static bool DontWaitForPacketsBefore(
+ QuicReceivedPacketManager* received_packet_manager,
+ QuicPacketSequenceNumber least_unacked);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicReceivedPacketManagerPeer);
+};
+
+} // namespace test
+
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_QUIC_RECEIVED_PACKET_MANAGER_PEER_H_
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 3f122ba..5d1b3a0 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -372,7 +372,7 @@ static QuicPacket* ConstructPacketFromHandshakeMessage(
QuicFrame frame(&stream_frame);
QuicFrames frames;
frames.push_back(frame);
- return quic_framer.ConstructFrameDataPacket(header, frames).packet;
+ return quic_framer.BuildUnsizedDataPacket(header, frames).packet;
}
QuicPacket* ConstructHandshakePacket(QuicGuid guid, QuicTag tag) {
@@ -381,13 +381,15 @@ QuicPacket* ConstructHandshakePacket(QuicGuid guid, QuicTag tag) {
return ConstructPacketFromHandshakeMessage(guid, message, false);
}
-size_t GetPacketLengthForOneStream(
- bool include_version, InFecGroup is_in_fec_group, size_t* payload_length) {
+size_t GetPacketLengthForOneStream(QuicVersion version,
+ bool include_version,
+ InFecGroup is_in_fec_group,
+ size_t* payload_length) {
*payload_length = 1;
const size_t stream_length =
NullEncrypter().GetCiphertextSize(*payload_length) +
QuicPacketCreator::StreamFramePacketOverhead(
- PACKET_8BYTE_GUID, include_version,
+ version, PACKET_8BYTE_GUID, include_version,
PACKET_6BYTE_SEQUENCE_NUMBER, is_in_fec_group);
const size_t ack_length = NullEncrypter().GetCiphertextSize(
QuicFramer::GetMinAckFrameSize()) +
@@ -399,10 +401,16 @@ size_t GetPacketLengthForOneStream(
return NullEncrypter().GetCiphertextSize(*payload_length) +
QuicPacketCreator::StreamFramePacketOverhead(
- PACKET_8BYTE_GUID, include_version,
+ version, PACKET_8BYTE_GUID, include_version,
PACKET_6BYTE_SEQUENCE_NUMBER, is_in_fec_group);
}
+size_t GetMinStreamFrameSize(QuicVersion version) {
+ return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize +
+ (version == QUIC_VERSION_6 ?
+ (kQuicStreamFinSize + kQuicStreamPayloadLengthSize) : 0);
+}
+
QuicPacketEntropyHash TestEntropyCalculator::EntropyHash(
QuicPacketSequenceNumber sequence_number) const {
return 1u;
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index a635a4c..f6172c9 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -38,8 +38,14 @@ void CompareQuicDataWithHexError(const std::string& description,
// Returns the length of a QuicPacket that is capable of holding either a
// stream frame or a minimal ack frame. Sets |*payload_length| to the number
// of bytes of stream data that will fit in such a packet.
-size_t GetPacketLengthForOneStream(
- bool include_version, InFecGroup is_in_fec_group, size_t* payload_length);
+size_t GetPacketLengthForOneStream(QuicVersion version,
+ bool include_version,
+ InFecGroup is_in_fec_group,
+ size_t* payload_length);
+
+// Size in bytes of the stream frame fields for an arbitrary StreamID and
+// offset and the last frame in a packet.
+size_t GetMinStreamFrameSize(QuicVersion version);
string SerializeUncompressedHeaders(const SpdyHeaderBlock& headers);
diff --git a/net/quic/test_tools/reliable_quic_stream_peer.cc b/net/quic/test_tools/reliable_quic_stream_peer.cc
index 5119d03..31a64e9 100644
--- a/net/quic/test_tools/reliable_quic_stream_peer.cc
+++ b/net/quic/test_tools/reliable_quic_stream_peer.cc
@@ -22,5 +22,11 @@ void ReliableQuicStreamPeer::SetStreamBytesWritten(
stream->stream_bytes_written_ = stream_bytes_written;
}
+void ReliableQuicStreamPeer::SetHeadersDecompressed(
+ ReliableQuicStream* stream,
+ bool headers_decompressed) {
+ stream->headers_decompressed_ = headers_decompressed;
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/reliable_quic_stream_peer.h b/net/quic/test_tools/reliable_quic_stream_peer.h
index da229da..346a9b4 100644
--- a/net/quic/test_tools/reliable_quic_stream_peer.h
+++ b/net/quic/test_tools/reliable_quic_stream_peer.h
@@ -19,6 +19,8 @@ class ReliableQuicStreamPeer {
static void SetWriteSideClosed(bool value, ReliableQuicStream* stream);
static void SetStreamBytesWritten(QuicStreamOffset stream_bytes_written,
ReliableQuicStream* stream);
+ static void SetHeadersDecompressed(ReliableQuicStream* stream,
+ bool headers_decompressed);
private:
DISALLOW_COPY_AND_ASSIGN(ReliableQuicStreamPeer);
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 310c393..40449b3 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -134,6 +134,7 @@ class EndToEndTest : public ::testing::TestWithParam<QuicVersion> {
virtual QuicTestClient* CreateQuicClient() {
QuicTestClient* client = new QuicTestClient(server_address_,
server_hostname_,
+ false, // not secure
client_config_,
version_);
client->Connect();
@@ -211,10 +212,10 @@ class EndToEndTest : public ::testing::TestWithParam<QuicVersion> {
QuicVersion version_;
};
-// Run all end to end tests with QUIC version 6.
+// Run all end to end tests with QUIC version 6 and 7.
INSTANTIATE_TEST_CASE_P(EndToEndTests,
EndToEndTest,
- ::testing::Values(QUIC_VERSION_6));
+ ::testing::Values(QUIC_VERSION_6, QUIC_VERSION_7));
TEST_P(EndToEndTest, SimpleRequestResponse) {
// TODO(rtenneti): Delete this when NSS is supported.
@@ -335,9 +336,12 @@ TEST_P(EndToEndTest, RequestOverMultiplePackets) {
// are added.
// TODO(rch) handle this better when we have different encryption options.
- size_t stream_data = 3;
- size_t stream_payload_size = QuicFramer::GetMinStreamFrameSize() +
- stream_data;
+ const size_t kStreamDataLength = 3;
+ const QuicStreamId kStreamId = 1u;
+ const QuicStreamOffset kStreamOffset = 0u;
+ size_t stream_payload_size =
+ QuicFramer::GetMinStreamFrameSize(
+ GetParam(), kStreamId, kStreamOffset, true) + kStreamDataLength;
size_t min_payload_size =
std::max(kCongestionFeedbackFrameSize, stream_payload_size);
size_t ciphertext_size = NullEncrypter().GetCiphertextSize(min_payload_size);
@@ -367,9 +371,12 @@ TEST_P(EndToEndTest, MultipleFramesRandomOrder) {
// are added.
// TODO(rch) handle this better when we have different encryption options.
- size_t stream_data = 3;
- size_t stream_payload_size = QuicFramer::GetMinStreamFrameSize() +
- stream_data;
+ const size_t kStreamDataLength = 3;
+ const QuicStreamId kStreamId = 1u;
+ const QuicStreamOffset kStreamOffset = 0u;
+ size_t stream_payload_size =
+ QuicFramer::GetMinStreamFrameSize(
+ GetParam(), kStreamId, kStreamOffset, true) + kStreamDataLength;
size_t min_payload_size =
std::max(kCongestionFeedbackFrameSize, stream_payload_size);
size_t ciphertext_size = NullEncrypter().GetCiphertextSize(min_payload_size);
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index 0d3baa9..86fa6c4 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -155,8 +155,8 @@ bool QuicClient::StartConnect() {
server_hostname_,
config_,
new QuicConnection(guid, server_address_,
- new QuicEpollConnectionHelper(fd_, &epoll_server_),
- false, version_),
+ CreateQuicConnectionHelper(), false,
+ version_),
&crypto_config_));
return session_->CryptoConnect();
}
@@ -245,6 +245,10 @@ bool QuicClient::connected() const {
session_->connection()->connected();
}
+QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
+ return new QuicEpollConnectionHelper(fd_, &epoll_server_);
+}
+
bool QuicClient::ReadAndProcessPacket() {
// Allocate some extra space so we can send an error if the server goes over
// the limit.
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h
index 2b9b9e7..ca20a8d2 100644
--- a/net/tools/quic/quic_client.h
+++ b/net/tools/quic/quic_client.h
@@ -28,6 +28,8 @@ class ProofVerifier;
namespace tools {
+class QuicEpollConnectionHelper;
+
namespace test {
class QuicClientPeer;
} // namespace test
@@ -139,6 +141,9 @@ class QuicClient : public EpollCallbackInterface {
crypto_config_.SetChannelIDSigner(signer);
}
+ protected:
+ virtual QuicEpollConnectionHelper* CreateQuicConnectionHelper();
+
private:
friend class net::tools::test::QuicClientPeer;
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index bb248c2..1b1ece6 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -33,7 +33,6 @@ class ToolsQuicClientSessionTest : public ::testing::Test {
session_.reset(new QuicClientSession(kServerHostname, QuicConfig(),
connection_, &crypto_config_));
session_->config()->SetDefaults();
- session_->config()->set_max_streams_per_connection(1, 1);
}
void CompleteCryptoHandshake() {
@@ -56,7 +55,8 @@ TEST_F(ToolsQuicClientSessionTest, CryptoConnect) {
CompleteCryptoHandshake();
}
-TEST_F(ToolsQuicClientSessionTest, DISABLED_MaxNumConnections) {
+TEST_F(ToolsQuicClientSessionTest, MaxNumStreams) {
+ session_->config()->set_max_streams_per_connection(1, 1);
if (!Aes128Gcm12Encrypter::IsSupported()) {
LOG(INFO) << "AES GCM not supported. Test skipped.";
return;
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index d702b1d..68691f7 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -167,7 +167,8 @@ void QuicDispatcher::Shutdown() {
void QuicDispatcher::OnConnectionClose(QuicGuid guid, QuicErrorCode error) {
SessionMap::iterator it = session_map_.find(guid);
if (it == session_map_.end()) {
- LOG(DFATAL) << "GUID " << guid << " Does not exist in the session map.";
+ LOG(DFATAL) << "GUID " << guid << " does not exist in the session map. "
+ << "Error: " << QuicUtils::ErrorToString(error);
return;
}
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index 6b7bc15..059d833 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -218,7 +218,7 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) {
packet.rejected_sequence_number = 19191;
packet.nonce_proof = 132232;
scoped_ptr<QuicEncryptedPacket> encrypted(
- QuicFramer::ConstructPublicResetPacket(packet));
+ QuicFramer::BuildPublicResetPacket(packet));
EXPECT_CALL(*session1_, ConnectionClose(QUIC_PUBLIC_RESET, true)).Times(1)
.WillOnce(WithoutArgs(Invoke(
reinterpret_cast<MockServerConnection*>(session1_->connection()),
diff --git a/net/tools/quic/quic_epoll_connection_helper_test.cc b/net/tools/quic/quic_epoll_connection_helper_test.cc
index ac034fd7..0bfaee2 100644
--- a/net/tools/quic/quic_epoll_connection_helper_test.cc
+++ b/net/tools/quic/quic_epoll_connection_helper_test.cc
@@ -15,6 +15,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::GetMinStreamFrameSize;
using net::test::FramerVisitorCapturingFrames;
using net::test::MockSendAlgorithm;
using net::test::QuicConnectionPeer;
@@ -102,7 +103,7 @@ class QuicEpollConnectionHelperTest : public ::testing::Test {
QuicFrames frames;
QuicFrame frame(&frame1_);
frames.push_back(frame);
- return framer_.ConstructFrameDataPacket(header_, frames).packet;
+ return framer_.BuildUnsizedDataPacket(header_, frames).packet;
}
QuicGuid guid_;
@@ -128,7 +129,7 @@ TEST_F(QuicEpollConnectionHelperTest, DISABLED_TestRetransmission) {
const size_t packet_size =
GetPacketHeaderSize(PACKET_8BYTE_GUID, kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP) +
- QuicFramer::GetMinStreamFrameSize() + arraysize(buffer) - 1;
+ GetMinStreamFrameSize(framer_.version()) + arraysize(buffer) - 1;
EXPECT_CALL(*send_algorithm_,
SentPacket(_, 1, packet_size, NOT_RETRANSMISSION));
EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, packet_size));
diff --git a/net/tools/quic/quic_socket_utils.cc b/net/tools/quic/quic_socket_utils.cc
index ab66102..4d7d360 100644
--- a/net/tools/quic/quic_socket_utils.cc
+++ b/net/tools/quic/quic_socket_utils.cc
@@ -144,7 +144,7 @@ int QuicSocketUtils::WritePacket(int fd, const char* buffer, size_t buf_len,
hdr.msg_namelen = address_len;
hdr.msg_iov = &iov;
hdr.msg_iovlen = 1;
- hdr.msg_flags = 0;
+ hdr.msg_flags = 0;
const int kSpaceForIpv4 = CMSG_SPACE(sizeof(in_pktinfo));
const int kSpaceForIpv6 = CMSG_SPACE(sizeof(in6_pktinfo));
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc
index 7d5862a..fe538e9 100644
--- a/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -93,7 +93,7 @@ class QuicTimeWaitListManager::QueuedPacket {
QuicTimeWaitListManager::QuicTimeWaitListManager(
QuicPacketWriter* writer,
EpollServer* epoll_server)
- : framer_(QUIC_VERSION_6,
+ : framer_(QuicVersionMax(),
QuicTime::Zero(), // unused
true),
epoll_server_(epoll_server),
@@ -239,7 +239,7 @@ void QuicTimeWaitListManager::SendPublicReset(
QueuedPacket* queued_packet = new QueuedPacket(
server_address,
client_address,
- framer_.ConstructPublicResetPacket(packet));
+ framer_.BuildPublicResetPacket(packet));
// Takes ownership of the packet.
SendOrQueuePacket(queued_packet);
}
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index eb26078..03600f2 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -10,6 +10,7 @@
#include "net/cert/x509_certificate.h"
#include "net/quic/crypto/proof_verifier.h"
#include "net/tools/flip_server/balsa_headers.h"
+#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/test_tools/http_message_test_utils.h"
#include "url/gurl.h"
@@ -88,43 +89,81 @@ BalsaHeaders* MungeHeaders(const BalsaHeaders* const_headers,
return headers;
}
+// A quic client which allows mocking out writes.
+class QuicEpollClient : public QuicClient {
+ public:
+ typedef QuicClient Super;
+
+ QuicEpollClient(IPEndPoint server_address,
+ const string& server_hostname,
+ const QuicVersion version)
+ : Super(server_address, server_hostname, version) {
+ }
+
+ QuicEpollClient(IPEndPoint server_address,
+ const string& server_hostname,
+ const QuicConfig& config,
+ const QuicVersion version)
+ : Super(server_address, server_hostname, config, version) {
+ }
+
+ virtual ~QuicEpollClient() {
+ if (connected()) {
+ Disconnect();
+ }
+ }
+
+ virtual QuicEpollConnectionHelper* CreateQuicConnectionHelper() OVERRIDE {
+ if (writer_.get() != NULL) {
+ writer_->set_fd(fd());
+ return new QuicEpollConnectionHelper(writer_.get(), epoll_server());
+ } else {
+ return Super::CreateQuicConnectionHelper();
+ }
+ }
+
+ void UseWriter(QuicTestWriter* writer) { writer_.reset(writer); }
+
+ private:
+ scoped_ptr<QuicTestWriter> writer_;
+};
+
QuicTestClient::QuicTestClient(IPEndPoint address, const string& hostname,
const QuicVersion version)
- : client_(address, hostname, version) {
- Initialize(address, hostname);
+ : client_(new QuicEpollClient(address, hostname, version)) {
+ Initialize(address, hostname, true);
}
QuicTestClient::QuicTestClient(IPEndPoint address,
const string& hostname,
bool secure,
const QuicVersion version)
- : client_(address, hostname, version) {
- Initialize(address, hostname);
- secure_ = secure;
- // TODO(alyssar, agl) uncomment here and below when default certs are allowed.
- // ExpectCertificates(secure_);
+ : client_(new QuicEpollClient(address, hostname, version)) {
+ Initialize(address, hostname, secure);
}
QuicTestClient::QuicTestClient(IPEndPoint address,
const string& hostname,
+ bool secure,
const QuicConfig& config,
const QuicVersion version)
- : client_(address, hostname, config, version) {
- Initialize(address, hostname);
+ : client_(new QuicEpollClient(address, hostname, config, version)) {
+ Initialize(address, hostname, secure);
}
-void QuicTestClient::Initialize(IPEndPoint address, const string& hostname) {
+void QuicTestClient::Initialize(IPEndPoint address,
+ const string& hostname,
+ bool secure) {
server_address_ = address;
stream_ = NULL;
stream_error_ = QUIC_STREAM_NO_ERROR;
- connection_error_ = QUIC_NO_ERROR;
bytes_read_ = 0;
bytes_written_= 0;
never_connected_ = true;
- secure_ = true;
+ secure_ = secure;
auto_reconnect_ = false;
proof_verifier_ = NULL;
- // ExpectCertificates(secure_);
+ ExpectCertificates(secure_);
}
QuicTestClient::~QuicTestClient() {
@@ -136,10 +175,10 @@ QuicTestClient::~QuicTestClient() {
void QuicTestClient::ExpectCertificates(bool on) {
if (on) {
proof_verifier_ = new RecordingProofVerifier;
- client_.SetProofVerifier(proof_verifier_);
+ client_->SetProofVerifier(proof_verifier_);
} else {
proof_verifier_ = NULL;
- client_.SetProofVerifier(NULL);
+ client_->SetProofVerifier(NULL);
}
}
@@ -155,7 +194,7 @@ ssize_t QuicTestClient::SendMessage(const HTTPMessage& message) {
if (!connected()) {
GURL url(message.headers()->request_uri().as_string());
if (!url.host().empty()) {
- client_.set_server_hostname(url.host());
+ client_->set_server_hostname(url.host());
}
}
@@ -203,7 +242,7 @@ QuicReliableClientStream* QuicTestClient::GetOrCreateStream() {
}
}
if (!stream_) {
- stream_ = client_.CreateReliableClientStream();
+ stream_ = client_->CreateReliableClientStream();
if (stream_ != NULL) {
stream_->set_visitor(this);
}
@@ -217,7 +256,7 @@ const string& QuicTestClient::cert_common_name() const {
}
bool QuicTestClient::connected() const {
- return client_.connected();
+ return client_->connected();
}
void QuicTestClient::WaitForResponse() {
@@ -225,13 +264,13 @@ void QuicTestClient::WaitForResponse() {
// The client has likely disconnected.
return;
}
- client_.WaitForStreamToClose(stream_->id());
+ client_->WaitForStreamToClose(stream_->id());
}
void QuicTestClient::Connect() {
DCHECK(!connected());
- client_.Initialize();
- client_.Connect();
+ client_->Initialize();
+ client_->Connect();
never_connected_ = false;
}
@@ -241,16 +280,15 @@ void QuicTestClient::ResetConnection() {
}
void QuicTestClient::Disconnect() {
- client_.Disconnect();
+ client_->Disconnect();
}
IPEndPoint QuicTestClient::LocalSocketAddress() const {
- return client_.client_address();
+ return client_->client_address();
}
void QuicTestClient::ClearPerRequestState() {
stream_error_ = QUIC_STREAM_NO_ERROR;
- connection_error_ = QUIC_NO_ERROR;
stream_ = NULL;
response_ = "";
headers_.Clear();
@@ -261,7 +299,7 @@ void QuicTestClient::ClearPerRequestState() {
void QuicTestClient::WaitForInitialResponse() {
DCHECK(stream_ != NULL);
while (stream_ && stream_->stream_bytes_read() == 0) {
- client_.WaitForEvents();
+ client_->WaitForEvents();
}
}
@@ -288,12 +326,16 @@ void QuicTestClient::OnClose(ReliableQuicStream* stream) {
response_ = stream_->data();
headers_.CopyFrom(stream_->headers());
stream_error_ = stream_->stream_error();
- connection_error_ = stream_->connection_error();
bytes_read_ = stream_->stream_bytes_read();
bytes_written_ = stream_->stream_bytes_written();
stream_ = NULL;
}
+void QuicTestClient::UseWriter(QuicTestWriter* writer) {
+ DCHECK(!connected());
+ reinterpret_cast<QuicEpollClient*>(client_.get())->UseWriter(writer);
+}
+
} // namespace test
} // namespace tools
} // namespace net
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h
index 051c011..74bfc24 100644
--- a/net/tools/quic/test_tools/quic_test_client.h
+++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -8,10 +8,12 @@
#include <string>
#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_creator.h"
#include "net/quic/quic_protocol.h"
#include "net/tools/quic/quic_client.h"
+#include "net/tools/quic/quic_packet_writer.h"
namespace net {
@@ -21,6 +23,14 @@ namespace tools {
namespace test {
+// Allows setting a writer for the client's QuicConnectionHelper, to allow
+// fine-grained control of writes.
+class QuicTestWriter : public QuicPacketWriter {
+ public:
+ virtual ~QuicTestWriter() {}
+ virtual void set_fd(int fd) = 0;
+};
+
class HTTPMessage;
// A toy QUIC client used for testing.
@@ -34,6 +44,7 @@ class QuicTestClient : public ReliableQuicStream::Visitor {
const QuicVersion version);
QuicTestClient(IPEndPoint server_address,
const string& server_hostname,
+ bool secure,
const QuicConfig& config,
const QuicVersion version);
@@ -55,7 +66,7 @@ class QuicTestClient : public ReliableQuicStream::Visitor {
// Wraps data in a quic packet and sends it.
ssize_t SendData(string data, bool last_data);
- QuicPacketCreator::Options* options() { return client_.options(); }
+ QuicPacketCreator::Options* options() { return client_->options(); }
const BalsaHeaders *response_headers() const {return &headers_;}
@@ -75,15 +86,17 @@ class QuicTestClient : public ReliableQuicStream::Visitor {
// From ReliableQuicStream::Visitor
virtual void OnClose(ReliableQuicStream* stream) OVERRIDE;
- void SetNextStreamId(QuicStreamId id);
+ // Configures client_ to take ownership of and use the writer.
+ // Must be called before initial connect.
+ void UseWriter(QuicTestWriter* writer);
// Returns NULL if the maximum number of streams have already been created.
QuicReliableClientStream* GetOrCreateStream();
QuicRstStreamErrorCode stream_error() { return stream_error_; }
- QuicErrorCode connection_error() { return connection_error_; }
+ QuicErrorCode connection_error() { return client()->session()->error(); }
- QuicClient* client() { return &client_; }
+ QuicClient* client() { return client_.get(); }
// cert_common_name returns the common name value of the server's certificate,
// or the empty string if no certificate was presented.
@@ -95,15 +108,14 @@ class QuicTestClient : public ReliableQuicStream::Visitor {
void set_auto_reconnect(bool reconnect) { auto_reconnect_ = reconnect; }
private:
- void Initialize(IPEndPoint address, const string& hostname);
+ void Initialize(IPEndPoint address, const string& hostname, bool secure);
IPEndPoint server_address_;
IPEndPoint client_address_;
- QuicClient client_; // The actual client
+ scoped_ptr<QuicClient> client_; // The actual client
QuicReliableClientStream* stream_;
QuicRstStreamErrorCode stream_error_;
- QuicErrorCode connection_error_;
BalsaHeaders headers_;
string response_;