diff options
author | rtenneti <rtenneti@chromium.org> | 2014-08-25 20:43:43 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-08-26 03:45:04 +0000 |
commit | 4b06ae7cc281996b6a6e5989ef70a54ee3b4ed79 (patch) | |
tree | 5c8bb1f75a87850e8cf4ba89874c518fe45d9633 /net | |
parent | 139fb7ad98ee8af20d557ff78e52473ea36f3ab1 (diff) | |
download | chromium_src-4b06ae7cc281996b6a6e5989ef70a54ee3b4ed79.zip chromium_src-4b06ae7cc281996b6a6e5989ef70a54ee3b4ed79.tar.gz chromium_src-4b06ae7cc281996b6a6e5989ef70a54ee3b4ed79.tar.bz2 |
Change the wire format of the ack frame to include a compressed version
of the previous CongestionFeedback Timestamp frame.
Adds QUIC_VERSION_23. Deprecate CongestionFeedbackFrame
1 bytes - num_received_packets
First packet:
1 byte - distance from the largest observed in sequence number space.
4 bytes - mod of microseconds since the connection's creation when the
packet arrived. (1.1hrs in us)
Every other packet:
1 byte - distance from the largest observed in sequence number space.
2 bytes - mod of microseconds since the previous timestamp
Merge internal change: 73740829
The following are chromium specific changes:
+ Changed ACK frame not to send CongestionFeedback frame
+ Added received_packet_times to ACK frame.
+ The timestamp that is sent is relative to creation time, thus passed
MockClock's now() as argument to AckFrame and it is used to pass
QuicFramer's creation time and received_packet_times.
R=cyr@google.com, ianswett@google.com, rch@chromium.org
Review URL: https://codereview.chromium.org/478153003
Cr-Commit-Position: refs/heads/master@{#291830}
Diffstat (limited to 'net')
21 files changed, 1255 insertions, 150 deletions
diff --git a/net/quic/congestion_control/receive_algorithm_interface.cc b/net/quic/congestion_control/receive_algorithm_interface.cc index 91d29dc..812aa46 100644 --- a/net/quic/congestion_control/receive_algorithm_interface.cc +++ b/net/quic/congestion_control/receive_algorithm_interface.cc @@ -14,9 +14,6 @@ ReceiveAlgorithmInterface* ReceiveAlgorithmInterface::Create( switch (type) { case kTCP: return new TcpReceiver(); - case kTimestamp: - LOG(DFATAL) << "Timestamp congestion feedback is not supported"; - return NULL; } return NULL; } diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h index 30f9282..f791acb 100644 --- a/net/quic/crypto/crypto_protocol.h +++ b/net/quic/crypto/crypto_protocol.h @@ -49,7 +49,6 @@ const QuicTag kSRBF = TAG('S', 'R', 'B', 'F'); // Socket receive buffer // Congestion control feedback types const QuicTag kQBIC = TAG('Q', 'B', 'I', 'C'); // TCP cubic -const QuicTag kTSTP = TAG('T', 'S', 'T', 'P'); // Timestamp // Connection options (COPT) values const QuicTag kTBBR = TAG('T', 'B', 'B', 'R'); // Reduced Buffer Bloat TCP diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc index e2e0348..6cbd4ff 100644 --- a/net/quic/quic_config_test.cc +++ b/net/quic/quic_config_test.cc @@ -80,7 +80,6 @@ TEST_F(QuicConfigTest, ToHandshakeMessage) { TEST_F(QuicConfigTest, ProcessClientHello) { QuicConfig client_config; QuicTagVector cgst; - cgst.push_back(kTSTP); cgst.push_back(kQBIC); client_config.set_congestion_feedback(cgst, kQBIC); client_config.set_idle_connection_state_lifetime( @@ -256,7 +255,7 @@ TEST_F(QuicConfigTest, MultipleNegotiatedValuesInVectorTag) { QuicConfig server_config; QuicTagVector cgst; cgst.push_back(kQBIC); - cgst.push_back(kTSTP); + cgst.push_back(kTBBR); server_config.set_congestion_feedback(cgst, kQBIC); CryptoHandshakeMessage msg; @@ -271,8 +270,8 @@ TEST_F(QuicConfigTest, NoOverLapInCGST) { QuicConfig server_config; server_config.SetDefaults(); QuicTagVector cgst; - cgst.push_back(kTSTP); - server_config.set_congestion_feedback(cgst, kTSTP); + cgst.push_back(kTBBR); + server_config.set_congestion_feedback(cgst, kTBBR); CryptoHandshakeMessage msg; string error_details; diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index b100bb9..ab1e0fe 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -211,7 +211,7 @@ QuicConnection::QuicConnection(QuicConnectionId connection_id, largest_seen_packet_with_ack_(0), largest_seen_packet_with_stop_waiting_(0), pending_version_negotiation_packet_(false), - received_packet_manager_(kTCP, &stats_), + received_packet_manager_(&stats_), ack_queued_(false), stop_waiting_count_(0), ack_alarm_(helper->CreateAlarm(new AckAlarm(this))), @@ -269,7 +269,6 @@ QuicConnection::~QuicConnection() { void QuicConnection::SetFromConfig(const QuicConfig& config) { SetIdleNetworkTimeout(config.idle_connection_state_lifetime()); sent_packet_manager_.SetFromConfig(config); - // TODO(satyamshekhar): Set congestion control and ICSL also. } bool QuicConnection::SelectMutualVersion( @@ -1574,15 +1573,16 @@ void QuicConnection::SendPing() { void QuicConnection::SendAck() { ack_alarm_->Cancel(); stop_waiting_count_ = 0; - // TODO(rch): delay this until the CreateFeedbackFrame - // method is invoked. This requires changes SetShouldSendAck - // to be a no-arg method, and re-jiggering its implementation. bool send_feedback = false; - if (received_packet_manager_.GenerateCongestionFeedback( - &outgoing_congestion_feedback_)) { - DVLOG(1) << ENDPOINT << "Sending feedback: " - << outgoing_congestion_feedback_; - send_feedback = true; + + // Deprecating the Congestion Feedback Frame after QUIC_VERSION_22. + if (version() <= QUIC_VERSION_22) { + if (received_packet_manager_.GenerateCongestionFeedback( + &outgoing_congestion_feedback_)) { + DVLOG(1) << ENDPOINT << "Sending feedback: " + << outgoing_congestion_feedback_; + send_feedback = true; + } } packet_generator_.SetShouldSendAck(send_feedback, true); diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc index b313ae6..8157848 100644 --- a/net/quic/quic_connection_logger.cc +++ b/net/quic/quic_connection_logger.cc @@ -122,19 +122,6 @@ base::Value* NetLogQuicCongestionFeedbackFrameCallback( NetLog::LogLevel /* log_level */) { base::DictionaryValue* dict = new base::DictionaryValue(); switch (frame->type) { - case kTimestamp: { - dict->SetString("type", "Timestamp"); - base::ListValue* received = new base::ListValue(); - dict->Set("received_packets", received); - for (TimeMap::const_iterator it = - frame->timestamp.received_packet_times.begin(); - it != frame->timestamp.received_packet_times.end(); ++it) { - string value = base::Uint64ToString(it->first) + "@" + - base::Uint64ToString(it->second.ToDebuggingValue()); - received->AppendString(value); - } - break; - } case kTCP: dict->SetString("type", "TCP"); dict->SetInteger("receive_window", frame->tcp.receive_window); diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index 1e036f3..5befba7 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -2568,11 +2568,20 @@ TEST_P(QuicConnectionTest, WithQuicCongestionFeedbackFrame) { QuicCongestionFeedbackFrame info; info.type = kTCP; info.tcp.receive_window = 0x4030; - SetFeedback(&info); - SendAckPacketToPeer(); - ASSERT_FALSE(writer_->feedback_frames().empty()); - ASSERT_EQ(kTCP, writer_->feedback_frames()[0].type); + // After QUIC_VERSION_22, do not send TCP Congestion Feedback Frames anymore. + if (version() > QUIC_VERSION_22) { + SendAckPacketToPeer(); + ASSERT_TRUE(writer_->feedback_frames().empty()); + } else { + // Only SetFeedback in this case because SetFeedback will create a receive + // algorithm which is how the received_packet_manager checks if it should be + // creating TCP Congestion Feedback Frames. + SetFeedback(&info); + SendAckPacketToPeer(); + ASSERT_FALSE(writer_->feedback_frames().empty()); + ASSERT_EQ(kTCP, writer_->feedback_frames()[0].type); + } } TEST_P(QuicConnectionTest, UpdateQuicCongestionFeedbackFrame) { diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index fe70501..84c6b30 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc @@ -132,16 +132,6 @@ QuicSequenceNumberLength ReadSequenceNumberLength(uint8 flags) { } } -bool CanTruncate(const QuicFrame& frame, size_t free_bytes) { - if ((frame.type == ACK_FRAME || frame.type == CONNECTION_CLOSE_FRAME) && - free_bytes >= - QuicFramer::GetMinAckFrameSize(PACKET_6BYTE_SEQUENCE_NUMBER, - PACKET_6BYTE_SEQUENCE_NUMBER)) { - return true; - } - return false; -} - } // namespace bool QuicFramerVisitorInterface::OnWindowUpdateFrame( @@ -168,7 +158,8 @@ QuicFramer::QuicFramer(const QuicVersionVector& supported_versions, alternative_decrypter_latch_(false), is_server_(is_server), validate_flags_(true), - creation_time_(creation_time) { + creation_time_(creation_time), + last_timestamp_(QuicTime::Delta::Zero()) { DCHECK(!supported_versions.empty()); quic_version_ = supported_versions_[0]; decrypter_.reset(QuicDecrypter::Create(kNULL)); @@ -302,7 +293,10 @@ size_t QuicFramer::GetSerializedFrameLength( if (!first_frame) { return 0; } - if (CanTruncate(frame, free_bytes)) { + bool can_truncate = frame.type == ACK_FRAME && + free_bytes >= GetMinAckFrameSize(PACKET_6BYTE_SEQUENCE_NUMBER, + PACKET_6BYTE_SEQUENCE_NUMBER); + if (can_truncate) { // Truncate the frame so the packet will not exceed kMaxPacketSize. // Note that we may not use every byte of the writer in this case. DVLOG(1) << "Truncating large frame, free bytes: " << free_bytes; @@ -807,6 +801,30 @@ bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header, return true; } +const QuicTime::Delta QuicFramer::CalculateTimestampFromWire( + uint32 time_delta_us) { + // The new time_delta might have wrapped to the next epoch, or it + // might have reverse wrapped to the previous epoch, or it might + // remain in the same epoch. Select the time closest to the previous + // time. + // + // epoch_delta is the delta between epochs. A delta is 4 bytes of + // microseconds. + const uint64 epoch_delta = GG_UINT64_C(1) << 32; + uint64 epoch = last_timestamp_.ToMicroseconds() & ~(epoch_delta - 1); + // Wrapping is safe here because a wrapped value will not be ClosestTo below. + uint64 prev_epoch = epoch - epoch_delta; + uint64 next_epoch = epoch + epoch_delta; + + uint64 time = ClosestTo(last_timestamp_.ToMicroseconds(), + epoch + time_delta_us, + ClosestTo(last_timestamp_.ToMicroseconds(), + prev_epoch + time_delta_us, + next_epoch + time_delta_us)); + + return QuicTime::Delta::FromMicroseconds(time); +} + QuicPacketSequenceNumber QuicFramer::CalculatePacketSequenceNumberFromWire( QuicSequenceNumberLength sequence_number_length, QuicPacketSequenceNumber packet_sequence_number) const { @@ -1110,8 +1128,12 @@ bool QuicFramer::ProcessFrameData(const QuicPacketHeader& header) { // Congestion Feedback Frame if (frame_type & kQuicFrameTypeCongestionFeedbackMask) { + if (quic_version_ > QUIC_VERSION_22) { + set_detailed_error("Congestion Feedback Frame has been deprecated."); + DLOG(WARNING) << "Congestion Feedback Frame has been deprecated."; + } QuicCongestionFeedbackFrame frame; - if (!ProcessQuicCongestionFeedbackFrame(&frame)) { + if (!ProcessCongestionFeedbackFrame(&frame)) { return RaiseError(QUIC_INVALID_CONGESTION_FEEDBACK_DATA); } if (!visitor_->OnCongestionFeedbackFrame(frame)) { @@ -1333,6 +1355,10 @@ bool QuicFramer::ProcessAckFrame(uint8 frame_type, QuicAckFrame* ack_frame) { QuicTime::Delta::FromMicroseconds(delta_time_largest_observed_us); } + if (!ProcessTimestampsInAckFrame(ack_frame)) { + return false; + } + if (!has_nacks) { return true; } @@ -1386,6 +1412,64 @@ bool QuicFramer::ProcessAckFrame(uint8 frame_type, QuicAckFrame* ack_frame) { return true; } +bool QuicFramer::ProcessTimestampsInAckFrame(QuicAckFrame* ack_frame) { + if (version() > QUIC_VERSION_22 && !ack_frame->is_truncated) { + uint8 num_received_packets; + if (!reader_->ReadBytes(&num_received_packets, 1)) { + set_detailed_error("Unable to read num received packets."); + return false; + } + + if (num_received_packets > 0) { + uint8 delta_from_largest_observed; + if (!reader_->ReadBytes(&delta_from_largest_observed, + PACKET_1BYTE_SEQUENCE_NUMBER)) { + set_detailed_error( + "Unable to read sequence delta in received packets."); + return false; + } + QuicPacketSequenceNumber seq_num = ack_frame->largest_observed - + delta_from_largest_observed; + + // Time delta from the framer creation. + uint32 time_delta_us; + if (!reader_->ReadBytes(&time_delta_us, sizeof(time_delta_us))) { + set_detailed_error("Unable to read time delta in received packets."); + return false; + } + + last_timestamp_ = CalculateTimestampFromWire(time_delta_us); + + ack_frame->received_packet_times.push_back( + make_pair(seq_num, creation_time_.Add(last_timestamp_))); + + for (uint8 i = 1; i < num_received_packets; ++i) { + if (!reader_->ReadBytes(&delta_from_largest_observed, + PACKET_1BYTE_SEQUENCE_NUMBER)) { + set_detailed_error( + "Unable to read sequence delta in received packets."); + return false; + } + seq_num = ack_frame->largest_observed - delta_from_largest_observed; + + // Time delta from the previous timestamp. + uint64 incremental_time_delta_us; + if (!reader_->ReadUFloat16(&incremental_time_delta_us)) { + set_detailed_error( + "Unable to read incremental time delta in received packets."); + return false; + } + + last_timestamp_ = last_timestamp_.Add( + QuicTime::Delta::FromMicroseconds(incremental_time_delta_us)); + ack_frame->received_packet_times.push_back( + make_pair(seq_num, creation_time_.Add(last_timestamp_))); + } + } + } + return true; +} + bool QuicFramer::ProcessStopWaitingFrame(const QuicPacketHeader& header, QuicStopWaitingFrame* stop_waiting) { if (!reader_->ReadBytes(&stop_waiting->entropy_hash, 1)) { @@ -1406,7 +1490,7 @@ bool QuicFramer::ProcessStopWaitingFrame(const QuicPacketHeader& header, return true; } -bool QuicFramer::ProcessQuicCongestionFeedbackFrame( +bool QuicFramer::ProcessCongestionFeedbackFrame( QuicCongestionFeedbackFrame* frame) { uint8 feedback_type; if (!reader_->ReadBytes(&feedback_type, 1)) { @@ -1417,10 +1501,6 @@ bool QuicFramer::ProcessQuicCongestionFeedbackFrame( static_cast<CongestionFeedbackType>(feedback_type); switch (frame->type) { - case kTimestamp: { - set_detailed_error("Timestamp feedback not supported."); - return false; - } case kTCP: { CongestionFeedbackMessageTCP* tcp = &frame->tcp; uint16 receive_window = 0; @@ -1716,6 +1796,24 @@ size_t QuicFramer::GetAckFrameSize( ack_size += min(ack.revived_packets.size(), kMaxRevivedPackets) * largest_observed_length; } + + // In version 23, if the ack will be truncated due to too many nack ranges, + // then do not include the number of timestamps (1 byte). + if (version() > QUIC_VERSION_22 && + ack_info.nack_ranges.size() <= kMaxNackRanges) { + // 1 byte for the number of timestamps. + ack_size += 1; + if (ack.received_packet_times.size() > 0) { + // 1 byte for sequence number, 4 bytes for timestamp for the first + // packet. + ack_size += 5; + + // 1 byte for sequence number, 2 bytes for timestamp for the other + // packets. + ack_size += 3 * (ack.received_packet_times.size() - 1); + } + } + return ack_size; } @@ -1741,10 +1839,6 @@ size_t QuicFramer::ComputeFrameLength( len += 1; // Congestion feedback type. switch (congestion_feedback.type) { - case kTimestamp: { - set_detailed_error("Timestamp feedback not supported."); - break; - } case kTCP: len += 2; // Receive window. break; @@ -1977,6 +2071,13 @@ bool QuicFramer::AppendAckFrameAndTypeByte( return false; } + // Timestamp goes at the end of the required fields. + if (version() > QUIC_VERSION_22 && !truncated) { + if (!AppendTimestampToAckFrame(frame, writer)) { + return false; + } + } + if (ack_info.nack_ranges.empty()) { return true; } @@ -2038,10 +2139,6 @@ bool QuicFramer::AppendCongestionFeedbackFrame( } switch (frame.type) { - case kTimestamp: { - // Timestamp feedback not supported. - return false; - } case kTCP: { const CongestionFeedbackMessageTCP& tcp = frame.tcp; DCHECK_LE(tcp.receive_window, 1u << 20); @@ -2059,6 +2156,72 @@ bool QuicFramer::AppendCongestionFeedbackFrame( return true; } +bool QuicFramer::AppendTimestampToAckFrame(const QuicAckFrame& frame, + QuicDataWriter* writer) { + DCHECK_GE(version(), QUIC_VERSION_23); + DCHECK_GE(numeric_limits<uint8>::max(), frame.received_packet_times.size()); + // num_received_packets is only 1 byte. + if (frame.received_packet_times.size() > numeric_limits<uint8>::max()) { + return false; + } + + uint8 num_received_packets = frame.received_packet_times.size(); + + if (!writer->WriteBytes(&num_received_packets, 1)) { + return false; + } + if (num_received_packets == 0) { + return true; + } + + PacketTimeList::const_iterator it = frame.received_packet_times.begin(); + QuicPacketSequenceNumber sequence_number = it->first; + QuicPacketSequenceNumber delta_from_largest_observed = + frame.largest_observed - sequence_number; + + DCHECK_GE(numeric_limits<uint8>::max(), delta_from_largest_observed); + if (delta_from_largest_observed > numeric_limits<uint8>::max()) { + return false; + } + + if (!writer->WriteUInt8( + delta_from_largest_observed & k1ByteSequenceNumberMask)) { + return false; + } + + // Use the lowest 4 bytes of the time delta from the creation_time_. + const uint64 time_epoch_delta_us = GG_UINT64_C(1) << 32; + uint32 time_delta_us = + static_cast<uint32>(it->second.Subtract(creation_time_).ToMicroseconds() + & (time_epoch_delta_us - 1)); + if (!writer->WriteBytes(&time_delta_us, sizeof(time_delta_us))) { + return false; + } + + QuicTime prev_time = it->second; + + for (++it; it != frame.received_packet_times.end(); ++it) { + sequence_number = it->first; + delta_from_largest_observed = frame.largest_observed - sequence_number; + + if (delta_from_largest_observed > numeric_limits<uint8>::max()) { + return false; + } + + if (!writer->WriteUInt8( + delta_from_largest_observed & k1ByteSequenceNumberMask)) { + return false; + } + + uint64 time_delta_us = it->second.Subtract(prev_time).ToMicroseconds(); + prev_time = it->second; + if (!writer->WriteUFloat16(time_delta_us)) { + return false; + } + } + return true; +} + bool QuicFramer::AppendStopWaitingFrame( const QuicPacketHeader& header, const QuicStopWaitingFrame& frame, diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h index a958786..3489803 100644 --- a/net/quic/quic_framer.h +++ b/net/quic/quic_framer.h @@ -45,6 +45,8 @@ const size_t kQuicEntropyHashSize = 1; // Size in bytes reserved for the delta time of the largest observed // sequence number in ack frames. const size_t kQuicDeltaTimeLargestObservedSize = 2; +// Size in bytes reserved for the number of received packets with timestamps. +const size_t kQuicNumTimestampsSize = 1; // Size in bytes reserved for the number of missing packets in ack frames. const size_t kNumberOfNackRangesSize = 1; // Maximum number of missing packet ranges that can fit within an ack frame. @@ -409,9 +411,10 @@ class NET_EXPORT_PRIVATE QuicFramer { bool ProcessFrameData(const QuicPacketHeader& header); bool ProcessStreamFrame(uint8 frame_type, QuicStreamFrame* frame); bool ProcessAckFrame(uint8 frame_type, QuicAckFrame* frame); + bool ProcessTimestampsInAckFrame(QuicAckFrame* frame); bool ProcessStopWaitingFrame(const QuicPacketHeader& public_header, QuicStopWaitingFrame* stop_waiting); - bool ProcessQuicCongestionFeedbackFrame( + bool ProcessCongestionFeedbackFrame( QuicCongestionFeedbackFrame* congestion_feedback); bool ProcessRstStreamFrame(QuicRstStreamFrame* frame); bool ProcessConnectionCloseFrame(QuicConnectionCloseFrame* frame); @@ -428,6 +431,10 @@ class NET_EXPORT_PRIVATE QuicFramer { QuicSequenceNumberLength sequence_number_length, QuicPacketSequenceNumber packet_sequence_number) const; + // Returns the QuicTime::Delta corresponding to the time from when the framer + // was created. + const QuicTime::Delta CalculateTimestampFromWire(uint32 time_delta_us); + // Computes the wire size in bytes of the |ack| frame, assuming no truncation. size_t GetAckFrameSize(const QuicAckFrame& ack, QuicSequenceNumberLength sequence_number_length); @@ -463,6 +470,8 @@ class NET_EXPORT_PRIVATE QuicFramer { QuicDataWriter* builder); bool AppendCongestionFeedbackFrame(const QuicCongestionFeedbackFrame& frame, QuicDataWriter* builder); + bool AppendTimestampToAckFrame(const QuicAckFrame& frame, + QuicDataWriter* builder); bool AppendStopWaitingFrame(const QuicPacketHeader& header, const QuicStopWaitingFrame& frame, QuicDataWriter* builder); @@ -527,6 +536,9 @@ class NET_EXPORT_PRIVATE QuicFramer { // The time this framer was created. Time written to the wire will be // written as a delta from this value. QuicTime creation_time_; + // The time delta computed for the last timestamp frame. This is relative to + // the creation_time. + QuicTime::Delta last_timestamp_; DISALLOW_COPY_AND_ASSIGN(QuicFramer); }; diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index d14e673..2c3d274 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc @@ -460,7 +460,7 @@ class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> { void CheckStreamFrameBoundaries(unsigned char* packet, size_t stream_id_size, bool include_version) { - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = kQuicFrameTypeSize; i < GetMinStreamFrameSize(); ++i) { string expected_error; if (i < kQuicFrameTypeSize + stream_id_size) { @@ -682,7 +682,7 @@ TEST_P(QuicFramerTest, PacketHeader) { EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); EXPECT_EQ(0x00u, visitor_.header_->fec_group); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); @@ -735,7 +735,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith4ByteConnectionId) { EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); EXPECT_EQ(0x00u, visitor_.header_->fec_group); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_4BYTE_CONNECTION_ID, !kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); @@ -791,7 +791,7 @@ TEST_P(QuicFramerTest, PacketHeader1ByteConnectionId) { EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); EXPECT_EQ(0x00u, visitor_.header_->fec_group); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_1BYTE_CONNECTION_ID, !kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); @@ -846,7 +846,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) { EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); EXPECT_EQ(0x00u, visitor_.header_->fec_group); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); @@ -903,7 +903,7 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) { EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); EXPECT_EQ(0x00u, visitor_.header_->fec_group); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); @@ -958,7 +958,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith4ByteSequenceNumber) { EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); EXPECT_EQ(0x00u, visitor_.header_->fec_group); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, PACKET_4BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); @@ -1013,7 +1013,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith2ByteSequenceNumber) { EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); EXPECT_EQ(0x00u, visitor_.header_->fec_group); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, PACKET_2BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); @@ -1068,7 +1068,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith1ByteSequenceNumber) { EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); EXPECT_EQ(0x00u, visitor_.header_->fec_group); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); @@ -1307,7 +1307,7 @@ TEST_P(QuicFramerTest, StreamFrame) { visitor_.stream_frames_[0]->offset); CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); - // Now test framing boundaries + // Now test framing boundaries. CheckStreamFrameBoundaries(packet, kQuicMaxStreamIdSize, !kIncludeVersion); } @@ -1355,7 +1355,7 @@ TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) { visitor_.stream_frames_[0]->offset); CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); - // Now test framing boundaries + // Now test framing boundaries. const size_t stream_id_size = 3; CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion); } @@ -1404,7 +1404,7 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) { visitor_.stream_frames_[0]->offset); CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); - // Now test framing boundaries + // Now test framing boundaries. const size_t stream_id_size = 2; CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion); } @@ -1453,7 +1453,7 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) { visitor_.stream_frames_[0]->offset); CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); - // Now test framing boundaries + // Now test framing boundaries. const size_t stream_id_size = 1; CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion); } @@ -1506,7 +1506,7 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) { visitor_.stream_frames_[0]->offset); CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); - // Now test framing boundaries + // Now test framing boundaries. CheckStreamFrameBoundaries(packet, kQuicMaxStreamIdSize, kIncludeVersion); } @@ -1682,7 +1682,10 @@ TEST_P(QuicFramerTest, StreamFrameInFecGroup) { CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); } -TEST_P(QuicFramerTest, AckFrame) { +TEST_P(QuicFramerTest, AckFramev22) { + if (version_ > QUIC_VERSION_22) { + return; + } unsigned char packet[] = { // public flags (8 byte connection_id) 0x3C, @@ -1745,7 +1748,123 @@ TEST_P(QuicFramerTest, AckFrame) { PACKET_1BYTE_SEQUENCE_NUMBER; const size_t kRevivedPacketsLength = kMissingPacketsRange + PACKET_1BYTE_SEQUENCE_NUMBER; - // Now test framing boundaries + // Now test framing boundaries. + const size_t ack_frame_size = kRevivedPacketsLength + + PACKET_1BYTE_SEQUENCE_NUMBER; + for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) { + string expected_error; + if (i < kLargestObservedOffset) { + expected_error = "Unable to read entropy hash for received packets."; + } else if (i < kMissingDeltaTimeOffset) { + expected_error = "Unable to read largest observed."; + } else if (i < kNumMissingPacketOffset) { + expected_error = "Unable to read delta time largest observed."; + } else if (i < kMissingPacketsOffset) { + expected_error = "Unable to read num missing packet ranges."; + } else if (i < kMissingPacketsRange) { + expected_error = "Unable to read missing sequence number delta."; + } else if (i < kRevivedPacketsLength) { + expected_error = "Unable to read missing sequence number range."; + } else { + expected_error = "Unable to read num revived packets."; + } + CheckProcessingFails( + packet, + i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP), + expected_error, QUIC_INVALID_ACK_DATA); + } +} + + +TEST_P(QuicFramerTest, AckFrameTwoTimestamp) { + if (version_ <= QUIC_VERSION_22) { + return; + } + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet sequence number + 0xA8, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, not truncated, 6 byte largest observed, 1 byte delta) + 0x6C, + // entropy hash of all received packets. + 0xBA, + // largest observed packet sequence number + 0xBF, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // Zero delta time. + 0x0, 0x0, + // Number of timestamps. + 0x02, + // Delta from largest observed. + 0x01, + // Delta time. + 0x10, 0x32, 0x54, 0x76, + // Delta from largest observed. + 0x02, + // Delta time. + 0x10, 0x32, + // num missing packets + 0x01, + // missing packet delta + 0x01, + // 0 more missing packets in range. + 0x00, + // Number of revived packets. + 0x00, + }; + + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); + + EXPECT_EQ(0u, visitor_.stream_frames_.size()); + ASSERT_EQ(1u, visitor_.ack_frames_.size()); + const QuicAckFrame& frame = *visitor_.ack_frames_[0]; + EXPECT_EQ(0xBA, frame.entropy_hash); + EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed); + ASSERT_EQ(1u, frame.missing_packets.size()); + ASSERT_EQ(2u, frame.received_packet_times.size()); + SequenceNumberSet::const_iterator missing_iter = + frame.missing_packets.begin(); + EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter); + + const size_t kReceivedEntropyOffset = kQuicFrameTypeSize; + const size_t kLargestObservedOffset = kReceivedEntropyOffset + + kQuicEntropyHashSize; + const size_t kMissingDeltaTimeOffset = kLargestObservedOffset + + PACKET_6BYTE_SEQUENCE_NUMBER; + const size_t kNumTimestampsOffset = kMissingDeltaTimeOffset + + kQuicDeltaTimeLargestObservedSize; + const size_t kTimestampDeltaLargestObserved1 = kNumTimestampsOffset + + kQuicNumTimestampsSize; + const size_t kTimestampTimeDeltaLargestObserved1 = + kTimestampDeltaLargestObserved1 + 1; + const size_t kTimestampDeltaLargestObserved2 = + kTimestampTimeDeltaLargestObserved1 + 4; + const size_t kTimestampTimeDeltaLargestObserved2 = + kTimestampDeltaLargestObserved2 + 1; + const size_t kNumMissingPacketOffset = + kTimestampTimeDeltaLargestObserved2 + 2; + const size_t kMissingPacketsOffset = kNumMissingPacketOffset + + kNumberOfNackRangesSize; + const size_t kMissingPacketsRange = kMissingPacketsOffset + + PACKET_1BYTE_SEQUENCE_NUMBER; + const size_t kRevivedPacketsLength = kMissingPacketsRange + + PACKET_1BYTE_SEQUENCE_NUMBER; + // Now test framing boundaries. const size_t ack_frame_size = kRevivedPacketsLength + PACKET_1BYTE_SEQUENCE_NUMBER; for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) { @@ -1754,8 +1873,233 @@ TEST_P(QuicFramerTest, AckFrame) { expected_error = "Unable to read entropy hash for received packets."; } else if (i < kMissingDeltaTimeOffset) { expected_error = "Unable to read largest observed."; + } else if (i < kNumTimestampsOffset) { + expected_error = "Unable to read delta time largest observed."; + } else if (i < kTimestampDeltaLargestObserved1) { + expected_error = "Unable to read num received packets."; + } else if (i < kTimestampTimeDeltaLargestObserved1) { + expected_error = "Unable to read sequence delta in received packets."; + } else if (i < kTimestampDeltaLargestObserved2) { + expected_error = "Unable to read time delta in received packets."; + } else if (i < kTimestampTimeDeltaLargestObserved2) { + expected_error = "Unable to read sequence delta in received packets."; } else if (i < kNumMissingPacketOffset) { + expected_error = + "Unable to read incremental time delta in received packets."; + } else if (i < kMissingPacketsOffset) { + expected_error = "Unable to read num missing packet ranges."; + } else if (i < kMissingPacketsRange) { + expected_error = "Unable to read missing sequence number delta."; + } else if (i < kRevivedPacketsLength) { + expected_error = "Unable to read missing sequence number range."; + } else { + expected_error = "Unable to read num revived packets."; + } + CheckProcessingFails( + packet, + i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP), + expected_error, QUIC_INVALID_ACK_DATA); + } +} + + +TEST_P(QuicFramerTest, AckFrameOneTimestamp) { + if (version_ <= QUIC_VERSION_22) { + return; + } + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet sequence number + 0xA8, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, not truncated, 6 byte largest observed, 1 byte delta) + 0x6C, + // entropy hash of all received packets. + 0xBA, + // largest observed packet sequence number + 0xBF, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // Zero delta time. + 0x0, 0x0, + // Number of timestamps. + 0x01, + // Delta from largest observed. + 0x01, + // Delta time. + 0x10, 0x32, 0x54, 0x76, + // num missing packets + 0x01, + // missing packet delta + 0x01, + // 0 more missing packets in range. + 0x00, + // Number of revived packets. + 0x00, + }; + + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); + + EXPECT_EQ(0u, visitor_.stream_frames_.size()); + ASSERT_EQ(1u, visitor_.ack_frames_.size()); + const QuicAckFrame& frame = *visitor_.ack_frames_[0]; + EXPECT_EQ(0xBA, frame.entropy_hash); + EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed); + ASSERT_EQ(1u, frame.missing_packets.size()); + ASSERT_EQ(1u, frame.received_packet_times.size()); + SequenceNumberSet::const_iterator missing_iter = + frame.missing_packets.begin(); + EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter); + + const size_t kReceivedEntropyOffset = kQuicFrameTypeSize; + const size_t kLargestObservedOffset = kReceivedEntropyOffset + + kQuicEntropyHashSize; + const size_t kMissingDeltaTimeOffset = kLargestObservedOffset + + PACKET_6BYTE_SEQUENCE_NUMBER; + const size_t kNumTimestampsOffset = kMissingDeltaTimeOffset + + kQuicDeltaTimeLargestObservedSize; + const size_t kTimestampDeltaLargestObserved = kNumTimestampsOffset + + kQuicNumTimestampsSize; + const size_t kTimestampTimeDeltaLargestObserved = + kTimestampDeltaLargestObserved + 1; + const size_t kNumMissingPacketOffset = kTimestampTimeDeltaLargestObserved + 4; + const size_t kMissingPacketsOffset = kNumMissingPacketOffset + + kNumberOfNackRangesSize; + const size_t kMissingPacketsRange = kMissingPacketsOffset + + PACKET_1BYTE_SEQUENCE_NUMBER; + const size_t kRevivedPacketsLength = kMissingPacketsRange + + PACKET_1BYTE_SEQUENCE_NUMBER; + // Now test framing boundaries. + const size_t ack_frame_size = kRevivedPacketsLength + + PACKET_1BYTE_SEQUENCE_NUMBER; + for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) { + string expected_error; + if (i < kLargestObservedOffset) { + expected_error = "Unable to read entropy hash for received packets."; + } else if (i < kMissingDeltaTimeOffset) { + expected_error = "Unable to read largest observed."; + } else if (i < kNumTimestampsOffset) { + expected_error = "Unable to read delta time largest observed."; + } else if (i < kTimestampDeltaLargestObserved) { + expected_error = "Unable to read num received packets."; + } else if (i < kTimestampTimeDeltaLargestObserved) { + expected_error = "Unable to read sequence delta in received packets."; + } else if (i < kNumMissingPacketOffset) { + expected_error = "Unable to read time delta in received packets."; + } else if (i < kMissingPacketsOffset) { + expected_error = "Unable to read num missing packet ranges."; + } else if (i < kMissingPacketsRange) { + expected_error = "Unable to read missing sequence number delta."; + } else if (i < kRevivedPacketsLength) { + expected_error = "Unable to read missing sequence number range."; + } else { + expected_error = "Unable to read num revived packets."; + } + CheckProcessingFails( + packet, + i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP), + expected_error, QUIC_INVALID_ACK_DATA); + } +} + + +TEST_P(QuicFramerTest, AckFrame) { + if (version_ <= QUIC_VERSION_22) { + return; + } + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet sequence number + 0xA8, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, not truncated, 6 byte largest observed, 1 byte delta) + 0x6C, + // entropy hash of all received packets. + 0xBA, + // largest observed packet sequence number + 0xBF, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // Zero delta time. + 0x0, 0x0, + // Number of timestamps. + 0x00, + // num missing packets + 0x01, + // missing packet delta + 0x01, + // 0 more missing packets in range. + 0x00, + // Number of revived packets. + 0x00, + }; + + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); + + EXPECT_EQ(0u, visitor_.stream_frames_.size()); + ASSERT_EQ(1u, visitor_.ack_frames_.size()); + const QuicAckFrame& frame = *visitor_.ack_frames_[0]; + EXPECT_EQ(0xBA, frame.entropy_hash); + EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed); + ASSERT_EQ(1u, frame.missing_packets.size()); + SequenceNumberSet::const_iterator missing_iter = + frame.missing_packets.begin(); + EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter); + + const size_t kReceivedEntropyOffset = kQuicFrameTypeSize; + const size_t kLargestObservedOffset = kReceivedEntropyOffset + + kQuicEntropyHashSize; + const size_t kMissingDeltaTimeOffset = kLargestObservedOffset + + PACKET_6BYTE_SEQUENCE_NUMBER; + const size_t kNumTimestampsOffset = kMissingDeltaTimeOffset + + kQuicDeltaTimeLargestObservedSize; + const size_t kNumMissingPacketOffset = kNumTimestampsOffset + + kQuicNumTimestampsSize; + const size_t kMissingPacketsOffset = kNumMissingPacketOffset + + kNumberOfNackRangesSize; + const size_t kMissingPacketsRange = kMissingPacketsOffset + + PACKET_1BYTE_SEQUENCE_NUMBER; + const size_t kRevivedPacketsLength = kMissingPacketsRange + + PACKET_1BYTE_SEQUENCE_NUMBER; + // Now test framing boundaries. + const size_t ack_frame_size = kRevivedPacketsLength + + PACKET_1BYTE_SEQUENCE_NUMBER; + for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) { + string expected_error; + if (i < kLargestObservedOffset) { + expected_error = "Unable to read entropy hash for received packets."; + } else if (i < kMissingDeltaTimeOffset) { + expected_error = "Unable to read largest observed."; + } else if (i < kNumTimestampsOffset) { expected_error = "Unable to read delta time largest observed."; + } else if (i < kNumMissingPacketOffset) { + expected_error = "Unable to read num received packets."; } else if (i < kMissingPacketsOffset) { expected_error = "Unable to read num missing packet ranges."; } else if (i < kMissingPacketsRange) { @@ -1774,6 +2118,9 @@ TEST_P(QuicFramerTest, AckFrame) { } TEST_P(QuicFramerTest, AckFrameRevivedPackets) { + if (version_ <= QUIC_VERSION_22) { + return; + } unsigned char packet[] = { // public flags (8 byte connection_id) 0x3C, @@ -1796,6 +2143,8 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) { 0x34, 0x12, // Zero delta time. 0x0, 0x0, + // num received packets. + 0x00, // num missing packets 0x01, // missing packet delta @@ -1807,6 +2156,117 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) { // Revived packet sequence number. 0xBE, 0x9A, 0x78, 0x56, 0x34, 0x12, + // Number of revived packets. + 0x00, + }; + + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); + + EXPECT_EQ(0u, visitor_.stream_frames_.size()); + ASSERT_EQ(1u, visitor_.ack_frames_.size()); + const QuicAckFrame& frame = *visitor_.ack_frames_[0]; + EXPECT_EQ(0xBA, frame.entropy_hash); + EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame.largest_observed); + ASSERT_EQ(1u, frame.missing_packets.size()); + SequenceNumberSet::const_iterator missing_iter = + frame.missing_packets.begin(); + EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter); + + const size_t kReceivedEntropyOffset = kQuicFrameTypeSize; + const size_t kLargestObservedOffset = kReceivedEntropyOffset + + kQuicEntropyHashSize; + const size_t kMissingDeltaTimeOffset = kLargestObservedOffset + + PACKET_6BYTE_SEQUENCE_NUMBER; + const size_t kNumTimestampsOffset = kMissingDeltaTimeOffset + + kQuicDeltaTimeLargestObservedSize; + const size_t kNumMissingPacketOffset = kNumTimestampsOffset + + kQuicNumTimestampsSize; + const size_t kMissingPacketsOffset = kNumMissingPacketOffset + + kNumberOfNackRangesSize; + const size_t kMissingPacketsRange = kMissingPacketsOffset + + PACKET_1BYTE_SEQUENCE_NUMBER; + const size_t kRevivedPacketsLength = kMissingPacketsRange + + PACKET_1BYTE_SEQUENCE_NUMBER; + const size_t kRevivedPacketSequenceNumberLength = kRevivedPacketsLength + + PACKET_1BYTE_SEQUENCE_NUMBER; + // Now test framing boundaries. + const size_t ack_frame_size = kRevivedPacketSequenceNumberLength + + PACKET_6BYTE_SEQUENCE_NUMBER; + for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) { + string expected_error; + if (i < kReceivedEntropyOffset) { + expected_error = "Unable to read least unacked delta."; + } else if (i < kLargestObservedOffset) { + expected_error = "Unable to read entropy hash for received packets."; + } else if (i < kMissingDeltaTimeOffset) { + expected_error = "Unable to read largest observed."; + } else if (i < kNumTimestampsOffset) { + expected_error = "Unable to read delta time largest observed."; + } else if (i < kNumMissingPacketOffset) { + expected_error = "Unable to read num received packets."; + } else if (i < kMissingPacketsOffset) { + expected_error = "Unable to read num missing packet ranges."; + } else if (i < kMissingPacketsRange) { + expected_error = "Unable to read missing sequence number delta."; + } else if (i < kRevivedPacketsLength) { + expected_error = "Unable to read missing sequence number range."; + } else if (i < kRevivedPacketSequenceNumberLength) { + expected_error = "Unable to read num revived packets."; + } else { + expected_error = "Unable to read revived packet."; + } + CheckProcessingFails( + packet, + i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP), + expected_error, QUIC_INVALID_ACK_DATA); + } +} + +TEST_P(QuicFramerTest, AckFrameRevivedPacketsv22) { + if (version_ > QUIC_VERSION_22) { + return; + } + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet sequence number + 0xA8, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, not truncated, 6 byte largest observed, 1 byte delta) + 0x6C, + // entropy hash of all received packets. + 0xBA, + // largest observed packet sequence number + 0xBF, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // Zero delta time. + 0x0, 0x0, + // num missing packets + 0x01, + // missing packet delta + 0x01, + // 0 more missing packets in range. + 0x00, + // Number of revived packets. + 0x01, + // Revived packet sequence number. + 0xBE, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // Number of revived packets. + 0x00, }; QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); @@ -1841,7 +2301,7 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) { PACKET_1BYTE_SEQUENCE_NUMBER; const size_t kRevivedPacketSequenceNumberLength = kRevivedPacketsLength + PACKET_1BYTE_SEQUENCE_NUMBER; - // Now test framing boundaries + // Now test framing boundaries. const size_t ack_frame_size = kRevivedPacketSequenceNumberLength + PACKET_6BYTE_SEQUENCE_NUMBER; for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) { @@ -1873,7 +2333,63 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) { } } +TEST_P(QuicFramerTest, AckFrameNoNacksv22) { + if (version_ > QUIC_VERSION_22) { + return; + } + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet sequence number + 0xA8, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (no nacks, not truncated, 6 byte largest observed, 1 byte delta) + 0x4C, + // entropy hash of all received packets. + 0xBA, + // largest observed packet sequence number + 0xBF, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // Zero delta time. + 0x0, 0x0, + }; + + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); + + EXPECT_EQ(0u, visitor_.stream_frames_.size()); + ASSERT_EQ(1u, visitor_.ack_frames_.size()); + QuicAckFrame* frame = visitor_.ack_frames_[0]; + EXPECT_EQ(0xBA, frame->entropy_hash); + EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame->largest_observed); + ASSERT_EQ(0u, frame->missing_packets.size()); + + // Verify that the packet re-serializes identically. + QuicFrames frames; + frames.push_back(QuicFrame(frame)); + scoped_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames)); + ASSERT_TRUE(data != NULL); + + test::CompareCharArraysWithHexError("constructed packet", + data->data(), data->length(), + AsChars(packet), arraysize(packet)); +} + TEST_P(QuicFramerTest, AckFrameNoNacks) { + if (version_ <= QUIC_VERSION_22) { + return; + } unsigned char packet[] = { // public flags (8 byte connection_id) 0x3C, @@ -1896,6 +2412,8 @@ TEST_P(QuicFramerTest, AckFrameNoNacks) { 0x34, 0x12, // Zero delta time. 0x0, 0x0, + // Number of received packets. + 0x00, }; QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); @@ -1923,7 +2441,83 @@ TEST_P(QuicFramerTest, AckFrameNoNacks) { AsChars(packet), arraysize(packet)); } +TEST_P(QuicFramerTest, AckFrame500Nacksv22) { + if (version_ > QUIC_VERSION_22) { + return; + } + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet sequence number + 0xA8, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, not truncated, 6 byte largest observed, 1 byte delta) + 0x6C, + // entropy hash of all received packets. + 0xBA, + // largest observed packet sequence number + 0xBF, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // Zero delta time. + 0x0, 0x0, + // num missing packet ranges + 0x02, + // missing packet delta + 0x01, + // 243 more missing packets in range. + // The ranges are listed in this order so the re-constructed packet matches. + 0xF3, + // No gap between ranges + 0x00, + // 255 more missing packets in range. + 0xFF, + // No revived packets. + 0x00, + }; + + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); + + EXPECT_EQ(0u, visitor_.stream_frames_.size()); + ASSERT_EQ(1u, visitor_.ack_frames_.size()); + QuicAckFrame* frame = visitor_.ack_frames_[0]; + EXPECT_EQ(0xBA, frame->entropy_hash); + EXPECT_EQ(GG_UINT64_C(0x0123456789ABF), frame->largest_observed); + EXPECT_EQ(0u, frame->revived_packets.size()); + ASSERT_EQ(500u, frame->missing_packets.size()); + SequenceNumberSet::const_iterator first_missing_iter = + frame->missing_packets.begin(); + EXPECT_EQ(GG_UINT64_C(0x0123456789ABE) - 499, *first_missing_iter); + SequenceNumberSet::const_reverse_iterator last_missing_iter = + frame->missing_packets.rbegin(); + EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *last_missing_iter); + + // Verify that the packet re-serializes identically. + QuicFrames frames; + frames.push_back(QuicFrame(frame)); + scoped_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames)); + ASSERT_TRUE(data != NULL); + + test::CompareCharArraysWithHexError("constructed packet", + data->data(), data->length(), + AsChars(packet), arraysize(packet)); +} + TEST_P(QuicFramerTest, AckFrame500Nacks) { + if (version_ <= QUIC_VERSION_22) { + return; + } unsigned char packet[] = { // public flags (8 byte connection_id) 0x3C, @@ -1946,6 +2540,8 @@ TEST_P(QuicFramerTest, AckFrame500Nacks) { 0x34, 0x12, // Zero delta time. 0x0, 0x0, + // No received packets. + 0x00, // num missing packet ranges 0x02, // missing packet delta @@ -2028,7 +2624,7 @@ TEST_P(QuicFramerTest, CongestionFeedbackFrameTCP) { ASSERT_EQ(kTCP, frame.type); EXPECT_EQ(0x4030u, frame.tcp.receive_window); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = kQuicFrameTypeSize; i < 4; ++i) { string expected_error; if (i < 2) { @@ -2170,7 +2766,7 @@ TEST_P(QuicFramerTest, RstStreamFrameQuic) { EXPECT_EQ(GG_UINT64_C(0x0807060504030201), visitor_.rst_stream_frame_.byte_offset); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetMinRstStreamFrameSize(); ++i) { string expected_error; @@ -2234,7 +2830,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) { ASSERT_EQ(0u, visitor_.ack_frames_.size()); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetMinConnectionCloseFrameSize(); ++i) { string expected_error; @@ -2292,7 +2888,7 @@ TEST_P(QuicFramerTest, GoAwayFrame) { EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase); const size_t reason_size = arraysize("because I can") - 1; - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetMinGoAwayFrameSize() + reason_size; ++i) { string expected_error; @@ -2347,7 +2943,7 @@ TEST_P(QuicFramerTest, WindowUpdateFrame) { EXPECT_EQ(GG_UINT64_C(0x0c0b0a0908070605), visitor_.window_update_frame_.byte_offset); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetWindowUpdateFrameSize(); ++i) { string expected_error; @@ -2394,7 +2990,7 @@ TEST_P(QuicFramerTest, BlockedFrame) { EXPECT_EQ(GG_UINT64_C(0x01020304), visitor_.blocked_frame_.stream_id); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetBlockedFrameSize(); ++i) { string expected_error = "Unable to read stream_id."; @@ -2481,7 +3077,7 @@ TEST_P(QuicFramerTest, PublicResetPacket) { EXPECT_TRUE( visitor_.public_reset_packet_->client_address.address().empty()); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = 0; i < arraysize(packet); ++i) { string expected_error; DVLOG(1) << "iteration: " << i; @@ -2587,7 +3183,7 @@ TEST_P(QuicFramerTest, PublicResetPacketWithClientAddress) { client_address.address())); EXPECT_EQ(443, visitor_.public_reset_packet_->client_address.port()); - // Now test framing boundaries + // Now test framing boundaries. for (size_t i = 0; i < arraysize(packet); ++i) { string expected_error; DVLOG(1) << "iteration: " << i; @@ -3052,7 +3648,73 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) { AsChars(packet), arraysize(packet)); } +TEST_P(QuicFramerTest, BuildAckFramePacketv22) { + if (version_ > QUIC_VERSION_22) { + return; + } + QuicPacketHeader header; + header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = true; + header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8); + header.fec_group = 0; + + QuicAckFrame ack_frame; + ack_frame.entropy_hash = 0x43; + ack_frame.largest_observed = GG_UINT64_C(0x770123456789ABF); + ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero(); + ack_frame.missing_packets.insert( + GG_UINT64_C(0x770123456789ABE)); + + QuicFrames frames; + frames.push_back(QuicFrame(&ack_frame)); + + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet sequence number + 0xA8, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, not truncated, 6 byte largest observed, 1 byte delta) + 0x6C, + // entropy hash of all received packets. + 0x43, + // largest observed packet sequence number + 0xBF, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // Zero delta time. + 0x0, 0x0, + // num missing packet ranges + 0x01, + // missing packet delta + 0x01, + // 0 more missing packets in range. + 0x00, + // 0 revived packets. + 0x00, + }; + + scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); + ASSERT_TRUE(data != NULL); + + test::CompareCharArraysWithHexError("constructed packet", + data->data(), data->length(), + AsChars(packet), arraysize(packet)); +} + TEST_P(QuicFramerTest, BuildAckFramePacket) { + if (version_ <= QUIC_VERSION_22) { + return; + } QuicPacketHeader header; header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210); header.public_header.reset_flag = false; @@ -3094,6 +3756,8 @@ TEST_P(QuicFramerTest, BuildAckFramePacket) { 0x34, 0x12, // Zero delta time. 0x0, 0x0, + // num received packets. + 0x00, // num missing packet ranges 0x01, // missing packet delta @@ -3114,7 +3778,126 @@ TEST_P(QuicFramerTest, BuildAckFramePacket) { // TODO(jri): Add test for tuncated packets in which the original ack frame had // revived packets. (In both the large and small packet cases below). + +TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacketv22) { + if (version_ > QUIC_VERSION_22) { + return; + } + QuicPacketHeader header; + header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = true; + header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8); + header.fec_group = 0; + + QuicAckFrame ack_frame; + // This entropy hash is different from what shows up in the packet below, + // since entropy is recomputed by the framer on ack truncation (by + // TestEntropyCalculator for this test.) + ack_frame.entropy_hash = 0x43; + ack_frame.largest_observed = 2 * 300; + ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero(); + for (size_t i = 1; i < 2 * 300; i += 2) { + ack_frame.missing_packets.insert(i); + } + + QuicFrames frames; + frames.push_back(QuicFrame(&ack_frame)); + + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet sequence number + 0xA8, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, is truncated, 2 byte largest observed, 1 byte delta) + 0x74, + // entropy hash of all received packets, set to 1 by TestEntropyCalculator + // since ack is truncated. + 0x01, + // 2-byte largest observed packet sequence number. + // Expected to be 510 (0x1FE), since only 255 nack ranges can fit. + 0xFE, 0x01, + // Zero delta time. + 0x0, 0x0, + // num missing packet ranges (limited to 255 by size of this field). + 0xFF, + // {missing packet delta, further missing packets in range} + // 6 nack ranges x 42 + 3 nack ranges + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + + // 0 revived packets. + 0x00, + }; + + scoped_ptr<QuicPacket> data( + framer_.BuildDataPacket(header, frames, kMaxPacketSize).packet); + ASSERT_TRUE(data != NULL); + + test::CompareCharArraysWithHexError("constructed packet", + data->data(), data->length(), + AsChars(packet), arraysize(packet)); +} + TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) { + if (version_ <= QUIC_VERSION_22) { + return; + } QuicPacketHeader header; header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210); header.public_header.reset_flag = false; @@ -3227,7 +4010,79 @@ TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) { } +TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacketv22) { + if (version_ > QUIC_VERSION_22) { + return; + } + QuicPacketHeader header; + header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = true; + header.packet_sequence_number = GG_UINT64_C(0x770123456789AA8); + header.fec_group = 0; + + QuicAckFrame ack_frame; + // This entropy hash is different from what shows up in the packet below, + // since entropy is recomputed by the framer on ack truncation (by + // TestEntropyCalculator for this test.) + ack_frame.entropy_hash = 0x43; + ack_frame.largest_observed = 2 * 300; + ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero(); + for (size_t i = 1; i < 2 * 300; i += 2) { + ack_frame.missing_packets.insert(i); + } + + QuicFrames frames; + frames.push_back(QuicFrame(&ack_frame)); + + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // packet sequence number + 0xA8, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, is truncated, 2 byte largest observed, 1 byte delta) + 0x74, + // entropy hash of all received packets, set to 1 by TestEntropyCalculator + // since ack is truncated. + 0x01, + // 2-byte largest observed packet sequence number. + // Expected to be 12 (0x0C), since only 6 nack ranges can fit. + 0x0C, 0x00, + // Zero delta time. + 0x0, 0x0, + // num missing packet ranges (limited to 6 by packet size of 37). + 0x06, + // {missing packet delta, further missing packets in range} + // 6 nack ranges + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + // 0 revived packets. + 0x00, + }; + + scoped_ptr<QuicPacket> data( + framer_.BuildDataPacket(header, frames, 37u).packet); + ASSERT_TRUE(data != NULL); + // Expect 1 byte unused since at least 2 bytes are needed to fit more nacks. + EXPECT_EQ(36u, data->length()); + test::CompareCharArraysWithHexError("constructed packet", + data->data(), data->length(), + AsChars(packet), arraysize(packet)); +} + TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacket) { + if (version_ <= QUIC_VERSION_22) { + return; + } QuicPacketHeader header; header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210); header.public_header.reset_flag = false; @@ -3396,7 +4251,7 @@ TEST_P(QuicFramerTest, BuildCongestionFeedbackFramePacketInvalidFeedback) { QuicCongestionFeedbackFrame congestion_feedback_frame; congestion_feedback_frame.type = - static_cast<CongestionFeedbackType>(kTimestamp + 1); + static_cast<CongestionFeedbackType>(kTCP + 1); QuicFrames frames; frames.push_back(QuicFrame(&congestion_feedback_frame)); @@ -3953,7 +4808,54 @@ TEST_P(QuicFramerTest, AckTruncationLargePacket) { EXPECT_EQ(509u, *last_missing_iter); } +TEST_P(QuicFramerTest, AckTruncationSmallPacketv22) { + if (version_ > QUIC_VERSION_22) { + return; + } + QuicPacketHeader header; + header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.reset_flag = false; + header.public_header.version_flag = false; + header.fec_flag = false; + header.entropy_flag = false; + header.packet_sequence_number = GG_UINT64_C(0x123456789ABC); + header.fec_group = 0; + + // Create a packet with just the ack. + QuicAckFrame ack_frame = MakeAckFrameWithNackRanges(300, 0u); + QuicFrame frame; + frame.type = ACK_FRAME; + frame.ack_frame = &ack_frame; + QuicFrames frames; + frames.push_back(frame); + + // Build an ack packet with truncation due to limit in number of nack ranges. + scoped_ptr<QuicPacket> raw_ack_packet( + framer_.BuildDataPacket(header, frames, 500).packet); + ASSERT_TRUE(raw_ack_packet != NULL); + scoped_ptr<QuicEncryptedPacket> ack_packet( + framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number, + *raw_ack_packet)); + // Now make sure we can turn our ack packet back into an ack frame. + ASSERT_TRUE(framer_.ProcessPacket(*ack_packet)); + ASSERT_EQ(1u, visitor_.ack_frames_.size()); + QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0]; + EXPECT_TRUE(processed_ack_frame.is_truncated); + EXPECT_EQ(476u, processed_ack_frame.largest_observed); + ASSERT_EQ(238u, processed_ack_frame.missing_packets.size()); + SequenceNumberSet::const_iterator missing_iter = + processed_ack_frame.missing_packets.begin(); + EXPECT_EQ(1u, *missing_iter); + SequenceNumberSet::const_reverse_iterator last_missing_iter = + processed_ack_frame.missing_packets.rbegin(); + EXPECT_EQ(475u, *last_missing_iter); +} + + TEST_P(QuicFramerTest, AckTruncationSmallPacket) { + if (version_ <= QUIC_VERSION_22) { + return; + } QuicPacketHeader header; header.public_header.connection_id = GG_UINT64_C(0xFEDCBA9876543210); header.public_header.reset_flag = false; diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index 14b1a11..75e533c 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc @@ -150,12 +150,13 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { read_buffer_(new IOBufferWithSize(4096)), connection_id_(2), stream_id_(kClientDataStreamId1), - maker_(GetParam(), connection_id_), + maker_(GetParam(), connection_id_, &clock_), random_generator_(0) { IPAddressNumber ip; CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip)); peer_addr_ = IPEndPoint(ip, 443); self_addr_ = IPEndPoint(ip, 8435); + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20)); } ~QuicHttpStreamTest() { @@ -243,7 +244,6 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { stream_.reset(use_closing_stream_ ? new AutoClosingStream(session_->GetWeakPtr()) : new QuicHttpStream(session_->GetWeakPtr())); - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20)); } void SetRequest(const std::string& method, diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index 3d119fb..c835184 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc @@ -107,8 +107,8 @@ class QuicNetworkTransactionTest public ::testing::WithParamInterface<QuicVersion> { protected: QuicNetworkTransactionTest() - : maker_(GetParam(), 0), - clock_(new MockClock), + : clock_(new MockClock), + maker_(GetParam(), 0, clock_), ssl_config_service_(new SSLConfigServiceDefaults), proxy_service_(ProxyService::CreateDirect()), auth_handler_factory_( @@ -304,11 +304,11 @@ class QuicNetworkTransactionTest socket_factory_.AddSocketDataProvider(&hanging_data_); } + MockClock* clock_; // Owned by QuicStreamFactory after CreateSession. QuicTestPacketMaker maker_; scoped_refptr<HttpNetworkSession> session_; MockClientSocketFactory socket_factory_; MockCryptoClientStreamFactory crypto_client_stream_factory_; - MockClock* clock_; // Owned by QuicStreamFactory after CreateSession. MockHostResolver host_resolver_; MockCertVerifier cert_verifier_; TransportSecurityState transport_security_state_; diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc index 1c3a1a8..1ca834e 100644 --- a/net/quic/quic_packet_creator.cc +++ b/net/quic/quic_packet_creator.cc @@ -379,19 +379,20 @@ SerializedPacket QuicPacketCreator::SerializePacket() { size_t max_plaintext_size = framer_->GetMaxPlaintextSize(max_packet_length_); DCHECK_GE(max_plaintext_size, packet_size_); - // ACK Frames will be truncated only if they're the only frame in the packet, - // and if packet_size_ was set to max_plaintext_size. If truncation occurred, - // then GetSerializedFrameLength will have returned all bytes free. - bool possibly_truncated = packet_size_ == max_plaintext_size && - queued_frames_.size() == 1 && - queued_frames_.back().type == ACK_FRAME; + // ACK Frames will be truncated due to length only if they're the only frame + // in the packet, and if packet_size_ was set to max_plaintext_size. If + // truncation due to length occurred, then GetSerializedFrameLength will have + // returned all bytes free. + bool possibly_truncated_by_length = packet_size_ == max_plaintext_size && + queued_frames_.size() == 1 && + queued_frames_.back().type == ACK_FRAME; SerializedPacket serialized = framer_->BuildDataPacket(header, queued_frames_, packet_size_); LOG_IF(DFATAL, !serialized.packet) << "Failed to serialize " << queued_frames_.size() << " frames."; // Because of possible truncation, we can't be confident that our // packet size calculation worked correctly. - if (!possibly_truncated) { + if (!possibly_truncated_by_length) { DCHECK_EQ(packet_size_, serialized.packet->length()); } packet_size_ = 0; diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index 66925ba..314f0ff 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc @@ -171,6 +171,8 @@ QuicTag QuicVersionToQuicTag(const QuicVersion version) { return MakeQuicTag('Q', '0', '2', '1'); case QUIC_VERSION_22: return MakeQuicTag('Q', '0', '2', '2'); + case QUIC_VERSION_23: + return MakeQuicTag('Q', '0', '2', '3'); default: // This shold be an ERROR because we should never attempt to convert an // invalid QuicVersion to be written to the wire. @@ -203,6 +205,7 @@ string QuicVersionToString(const QuicVersion version) { RETURN_STRING_LITERAL(QUIC_VERSION_20); RETURN_STRING_LITERAL(QUIC_VERSION_21); RETURN_STRING_LITERAL(QUIC_VERSION_22); + RETURN_STRING_LITERAL(QUIC_VERSION_23); default: return "QUIC_VERSION_UNSUPPORTED"; } @@ -274,11 +277,6 @@ CongestionFeedbackMessageTCP::CongestionFeedbackMessageTCP() : receive_window(0) { } -CongestionFeedbackMessageTimestamp::CongestionFeedbackMessageTimestamp() { -} - -CongestionFeedbackMessageTimestamp::~CongestionFeedbackMessageTimestamp() {} - QuicCongestionFeedbackFrame::QuicCongestionFeedbackFrame() : type(kTCP) {} QuicCongestionFeedbackFrame::~QuicCongestionFeedbackFrame() {} @@ -383,7 +381,6 @@ ostream& operator<<(ostream& os, const QuicStopWaitingFrame& sent_info) { ostream& operator<<(ostream& os, const QuicAckFrame& ack_frame) { os << "entropy_hash: " << static_cast<int>(ack_frame.entropy_hash) - << " is_truncated: " << ack_frame.is_truncated << " largest_observed: " << ack_frame.largest_observed << " delta_time_largest_observed: " << ack_frame.delta_time_largest_observed.ToMicroseconds() @@ -392,11 +389,18 @@ ostream& operator<<(ostream& os, const QuicAckFrame& ack_frame) { it != ack_frame.missing_packets.end(); ++it) { os << *it << " "; } - os << " ] revived_packets: [ "; + os << " ] is_truncated: " << ack_frame.is_truncated; + os << " revived_packets: [ "; for (SequenceNumberSet::const_iterator it = ack_frame.revived_packets.begin(); it != ack_frame.revived_packets.end(); ++it) { os << *it << " "; } + os << " ] received_packets: [ "; + for (PacketTimeList::const_iterator it = + ack_frame.received_packet_times.begin(); + it != ack_frame.received_packet_times.end(); ++it) { + os << it->first << " at " << it->second.ToDebuggingValue() << " "; + } os << " ]"; return os; } @@ -504,17 +508,6 @@ ostream& operator<<(ostream& os, const QuicCongestionFeedbackFrame& congestion_frame) { os << "type: " << congestion_frame.type; switch (congestion_frame.type) { - case kTimestamp: { - const CongestionFeedbackMessageTimestamp& timestamp = - congestion_frame.timestamp; - os << " received packets: [ "; - for (TimeMap::const_iterator it = timestamp.received_packet_times.begin(); - it != timestamp.received_packet_times.end(); ++it) { - os << it->first << "@" << it->second.ToDebuggingValue() << " "; - } - os << "]"; - break; - } case kTCP: { const CongestionFeedbackMessageTCP& tcp = congestion_frame.tcp; os << " receive_window: " << tcp.receive_window; diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index 539c6d3..0d9fb84 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -7,6 +7,7 @@ #include <stddef.h> #include <limits> +#include <list> #include <map> #include <ostream> #include <set> @@ -291,6 +292,7 @@ enum QuicVersion { QUIC_VERSION_20 = 20, // Independent stream/connection flow control windows. QUIC_VERSION_21 = 21, // Headers/crypto streams are flow controlled. QUIC_VERSION_22 = 22, // Send Server Config Update messages on crypto stream. + QUIC_VERSION_23 = 23, // Timestamp in the ack frame. }; // This vector contains QUIC versions which we currently support. @@ -300,7 +302,8 @@ enum QuicVersion { // // IMPORTANT: if you are adding to this list, follow the instructions at // http://sites/quic/adding-and-removing-versions -static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_22, +static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_23, + QUIC_VERSION_22, QUIC_VERSION_21, QUIC_VERSION_20, QUIC_VERSION_19, @@ -644,8 +647,8 @@ struct NET_EXPORT_PRIVATE QuicStreamFrame { // TODO(ianswett): Re-evaluate the trade-offs of hash_set vs set when framing // is finalized. typedef std::set<QuicPacketSequenceNumber> SequenceNumberSet; -// TODO(pwestin): Add a way to enforce the max size of this map. -typedef std::map<QuicPacketSequenceNumber, QuicTime> TimeMap; + +typedef std::list<std::pair<QuicPacketSequenceNumber, QuicTime>> PacketTimeList; struct NET_EXPORT_PRIVATE QuicStopWaitingFrame { QuicStopWaitingFrame(); @@ -696,6 +699,9 @@ struct NET_EXPORT_PRIVATE QuicAckFrame { // Packets which have been revived via FEC. // All of these must also be in missing_packets. SequenceNumberSet revived_packets; + + // List of <sequence_number, time> for when packets arrived. + PacketTimeList received_packet_times; }; // True if the sequence number is greater than largest_observed or is listed @@ -714,9 +720,9 @@ void NET_EXPORT_PRIVATE InsertMissingPacketsBetween( // Defines for all types of congestion feedback that will be negotiated in QUIC, // kTCP MUST be supported by all QUIC implementations to guarantee 100% // compatibility. +// TODO(cyr): Remove this when removing QUIC_VERSION_22. enum CongestionFeedbackType { kTCP, // Used to mimic TCP. - kTimestamp, // Use additional inter arrival timestamp information. }; // Defines for all types of congestion control algorithms that can be used in @@ -734,21 +740,14 @@ enum LossDetectionType { kTime, // Time based loss detection. }; +// TODO(cyr): Remove this when removing QUIC_VERSION_22. struct NET_EXPORT_PRIVATE CongestionFeedbackMessageTCP { CongestionFeedbackMessageTCP(); QuicByteCount receive_window; }; -struct NET_EXPORT_PRIVATE CongestionFeedbackMessageTimestamp { - CongestionFeedbackMessageTimestamp(); - ~CongestionFeedbackMessageTimestamp(); - - // The set of received packets since the last feedback was sent, along with - // their arrival times. - TimeMap received_packet_times; -}; - +// TODO(cyr): Remove this when removing QUIC_VERSION_22. struct NET_EXPORT_PRIVATE QuicCongestionFeedbackFrame { QuicCongestionFeedbackFrame(); ~QuicCongestionFeedbackFrame(); @@ -760,7 +759,6 @@ struct NET_EXPORT_PRIVATE QuicCongestionFeedbackFrame { // This should really be a union, but since the timestamp struct // is non-trivial, C++ prohibits it. CongestionFeedbackMessageTCP tcp; - CongestionFeedbackMessageTimestamp timestamp; }; struct NET_EXPORT_PRIVATE QuicRstStreamFrame { @@ -861,7 +859,10 @@ struct NET_EXPORT_PRIVATE QuicFrame { explicit QuicFrame(QuicPaddingFrame* padding_frame); explicit QuicFrame(QuicStreamFrame* stream_frame); explicit QuicFrame(QuicAckFrame* frame); + + // TODO(cyr): Remove this when removing QUIC_VERSION_22. explicit QuicFrame(QuicCongestionFeedbackFrame* frame); + explicit QuicFrame(QuicRstStreamFrame* frame); explicit QuicFrame(QuicConnectionCloseFrame* frame); explicit QuicFrame(QuicStopWaitingFrame* frame); @@ -878,8 +879,11 @@ struct NET_EXPORT_PRIVATE QuicFrame { QuicPaddingFrame* padding_frame; QuicStreamFrame* stream_frame; QuicAckFrame* ack_frame; + + // TODO(cyr): Remove this when removing QUIC_VERSION_22. QuicCongestionFeedbackFrame* congestion_feedback_frame; QuicStopWaitingFrame* stop_waiting_frame; + QuicPingFrame* ping_frame; QuicRstStreamFrame* rst_stream_frame; QuicConnectionCloseFrame* connection_close_frame; diff --git a/net/quic/quic_received_packet_manager.cc b/net/quic/quic_received_packet_manager.cc index 15030a4..98136f8 100644 --- a/net/quic/quic_received_packet_manager.cc +++ b/net/quic/quic_received_packet_manager.cc @@ -7,11 +7,13 @@ #include "base/logging.h" #include "base/stl_util.h" #include "net/base/linked_hash_map.h" +#include "net/quic/crypto/crypto_protocol.h" #include "net/quic/quic_connection_stats.h" using std::make_pair; using std::max; using std::min; +using std::numeric_limits; namespace net { @@ -128,11 +130,10 @@ AdvanceFirstGapAndGarbageCollectEntropyMap() { } QuicReceivedPacketManager::QuicReceivedPacketManager( - CongestionFeedbackType congestion_type, QuicConnectionStats* stats) : peer_least_packet_awaiting_ack_(0), time_largest_observed_(QuicTime::Zero()), - receive_algorithm_(ReceiveAlgorithmInterface::Create(congestion_type)), + receive_algorithm_(ReceiveAlgorithmInterface::Create(kTCP)), stats_(stats) { ack_frame_.largest_observed = 0; ack_frame_.entropy_hash = 0; @@ -178,6 +179,9 @@ void QuicReceivedPacketManager::RecordPacketReceived( receive_algorithm_->RecordIncomingPacket( bytes, sequence_number, receipt_time); + received_packet_times_.push_back( + std::make_pair(sequence_number, receipt_time)); + ack_frame_.revived_packets.erase(sequence_number); } @@ -216,6 +220,15 @@ void QuicReceivedPacketManager::UpdateReceivedPacketInfo( ack_frame->delta_time_largest_observed = approximate_now.Subtract(time_largest_observed_); + + // Remove all packets that are too far from largest_observed to express. + received_packet_times_.remove_if( + [this] (std::pair<QuicPacketSequenceNumber, QuicTime> p) + { return ack_frame_.largest_observed - p.first >= + numeric_limits<uint8>::max();}); + + ack_frame->received_packet_times = received_packet_times_; + received_packet_times_.clear(); } bool QuicReceivedPacketManager::GenerateCongestionFeedback( diff --git a/net/quic/quic_received_packet_manager.h b/net/quic/quic_received_packet_manager.h index 92c08f5..57a1175d 100644 --- a/net/quic/quic_received_packet_manager.h +++ b/net/quic/quic_received_packet_manager.h @@ -11,6 +11,7 @@ #include <deque> #include "net/quic/congestion_control/receive_algorithm_interface.h" +#include "net/quic/quic_config.h" #include "net/quic/quic_framer.h" #include "net/quic/quic_protocol.h" @@ -94,8 +95,7 @@ class NET_EXPORT_PRIVATE QuicReceivedPacketManager : DISALLOW_COPY_AND_ASSIGN(EntropyTracker); }; - explicit QuicReceivedPacketManager(CongestionFeedbackType congestion_type, - QuicConnectionStats* stats); + explicit QuicReceivedPacketManager(QuicConnectionStats* stats); virtual ~QuicReceivedPacketManager(); // Updates the internal state concerning which packets have been received. @@ -172,6 +172,8 @@ class NET_EXPORT_PRIVATE QuicReceivedPacketManager : QuicConnectionStats* stats_; + PacketTimeList received_packet_times_; + DISALLOW_COPY_AND_ASSIGN(QuicReceivedPacketManager); }; diff --git a/net/quic/quic_received_packet_manager_test.cc b/net/quic/quic_received_packet_manager_test.cc index 2a219d3..9e8c128 100644 --- a/net/quic/quic_received_packet_manager_test.cc +++ b/net/quic/quic_received_packet_manager_test.cc @@ -188,7 +188,7 @@ TEST(EntropyTrackerTest, SetCumulativeEntropyUpTo) { class QuicReceivedPacketManagerTest : public ::testing::Test { protected: - QuicReceivedPacketManagerTest() : received_manager_(kTCP, &stats_) {} + QuicReceivedPacketManagerTest() : received_manager_(&stats_) {} void RecordPacketReceipt(QuicPacketSequenceNumber sequence_number, QuicPacketEntropyHash entropy_hash) { diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index 5cb5b57..82ec1cd 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc @@ -90,8 +90,8 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> { protected: QuicStreamFactoryTest() : random_generator_(0), - maker_(GetParam(), 0), clock_(new MockClock()), + maker_(GetParam(), 0, clock_), cert_verifier_(CertVerifier::CreateDefault()), channel_id_service_(new ChannelIDService( new DefaultChannelIDStore(NULL), @@ -187,8 +187,8 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<QuicVersion> { DeterministicMockClientSocketFactory socket_factory_; MockCryptoClientStreamFactory crypto_client_stream_factory_; MockRandom random_generator_; - QuicTestPacketMaker maker_; MockClock* clock_; // Owned by factory_. + QuicTestPacketMaker maker_; scoped_ptr<CertVerifier> cert_verifier_; scoped_ptr<ChannelIDService> channel_id_service_; TransportSecurityState transport_security_state_; diff --git a/net/quic/test_tools/mock_crypto_client_stream.cc b/net/quic/test_tools/mock_crypto_client_stream.cc index 4d4057a..ea7b84f 100644 --- a/net/quic/test_tools/mock_crypto_client_stream.cc +++ b/net/quic/test_tools/mock_crypto_client_stream.cc @@ -81,7 +81,10 @@ void MockCryptoClientStream::SendOnCryptoHandshakeEvent( void MockCryptoClientStream::SetConfigNegotiated() { ASSERT_FALSE(session()->config()->negotiated()); QuicTagVector cgst; - cgst.push_back(kTSTP); + // TODO(rtenneti): Enable the following code after BBR code is checked in. +#if 0 + cgst.push_back(kTBBR); +#endif cgst.push_back(kQBIC); session()->config()->set_congestion_feedback(cgst, kQBIC); session()->config()->set_idle_connection_state_lifetime( diff --git a/net/quic/test_tools/quic_test_packet_maker.cc b/net/quic/test_tools/quic_test_packet_maker.cc index 345b7b5..6540426 100644 --- a/net/quic/test_tools/quic_test_packet_maker.cc +++ b/net/quic/test_tools/quic_test_packet_maker.cc @@ -4,18 +4,24 @@ #include "net/quic/test_tools/quic_test_packet_maker.h" +#include <list> + #include "net/quic/quic_framer.h" #include "net/quic/quic_http_utils.h" #include "net/quic/quic_utils.h" #include "net/quic/test_tools/quic_test_utils.h" +using std::make_pair; + namespace net { namespace test { QuicTestPacketMaker::QuicTestPacketMaker(QuicVersion version, - QuicConnectionId connection_id) + QuicConnectionId connection_id, + MockClock* clock) : version_(version), connection_id_(connection_id), + clock_(clock), spdy_request_framer_(SPDY3), spdy_response_framer_(SPDY3) { } @@ -63,10 +69,16 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckAndRstPacket( QuicAckFrame ack(MakeAckFrame(largest_received)); ack.delta_time_largest_observed = QuicTime::Delta::Zero(); + if (version_ > QUIC_VERSION_22) { + for (QuicPacketSequenceNumber i = least_unacked; i <= largest_received; + ++i) { + ack.received_packet_times.push_back(make_pair(i, clock_->Now())); + } + } QuicFrames frames; frames.push_back(QuicFrame(&ack)); QuicCongestionFeedbackFrame feedback; - if (send_feedback) { + if (send_feedback && version_ <= QUIC_VERSION_22) { feedback.type = kTCP; feedback.tcp.receive_window = 256000; @@ -80,7 +92,7 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckAndRstPacket( QuicRstStreamFrame rst(stream_id, error_code, 0); frames.push_back(QuicFrame(&rst)); - QuicFramer framer(SupportedVersions(version_), QuicTime::Zero(), false); + QuicFramer framer(SupportedVersions(version_), clock_->Now(), false); scoped_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header, frames).packet); return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket( @@ -122,15 +134,20 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckPacket( QuicAckFrame ack(MakeAckFrame(largest_received)); ack.delta_time_largest_observed = QuicTime::Delta::Zero(); + if (version_ > QUIC_VERSION_22) { + for (QuicPacketSequenceNumber i = least_unacked; i <= largest_received; + ++i) { + ack.received_packet_times.push_back(make_pair(i, clock_->Now())); + } + } - QuicCongestionFeedbackFrame feedback; - feedback.type = kTCP; - feedback.tcp.receive_window = 256000; - - QuicFramer framer(SupportedVersions(version_), QuicTime::Zero(), false); + QuicFramer framer(SupportedVersions(version_), clock_->Now(), false); QuicFrames frames; frames.push_back(QuicFrame(&ack)); - if (send_feedback) { + QuicCongestionFeedbackFrame feedback; + if (send_feedback && version_ <= QUIC_VERSION_22) { + feedback.type = kTCP; + feedback.tcp.receive_window = 256000; frames.push_back(QuicFrame(&feedback)); } diff --git a/net/quic/test_tools/quic_test_packet_maker.h b/net/quic/test_tools/quic_test_packet_maker.h index e4f3ec0..9120eeb 100644 --- a/net/quic/test_tools/quic_test_packet_maker.h +++ b/net/quic/test_tools/quic_test_packet_maker.h @@ -10,6 +10,7 @@ #include "base/memory/scoped_ptr.h" #include "net/base/request_priority.h" #include "net/quic/quic_protocol.h" +#include "net/quic/test_tools/mock_clock.h" #include "net/quic/test_tools/mock_random.h" #include "net/spdy/spdy_framer.h" #include "net/spdy/spdy_protocol.h" @@ -19,7 +20,9 @@ namespace test { class QuicTestPacketMaker { public: - QuicTestPacketMaker(QuicVersion version, QuicConnectionId connection_id); + QuicTestPacketMaker(QuicVersion version, + QuicConnectionId connection_id, + MockClock* clock); ~QuicTestPacketMaker(); scoped_ptr<QuicEncryptedPacket> MakeRstPacket( @@ -77,6 +80,7 @@ class QuicTestPacketMaker { QuicVersion version_; QuicConnectionId connection_id_; + MockClock* clock_; // Owned by QuicStreamFactory. SpdyFramer spdy_request_framer_; SpdyFramer spdy_response_framer_; MockRandom random_generator_; |