|  | // Copyright (c) 2012 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_framer.h" | 
|  |  | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <map> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/containers/hash_tables.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/memory/scoped_ptr.h" | 
|  | #include "base/stl_util.h" | 
|  | #include "net/quic/crypto/quic_decrypter.h" | 
|  | #include "net/quic/crypto/quic_encrypter.h" | 
|  | #include "net/quic/quic_protocol.h" | 
|  | #include "net/quic/quic_utils.h" | 
|  | #include "net/quic/test_tools/quic_framer_peer.h" | 
|  | #include "net/quic/test_tools/quic_test_utils.h" | 
|  | #include "net/test/gtest_util.h" | 
|  |  | 
|  | using base::hash_set; | 
|  | using base::StringPiece; | 
|  | using std::make_pair; | 
|  | using std::map; | 
|  | using std::numeric_limits; | 
|  | using std::pair; | 
|  | using std::string; | 
|  | using std::vector; | 
|  | using testing::Return; | 
|  | using testing::_; | 
|  |  | 
|  | namespace net { | 
|  | namespace test { | 
|  |  | 
|  | const QuicPacketSequenceNumber kEpoch = UINT64_C(1) << 48; | 
|  | const QuicPacketSequenceNumber kMask = kEpoch - 1; | 
|  |  | 
|  | // Index into the connection_id offset in the header. | 
|  | const size_t kConnectionIdOffset = kPublicFlagsSize; | 
|  | // Index into the version string in the header. (if present). | 
|  | const size_t kVersionOffset = kConnectionIdOffset + PACKET_8BYTE_CONNECTION_ID; | 
|  |  | 
|  | // Size in bytes of the stream frame fields for an arbitrary StreamID and | 
|  | // offset and the last frame in a packet. | 
|  | size_t GetMinStreamFrameSize() { | 
|  | return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize; | 
|  | } | 
|  |  | 
|  | // Index into the sequence number offset in the header. | 
|  | size_t GetSequenceNumberOffset(QuicConnectionIdLength connection_id_length, | 
|  | bool include_version) { | 
|  | return kConnectionIdOffset + connection_id_length + | 
|  | (include_version ? kQuicVersionSize : 0); | 
|  | } | 
|  |  | 
|  | size_t GetSequenceNumberOffset(bool include_version) { | 
|  | return GetSequenceNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version); | 
|  | } | 
|  |  | 
|  | // Index into the private flags offset in the data packet header. | 
|  | size_t GetPrivateFlagsOffset(QuicConnectionIdLength connection_id_length, | 
|  | bool include_version) { | 
|  | return GetSequenceNumberOffset(connection_id_length, include_version) + | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER; | 
|  | } | 
|  |  | 
|  | size_t GetPrivateFlagsOffset(bool include_version) { | 
|  | return GetPrivateFlagsOffset(PACKET_8BYTE_CONNECTION_ID, include_version); | 
|  | } | 
|  |  | 
|  | size_t GetPrivateFlagsOffset(bool include_version, | 
|  | QuicSequenceNumberLength sequence_number_length) { | 
|  | return GetSequenceNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version) + | 
|  | sequence_number_length; | 
|  | } | 
|  |  | 
|  | // Index into the fec group offset in the header. | 
|  | size_t GetFecGroupOffset(QuicConnectionIdLength connection_id_length, | 
|  | bool include_version) { | 
|  | return GetPrivateFlagsOffset(connection_id_length, include_version) + | 
|  | kPrivateFlagsSize; | 
|  | } | 
|  |  | 
|  | size_t GetFecGroupOffset(bool include_version) { | 
|  | return GetPrivateFlagsOffset(PACKET_8BYTE_CONNECTION_ID, include_version) + | 
|  | kPrivateFlagsSize; | 
|  | } | 
|  |  | 
|  | size_t GetFecGroupOffset(bool include_version, | 
|  | QuicSequenceNumberLength sequence_number_length) { | 
|  | return GetPrivateFlagsOffset(include_version, sequence_number_length) + | 
|  | kPrivateFlagsSize; | 
|  | } | 
|  |  | 
|  | // Index into the message tag of the public reset packet. | 
|  | // Public resets always have full connection_ids. | 
|  | const size_t kPublicResetPacketMessageTagOffset = | 
|  | kConnectionIdOffset + PACKET_8BYTE_CONNECTION_ID; | 
|  |  | 
|  | class TestEncrypter : public QuicEncrypter { | 
|  | public: | 
|  | ~TestEncrypter() override {} | 
|  | bool SetKey(StringPiece key) override { return true; } | 
|  | bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; } | 
|  | bool Encrypt(StringPiece nonce, | 
|  | StringPiece associated_data, | 
|  | StringPiece plaintext, | 
|  | unsigned char* output) override { | 
|  | CHECK(false) << "Not implemented"; | 
|  | return false; | 
|  | } | 
|  | bool EncryptPacket(QuicPacketSequenceNumber sequence_number, | 
|  | StringPiece associated_data, | 
|  | StringPiece plaintext, | 
|  | char* output, | 
|  | size_t* output_length, | 
|  | size_t max_output_length) override { | 
|  | sequence_number_ = sequence_number; | 
|  | associated_data_ = associated_data.as_string(); | 
|  | plaintext_ = plaintext.as_string(); | 
|  | memcpy(output, plaintext.data(), plaintext.length()); | 
|  | *output_length = plaintext.length(); | 
|  | return true; | 
|  | } | 
|  | size_t GetKeySize() const override { return 0; } | 
|  | size_t GetNoncePrefixSize() const override { return 0; } | 
|  | size_t GetMaxPlaintextSize(size_t ciphertext_size) const override { | 
|  | return ciphertext_size; | 
|  | } | 
|  | size_t GetCiphertextSize(size_t plaintext_size) const override { | 
|  | return plaintext_size; | 
|  | } | 
|  | StringPiece GetKey() const override { return StringPiece(); } | 
|  | StringPiece GetNoncePrefix() const override { return StringPiece(); } | 
|  | QuicPacketSequenceNumber sequence_number_; | 
|  | string associated_data_; | 
|  | string plaintext_; | 
|  | }; | 
|  |  | 
|  | class TestDecrypter : public QuicDecrypter { | 
|  | public: | 
|  | ~TestDecrypter() override {} | 
|  | bool SetKey(StringPiece key) override { return true; } | 
|  | bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; } | 
|  | bool DecryptPacket(QuicPacketSequenceNumber sequence_number, | 
|  | const StringPiece& associated_data, | 
|  | const StringPiece& ciphertext, | 
|  | char* output, | 
|  | size_t* output_length, | 
|  | size_t max_output_length) override { | 
|  | sequence_number_ = sequence_number; | 
|  | associated_data_ = associated_data.as_string(); | 
|  | ciphertext_ = ciphertext.as_string(); | 
|  | memcpy(output, ciphertext.data(), ciphertext.length()); | 
|  | *output_length = ciphertext.length(); | 
|  | return true; | 
|  | } | 
|  | StringPiece GetKey() const override { return StringPiece(); } | 
|  | StringPiece GetNoncePrefix() const override { return StringPiece(); } | 
|  | QuicPacketSequenceNumber sequence_number_; | 
|  | string associated_data_; | 
|  | string ciphertext_; | 
|  | }; | 
|  |  | 
|  | class TestQuicVisitor : public QuicFramerVisitorInterface { | 
|  | public: | 
|  | TestQuicVisitor() | 
|  | : error_count_(0), | 
|  | version_mismatch_(0), | 
|  | packet_count_(0), | 
|  | frame_count_(0), | 
|  | fec_count_(0), | 
|  | complete_packets_(0), | 
|  | revived_packets_(0), | 
|  | accept_packet_(true), | 
|  | accept_public_header_(true) { | 
|  | } | 
|  |  | 
|  | ~TestQuicVisitor() override { | 
|  | STLDeleteElements(&stream_frames_); | 
|  | STLDeleteElements(&ack_frames_); | 
|  | STLDeleteElements(&stop_waiting_frames_); | 
|  | STLDeleteElements(&ping_frames_); | 
|  | STLDeleteElements(&fec_data_); | 
|  | STLDeleteElements(&stream_data_); | 
|  | STLDeleteElements(&fec_data_redundancy_); | 
|  | } | 
|  |  | 
|  | void OnError(QuicFramer* f) override { | 
|  | DVLOG(1) << "QuicFramer Error: " << QuicUtils::ErrorToString(f->error()) | 
|  | << " (" << f->error() << ")"; | 
|  | ++error_count_; | 
|  | } | 
|  |  | 
|  | void OnPacket() override {} | 
|  |  | 
|  | void OnPublicResetPacket(const QuicPublicResetPacket& packet) override { | 
|  | public_reset_packet_.reset(new QuicPublicResetPacket(packet)); | 
|  | } | 
|  |  | 
|  | void OnVersionNegotiationPacket( | 
|  | const QuicVersionNegotiationPacket& packet) override { | 
|  | version_negotiation_packet_.reset(new QuicVersionNegotiationPacket(packet)); | 
|  | } | 
|  |  | 
|  | void OnRevivedPacket() override { ++revived_packets_; } | 
|  |  | 
|  | bool OnProtocolVersionMismatch(QuicVersion version) override { | 
|  | DVLOG(1) << "QuicFramer Version Mismatch, version: " << version; | 
|  | ++version_mismatch_; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnUnauthenticatedPublicHeader( | 
|  | const QuicPacketPublicHeader& header) override { | 
|  | public_header_.reset(new QuicPacketPublicHeader(header)); | 
|  | return accept_public_header_; | 
|  | } | 
|  |  | 
|  | bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void OnDecryptedPacket(EncryptionLevel level) override {} | 
|  |  | 
|  | bool OnPacketHeader(const QuicPacketHeader& header) override { | 
|  | ++packet_count_; | 
|  | header_.reset(new QuicPacketHeader(header)); | 
|  | return accept_packet_; | 
|  | } | 
|  |  | 
|  | bool OnStreamFrame(const QuicStreamFrame& frame) override { | 
|  | ++frame_count_; | 
|  | // Save a copy of the data so it is valid after the packet is processed. | 
|  | stream_data_.push_back(frame.GetDataAsString()); | 
|  | QuicStreamFrame* stream_frame = new QuicStreamFrame(frame); | 
|  | // Make sure that the stream frame points to this data. | 
|  | stream_frame->data.Clear(); | 
|  | stream_frame->data.Append(const_cast<char*>(stream_data_.back()->data()), | 
|  | stream_data_.back()->size()); | 
|  | stream_frames_.push_back(stream_frame); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void OnFecProtectedPayload(StringPiece payload) override { | 
|  | fec_protected_payload_ = payload.as_string(); | 
|  | } | 
|  |  | 
|  | bool OnAckFrame(const QuicAckFrame& frame) override { | 
|  | ++frame_count_; | 
|  | ack_frames_.push_back(new QuicAckFrame(frame)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override { | 
|  | ++frame_count_; | 
|  | stop_waiting_frames_.push_back(new QuicStopWaitingFrame(frame)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnPingFrame(const QuicPingFrame& frame) override { | 
|  | ++frame_count_; | 
|  | ping_frames_.push_back(new QuicPingFrame(frame)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void OnFecData(const QuicFecData& fec) override { | 
|  | ++fec_count_; | 
|  | QuicFecData* fec_data = new QuicFecData(); | 
|  | fec_data->fec_group = fec.fec_group; | 
|  | // Save a copy of the data so it is valid after the packet is processed. | 
|  | string* redundancy = new string(fec.redundancy.as_string()); | 
|  | fec_data_redundancy_.push_back(redundancy); | 
|  | fec_data->redundancy = StringPiece(*redundancy); | 
|  | fec_data_.push_back(fec_data); | 
|  | } | 
|  |  | 
|  | void OnPacketComplete() override { ++complete_packets_; } | 
|  |  | 
|  | bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override { | 
|  | rst_stream_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override { | 
|  | connection_close_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override { | 
|  | goaway_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override { | 
|  | window_update_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool OnBlockedFrame(const QuicBlockedFrame& frame) override { | 
|  | blocked_frame_ = frame; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Counters from the visitor_ callbacks. | 
|  | int error_count_; | 
|  | int version_mismatch_; | 
|  | int packet_count_; | 
|  | int frame_count_; | 
|  | int fec_count_; | 
|  | int complete_packets_; | 
|  | int revived_packets_; | 
|  | bool accept_packet_; | 
|  | bool accept_public_header_; | 
|  |  | 
|  | scoped_ptr<QuicPacketHeader> header_; | 
|  | scoped_ptr<QuicPacketPublicHeader> public_header_; | 
|  | scoped_ptr<QuicPublicResetPacket> public_reset_packet_; | 
|  | scoped_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_; | 
|  | vector<QuicStreamFrame*> stream_frames_; | 
|  | vector<QuicAckFrame*> ack_frames_; | 
|  | vector<QuicStopWaitingFrame*> stop_waiting_frames_; | 
|  | vector<QuicPingFrame*> ping_frames_; | 
|  | vector<QuicFecData*> fec_data_; | 
|  | string fec_protected_payload_; | 
|  | QuicRstStreamFrame rst_stream_frame_; | 
|  | QuicConnectionCloseFrame connection_close_frame_; | 
|  | QuicGoAwayFrame goaway_frame_; | 
|  | QuicWindowUpdateFrame window_update_frame_; | 
|  | QuicBlockedFrame blocked_frame_; | 
|  | vector<string*> stream_data_; | 
|  | vector<string*> fec_data_redundancy_; | 
|  | }; | 
|  |  | 
|  | class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> { | 
|  | public: | 
|  | QuicFramerTest() | 
|  | : encrypter_(new test::TestEncrypter()), | 
|  | decrypter_(new test::TestDecrypter()), | 
|  | start_(QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(0x10))), | 
|  | framer_(QuicSupportedVersions(), start_, Perspective::IS_SERVER) { | 
|  | version_ = GetParam(); | 
|  | framer_.set_version(version_); | 
|  | framer_.SetDecrypter(decrypter_, ENCRYPTION_NONE); | 
|  | framer_.SetEncrypter(ENCRYPTION_NONE, encrypter_); | 
|  | framer_.set_visitor(&visitor_); | 
|  | framer_.set_received_entropy_calculator(&entropy_calculator_); | 
|  | } | 
|  |  | 
|  | // Helper function to get unsigned char representation of digit in the | 
|  | // units place of the current QUIC version number. | 
|  | unsigned char GetQuicVersionDigitOnes() { | 
|  | return static_cast<unsigned char> ('0' + version_%10); | 
|  | } | 
|  |  | 
|  | // Helper function to get unsigned char representation of digit in the | 
|  | // tens place of the current QUIC version number. | 
|  | unsigned char GetQuicVersionDigitTens() { | 
|  | return static_cast<unsigned char> ('0' + (version_/10)%10); | 
|  | } | 
|  |  | 
|  | bool CheckEncryption(QuicPacketSequenceNumber sequence_number, | 
|  | QuicPacket* packet) { | 
|  | if (sequence_number != encrypter_->sequence_number_) { | 
|  | LOG(ERROR) << "Encrypted incorrect packet sequence number.  expected " | 
|  | << sequence_number << " actual: " | 
|  | << encrypter_->sequence_number_; | 
|  | return false; | 
|  | } | 
|  | if (packet->AssociatedData() != encrypter_->associated_data_) { | 
|  | LOG(ERROR) << "Encrypted incorrect associated data.  expected " | 
|  | << packet->AssociatedData() << " actual: " | 
|  | << encrypter_->associated_data_; | 
|  | return false; | 
|  | } | 
|  | if (packet->Plaintext() != encrypter_->plaintext_) { | 
|  | LOG(ERROR) << "Encrypted incorrect plaintext data.  expected " | 
|  | << packet->Plaintext() << " actual: " | 
|  | << encrypter_->plaintext_; | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool CheckDecryption(const QuicEncryptedPacket& encrypted, | 
|  | bool includes_version) { | 
|  | if (visitor_.header_->packet_sequence_number != | 
|  | decrypter_->sequence_number_) { | 
|  | LOG(ERROR) << "Decrypted incorrect packet sequence number.  expected " | 
|  | << visitor_.header_->packet_sequence_number << " actual: " | 
|  | << decrypter_->sequence_number_; | 
|  | return false; | 
|  | } | 
|  | if (QuicFramer::GetAssociatedDataFromEncryptedPacket( | 
|  | encrypted, PACKET_8BYTE_CONNECTION_ID, | 
|  | includes_version, PACKET_6BYTE_SEQUENCE_NUMBER) != | 
|  | decrypter_->associated_data_) { | 
|  | LOG(ERROR) << "Decrypted incorrect associated data.  expected " | 
|  | << QuicFramer::GetAssociatedDataFromEncryptedPacket( | 
|  | encrypted, PACKET_8BYTE_CONNECTION_ID, | 
|  | includes_version, PACKET_6BYTE_SEQUENCE_NUMBER) | 
|  | << " actual: " << decrypter_->associated_data_; | 
|  | return false; | 
|  | } | 
|  | StringPiece ciphertext(encrypted.AsStringPiece().substr( | 
|  | GetStartOfEncryptedData(PACKET_8BYTE_CONNECTION_ID, includes_version, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER))); | 
|  | if (ciphertext != decrypter_->ciphertext_) { | 
|  | LOG(ERROR) << "Decrypted incorrect ciphertext data.  expected " | 
|  | << ciphertext << " actual: " | 
|  | << decrypter_->ciphertext_; | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | char* AsChars(unsigned char* data) { | 
|  | return reinterpret_cast<char*>(data); | 
|  | } | 
|  |  | 
|  | void CheckProcessingFails(unsigned char* packet, | 
|  | size_t len, | 
|  | string expected_error, | 
|  | QuicErrorCode error_code) { | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), len, false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)) << "len: " << len; | 
|  | EXPECT_EQ(expected_error, framer_.detailed_error()) << "len: " << len; | 
|  | EXPECT_EQ(error_code, framer_.error()) << "len: " << len; | 
|  | } | 
|  |  | 
|  | // Checks if the supplied string matches data in the supplied StreamFrame. | 
|  | void CheckStreamFrameData(string str, QuicStreamFrame* frame) { | 
|  | scoped_ptr<string> frame_data(frame->GetDataAsString()); | 
|  | EXPECT_EQ(str, *frame_data); | 
|  | } | 
|  |  | 
|  | void CheckStreamFrameBoundaries(unsigned char* packet, | 
|  | size_t stream_id_size, | 
|  | bool include_version) { | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = kQuicFrameTypeSize; i < GetMinStreamFrameSize(); ++i) { | 
|  | string expected_error; | 
|  | if (i < kQuicFrameTypeSize + stream_id_size) { | 
|  | expected_error = "Unable to read stream_id."; | 
|  | } 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_CONNECTION_ID, include_version, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, | 
|  | NOT_IN_FEC_GROUP), | 
|  | expected_error, QUIC_INVALID_STREAM_DATA); | 
|  | } | 
|  | } | 
|  |  | 
|  | void CheckCalculatePacketSequenceNumber( | 
|  | QuicPacketSequenceNumber expected_sequence_number, | 
|  | QuicPacketSequenceNumber last_sequence_number) { | 
|  | QuicPacketSequenceNumber wire_sequence_number = | 
|  | expected_sequence_number & kMask; | 
|  | QuicFramerPeer::SetLastSequenceNumber(&framer_, last_sequence_number); | 
|  | EXPECT_EQ(expected_sequence_number, | 
|  | QuicFramerPeer::CalculatePacketSequenceNumberFromWire( | 
|  | &framer_, PACKET_6BYTE_SEQUENCE_NUMBER, wire_sequence_number)) | 
|  | << "last_sequence_number: " << last_sequence_number | 
|  | << " wire_sequence_number: " << wire_sequence_number; | 
|  | } | 
|  |  | 
|  | QuicPacket* BuildDataPacket(const QuicPacketHeader& header, | 
|  | const QuicFrames& frames) { | 
|  | return BuildUnsizedDataPacket(&framer_, header, frames); | 
|  | } | 
|  |  | 
|  | QuicPacket* BuildDataPacket(const QuicPacketHeader& header, | 
|  | const QuicFrames& frames, | 
|  | size_t packet_size) { | 
|  | return BuildUnsizedDataPacket(&framer_, header, frames, packet_size); | 
|  | } | 
|  |  | 
|  | test::TestEncrypter* encrypter_; | 
|  | test::TestDecrypter* decrypter_; | 
|  | QuicVersion version_; | 
|  | QuicTime start_; | 
|  | QuicFramer framer_; | 
|  | test::TestQuicVisitor visitor_; | 
|  | test::TestEntropyCalculator entropy_calculator_; | 
|  | }; | 
|  |  | 
|  | // Run all framer tests with all supported versions of QUIC. | 
|  | INSTANTIATE_TEST_CASE_P(QuicFramerTests, | 
|  | QuicFramerTest, | 
|  | ::testing::ValuesIn(kSupportedQuicVersions)); | 
|  |  | 
|  | TEST_P(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearEpochStart) { | 
|  | // A few quick manual sanity checks | 
|  | CheckCalculatePacketSequenceNumber(UINT64_C(1), UINT64_C(0)); | 
|  | CheckCalculatePacketSequenceNumber(kEpoch + 1, kMask); | 
|  | CheckCalculatePacketSequenceNumber(kEpoch, kMask); | 
|  |  | 
|  | // Cases where the last number was close to the start of the range | 
|  | for (uint64 last = 0; last < 10; last++) { | 
|  | // Small numbers should not wrap (even if they're out of order). | 
|  | for (uint64 j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketSequenceNumber(j, last); | 
|  | } | 
|  |  | 
|  | // Large numbers should not wrap either (because we're near 0 already). | 
|  | for (uint64 j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketSequenceNumber(kEpoch - 1 - j, last); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearEpochEnd) { | 
|  | // Cases where the last number was close to the end of the range | 
|  | for (uint64 i = 0; i < 10; i++) { | 
|  | QuicPacketSequenceNumber last = kEpoch - i; | 
|  |  | 
|  | // Small numbers should wrap. | 
|  | for (uint64 j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketSequenceNumber(kEpoch + j, last); | 
|  | } | 
|  |  | 
|  | // Large numbers should not (even if they're out of order). | 
|  | for (uint64 j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketSequenceNumber(kEpoch - 1 - j, last); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Next check where we're in a non-zero epoch to verify we handle | 
|  | // reverse wrapping, too. | 
|  | TEST_P(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearPrevEpoch) { | 
|  | const uint64 prev_epoch = 1 * kEpoch; | 
|  | const uint64 cur_epoch = 2 * kEpoch; | 
|  | // Cases where the last number was close to the start of the range | 
|  | for (uint64 i = 0; i < 10; i++) { | 
|  | uint64 last = cur_epoch + i; | 
|  | // Small number should not wrap (even if they're out of order). | 
|  | for (uint64 j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketSequenceNumber(cur_epoch + j, last); | 
|  | } | 
|  |  | 
|  | // But large numbers should reverse wrap. | 
|  | for (uint64 j = 0; j < 10; j++) { | 
|  | uint64 num = kEpoch - 1 - j; | 
|  | CheckCalculatePacketSequenceNumber(prev_epoch + num, last); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearNextEpoch) { | 
|  | const uint64 cur_epoch = 2 * kEpoch; | 
|  | const uint64 next_epoch = 3 * kEpoch; | 
|  | // Cases where the last number was close to the end of the range | 
|  | for (uint64 i = 0; i < 10; i++) { | 
|  | QuicPacketSequenceNumber last = next_epoch - 1 - i; | 
|  |  | 
|  | // Small numbers should wrap. | 
|  | for (uint64 j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketSequenceNumber(next_epoch + j, last); | 
|  | } | 
|  |  | 
|  | // but large numbers should not (even if they're out of order). | 
|  | for (uint64 j = 0; j < 10; j++) { | 
|  | uint64 num = kEpoch - 1 - j; | 
|  | CheckCalculatePacketSequenceNumber(cur_epoch + num, last); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, CalculatePacketSequenceNumberFromWireNearNextMax) { | 
|  | const uint64 max_number = numeric_limits<uint64>::max(); | 
|  | const uint64 max_epoch = max_number & ~kMask; | 
|  |  | 
|  | // Cases where the last number was close to the end of the range | 
|  | for (uint64 i = 0; i < 10; i++) { | 
|  | // Subtract 1, because the expected next sequence number is 1 more than the | 
|  | // last sequence number. | 
|  | QuicPacketSequenceNumber last = max_number - i - 1; | 
|  |  | 
|  | // Small numbers should not wrap, because they have nowhere to go. | 
|  | for (uint64 j = 0; j < 10; j++) { | 
|  | CheckCalculatePacketSequenceNumber(max_epoch + j, last); | 
|  | } | 
|  |  | 
|  | // Large numbers should not wrap either. | 
|  | for (uint64 j = 0; j < 10; j++) { | 
|  | uint64 num = kEpoch - 1 - j; | 
|  | CheckCalculatePacketSequenceNumber(max_epoch + num, last); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, EmptyPacket) { | 
|  | char packet[] = { 0x00 }; | 
|  | QuicEncryptedPacket encrypted(packet, 0, false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, LargePacket) { | 
|  | unsigned char packet[kMaxPacketSize + 1] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, | 
|  | 0x32, | 
|  | 0x54, | 
|  | 0x76, | 
|  | 0x98, | 
|  | 0xBA, | 
|  | 0xDC, | 
|  | 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, | 
|  | 0x9A, | 
|  | 0x78, | 
|  | 0x56, | 
|  | 0x34, | 
|  | 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | memset(packet + GetPacketHeaderSize( | 
|  | PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP), 0, | 
|  | kMaxPacketSize - GetPacketHeaderSize( | 
|  | PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP) + 1); | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  |  | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | // Make sure we've parsed the packet header, so we can send an error. | 
|  | EXPECT_EQ(UINT64_C(0xFEDCBA9876543210), | 
|  | visitor_.header_->public_header.connection_id); | 
|  | // Make sure the correct error is propagated. | 
|  | EXPECT_EQ(QUIC_PACKET_TOO_LARGE, framer_.error()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeader) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(UINT64_C(0xFEDCBA9876543210), | 
|  | visitor_.header_->public_header.connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.version_flag); | 
|  | EXPECT_FALSE(visitor_.header_->fec_flag); | 
|  | EXPECT_FALSE(visitor_.header_->entropy_flag); | 
|  | EXPECT_EQ(0, visitor_.header_->entropy_hash); | 
|  | EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number); | 
|  | EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); | 
|  | EXPECT_EQ(0x00u, visitor_.header_->fec_group); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = 0; | 
|  | i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); | 
|  | ++i) { | 
|  | string expected_error; | 
|  | if (i < kConnectionIdOffset) { | 
|  | expected_error = "Unable to read public flags."; | 
|  | } else if (i < GetSequenceNumberOffset(!kIncludeVersion)) { | 
|  | expected_error = "Unable to read ConnectionId."; | 
|  | } else if (i < GetPrivateFlagsOffset(!kIncludeVersion)) { | 
|  | expected_error = "Unable to read sequence number."; | 
|  | } else if (i < GetFecGroupOffset(!kIncludeVersion)) { | 
|  | expected_error = "Unable to read private flags."; | 
|  | } else { | 
|  | expected_error = "Unable to read first fec protected packet offset."; | 
|  | } | 
|  | CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeaderWith4ByteConnectionId) { | 
|  | QuicFramerPeer::SetLastSerializedConnectionId(&framer_, | 
|  | UINT64_C(0xFEDCBA9876543210)); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (4 byte connection_id) | 
|  | 0x38, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(UINT64_C(0xFEDCBA9876543210), | 
|  | visitor_.header_->public_header.connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.version_flag); | 
|  | EXPECT_FALSE(visitor_.header_->fec_flag); | 
|  | EXPECT_FALSE(visitor_.header_->entropy_flag); | 
|  | EXPECT_EQ(0, visitor_.header_->entropy_hash); | 
|  | EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number); | 
|  | EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); | 
|  | EXPECT_EQ(0x00u, visitor_.header_->fec_group); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = 0; | 
|  | i < GetPacketHeaderSize(PACKET_4BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); | 
|  | ++i) { | 
|  | string expected_error; | 
|  | if (i < kConnectionIdOffset) { | 
|  | expected_error = "Unable to read public flags."; | 
|  | } else if (i < GetSequenceNumberOffset(PACKET_4BYTE_CONNECTION_ID, | 
|  | !kIncludeVersion)) { | 
|  | expected_error = "Unable to read ConnectionId."; | 
|  | } else if (i < GetPrivateFlagsOffset(PACKET_4BYTE_CONNECTION_ID, | 
|  | !kIncludeVersion)) { | 
|  | expected_error = "Unable to read sequence number."; | 
|  | } else if (i < GetFecGroupOffset(PACKET_4BYTE_CONNECTION_ID, | 
|  | !kIncludeVersion)) { | 
|  | expected_error = "Unable to read private flags."; | 
|  | } else { | 
|  | expected_error = "Unable to read first fec protected packet offset."; | 
|  | } | 
|  | CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeader1ByteConnectionId) { | 
|  | QuicFramerPeer::SetLastSerializedConnectionId(&framer_, | 
|  | UINT64_C(0xFEDCBA9876543210)); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (1 byte connection_id) | 
|  | 0x34, | 
|  | // connection_id | 
|  | 0x10, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(UINT64_C(0xFEDCBA9876543210), | 
|  | visitor_.header_->public_header.connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.version_flag); | 
|  | EXPECT_FALSE(visitor_.header_->fec_flag); | 
|  | EXPECT_FALSE(visitor_.header_->entropy_flag); | 
|  | EXPECT_EQ(0, visitor_.header_->entropy_hash); | 
|  | EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number); | 
|  | EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); | 
|  | EXPECT_EQ(0x00u, visitor_.header_->fec_group); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = 0; | 
|  | i < GetPacketHeaderSize(PACKET_1BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); | 
|  | ++i) { | 
|  | string expected_error; | 
|  | if (i < kConnectionIdOffset) { | 
|  | expected_error = "Unable to read public flags."; | 
|  | } else if (i < GetSequenceNumberOffset(PACKET_1BYTE_CONNECTION_ID, | 
|  | !kIncludeVersion)) { | 
|  | expected_error = "Unable to read ConnectionId."; | 
|  | } else if (i < GetPrivateFlagsOffset(PACKET_1BYTE_CONNECTION_ID, | 
|  | !kIncludeVersion)) { | 
|  | expected_error = "Unable to read sequence number."; | 
|  | } else if (i < GetFecGroupOffset(PACKET_1BYTE_CONNECTION_ID, | 
|  | !kIncludeVersion)) { | 
|  | expected_error = "Unable to read private flags."; | 
|  | } else { | 
|  | expected_error = "Unable to read first fec protected packet offset."; | 
|  | } | 
|  | CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) { | 
|  | QuicFramerPeer::SetLastSerializedConnectionId(&framer_, | 
|  | UINT64_C(0xFEDCBA9876543210)); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (0 byte connection_id) | 
|  | 0x30, | 
|  | // connection_id | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(UINT64_C(0xFEDCBA9876543210), | 
|  | visitor_.header_->public_header.connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.version_flag); | 
|  | EXPECT_FALSE(visitor_.header_->fec_flag); | 
|  | EXPECT_FALSE(visitor_.header_->entropy_flag); | 
|  | EXPECT_EQ(0, visitor_.header_->entropy_hash); | 
|  | EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number); | 
|  | EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); | 
|  | EXPECT_EQ(0x00u, visitor_.header_->fec_group); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = 0; | 
|  | i < GetPacketHeaderSize(PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); | 
|  | ++i) { | 
|  | string expected_error; | 
|  | if (i < kConnectionIdOffset) { | 
|  | expected_error = "Unable to read public flags."; | 
|  | } else if (i < GetSequenceNumberOffset(PACKET_0BYTE_CONNECTION_ID, | 
|  | !kIncludeVersion)) { | 
|  | expected_error = "Unable to read ConnectionId."; | 
|  | } else if (i < GetPrivateFlagsOffset(PACKET_0BYTE_CONNECTION_ID, | 
|  | !kIncludeVersion)) { | 
|  | expected_error = "Unable to read sequence number."; | 
|  | } else if (i < GetFecGroupOffset(PACKET_0BYTE_CONNECTION_ID, | 
|  | !kIncludeVersion)) { | 
|  | expected_error = "Unable to read private flags."; | 
|  | } else { | 
|  | expected_error = "Unable to read first fec protected packet offset."; | 
|  | } | 
|  | CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (version) | 
|  | 0x3D, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // version tag | 
|  | 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(UINT64_C(0xFEDCBA9876543210), | 
|  | visitor_.header_->public_header.connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.reset_flag); | 
|  | EXPECT_TRUE(visitor_.header_->public_header.version_flag); | 
|  | EXPECT_EQ(GetParam(), 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); | 
|  | EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number); | 
|  | EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); | 
|  | EXPECT_EQ(0x00u, visitor_.header_->fec_group); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = 0; | 
|  | i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); | 
|  | ++i) { | 
|  | string expected_error; | 
|  | if (i < kConnectionIdOffset) { | 
|  | expected_error = "Unable to read public flags."; | 
|  | } else if (i < kVersionOffset) { | 
|  | expected_error = "Unable to read ConnectionId."; | 
|  | } else if (i <  GetSequenceNumberOffset(kIncludeVersion)) { | 
|  | expected_error = "Unable to read protocol version."; | 
|  | } else if (i < GetPrivateFlagsOffset(kIncludeVersion)) { | 
|  | expected_error = "Unable to read sequence number."; | 
|  | } else if (i < GetFecGroupOffset(kIncludeVersion)) { | 
|  | expected_error = "Unable to read private flags."; | 
|  | } else { | 
|  | expected_error = "Unable to read first fec protected packet offset."; | 
|  | } | 
|  | CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeaderWith4ByteSequenceNumber) { | 
|  | QuicFramerPeer::SetLastSequenceNumber(&framer_, UINT64_C(0x123456789ABA)); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id and 4 byte sequence number) | 
|  | 0x2C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | // private flags | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(UINT64_C(0xFEDCBA9876543210), | 
|  | visitor_.header_->public_header.connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.version_flag); | 
|  | EXPECT_FALSE(visitor_.header_->fec_flag); | 
|  | EXPECT_FALSE(visitor_.header_->entropy_flag); | 
|  | EXPECT_EQ(0, visitor_.header_->entropy_hash); | 
|  | EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number); | 
|  | EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); | 
|  | EXPECT_EQ(0x00u, visitor_.header_->fec_group); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = 0; | 
|  | i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_4BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); | 
|  | ++i) { | 
|  | string expected_error; | 
|  | if (i < kConnectionIdOffset) { | 
|  | expected_error = "Unable to read public flags."; | 
|  | } else if (i < GetSequenceNumberOffset(!kIncludeVersion)) { | 
|  | expected_error = "Unable to read ConnectionId."; | 
|  | } else if (i < GetPrivateFlagsOffset(!kIncludeVersion, | 
|  | PACKET_4BYTE_SEQUENCE_NUMBER)) { | 
|  | expected_error = "Unable to read sequence number."; | 
|  | } else if (i < GetFecGroupOffset(!kIncludeVersion, | 
|  | PACKET_4BYTE_SEQUENCE_NUMBER)) { | 
|  | expected_error = "Unable to read private flags."; | 
|  | } else { | 
|  | expected_error = "Unable to read first fec protected packet offset."; | 
|  | } | 
|  | CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeaderWith2ByteSequenceNumber) { | 
|  | QuicFramerPeer::SetLastSequenceNumber(&framer_, UINT64_C(0x123456789ABA)); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id and 2 byte sequence number) | 
|  | 0x1C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, | 
|  | // private flags | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(UINT64_C(0xFEDCBA9876543210), | 
|  | visitor_.header_->public_header.connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.version_flag); | 
|  | EXPECT_FALSE(visitor_.header_->fec_flag); | 
|  | EXPECT_FALSE(visitor_.header_->entropy_flag); | 
|  | EXPECT_EQ(0, visitor_.header_->entropy_hash); | 
|  | EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number); | 
|  | EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); | 
|  | EXPECT_EQ(0x00u, visitor_.header_->fec_group); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = 0; | 
|  | i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_2BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); | 
|  | ++i) { | 
|  | string expected_error; | 
|  | if (i < kConnectionIdOffset) { | 
|  | expected_error = "Unable to read public flags."; | 
|  | } else if (i < GetSequenceNumberOffset(!kIncludeVersion)) { | 
|  | expected_error = "Unable to read ConnectionId."; | 
|  | } else if (i < GetPrivateFlagsOffset(!kIncludeVersion, | 
|  | PACKET_2BYTE_SEQUENCE_NUMBER)) { | 
|  | expected_error = "Unable to read sequence number."; | 
|  | } else if (i < GetFecGroupOffset(!kIncludeVersion, | 
|  | PACKET_2BYTE_SEQUENCE_NUMBER)) { | 
|  | expected_error = "Unable to read private flags."; | 
|  | } else { | 
|  | expected_error = "Unable to read first fec protected packet offset."; | 
|  | } | 
|  | CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PacketHeaderWith1ByteSequenceNumber) { | 
|  | QuicFramerPeer::SetLastSequenceNumber(&framer_, UINT64_C(0x123456789ABA)); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id and 1 byte sequence number) | 
|  | 0x0C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, | 
|  | // private flags | 
|  | 0x00, | 
|  | }; | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_FALSE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(UINT64_C(0xFEDCBA9876543210), | 
|  | visitor_.header_->public_header.connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.version_flag); | 
|  | EXPECT_FALSE(visitor_.header_->fec_flag); | 
|  | EXPECT_FALSE(visitor_.header_->entropy_flag); | 
|  | EXPECT_EQ(0, visitor_.header_->entropy_hash); | 
|  | EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number); | 
|  | EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); | 
|  | EXPECT_EQ(0x00u, visitor_.header_->fec_group); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = 0; | 
|  | i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_1BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); | 
|  | ++i) { | 
|  | string expected_error; | 
|  | if (i < kConnectionIdOffset) { | 
|  | expected_error = "Unable to read public flags."; | 
|  | } else if (i < GetSequenceNumberOffset(!kIncludeVersion)) { | 
|  | expected_error = "Unable to read ConnectionId."; | 
|  | } else if (i < GetPrivateFlagsOffset(!kIncludeVersion, | 
|  | PACKET_1BYTE_SEQUENCE_NUMBER)) { | 
|  | expected_error = "Unable to read sequence number."; | 
|  | } else if (i < GetFecGroupOffset(!kIncludeVersion, | 
|  | PACKET_1BYTE_SEQUENCE_NUMBER)) { | 
|  | expected_error = "Unable to read private flags."; | 
|  | } else { | 
|  | expected_error = "Unable to read first fec protected packet offset."; | 
|  | } | 
|  | CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, InvalidPublicFlag) { | 
|  | unsigned char packet[] = { | 
|  | // public flags: all flags set but the public reset flag and version flag. | 
|  | 0xFC, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (padding) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | CheckProcessingFails(packet, | 
|  | arraysize(packet), | 
|  | "Illegal public flags value.", | 
|  | QUIC_INVALID_PACKET_HEADER); | 
|  |  | 
|  | // Now turn off validation. | 
|  | framer_.set_validate_flags(false); | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  | }; | 
|  |  | 
|  | TEST_P(QuicFramerTest, InvalidPublicFlagWithMatchingVersions) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id and version flag and an unknown flag) | 
|  | 0x4D, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // version tag | 
|  | 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (padding) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | CheckProcessingFails(packet, | 
|  | arraysize(packet), | 
|  | "Illegal public flags value.", | 
|  | QUIC_INVALID_PACKET_HEADER); | 
|  | }; | 
|  |  | 
|  | TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id, version flag and an unknown flag) | 
|  | 0x7D, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // version tag | 
|  | 'Q', '0', '0', '0', | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(0, visitor_.frame_count_); | 
|  | EXPECT_EQ(1, visitor_.version_mismatch_); | 
|  | }; | 
|  |  | 
|  | TEST_P(QuicFramerTest, InvalidPrivateFlag) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x10, | 
|  |  | 
|  | // frame type (padding) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  | CheckProcessingFails(packet, | 
|  | arraysize(packet), | 
|  | "Illegal private flags value.", | 
|  | QUIC_INVALID_PACKET_HEADER); | 
|  | }; | 
|  |  | 
|  | TEST_P(QuicFramerTest, InvalidFECGroupOffset) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 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 connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | // Ignored data (which in this case is a stream frame) | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // 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(0u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  | // A packet with no frames is not acceptable. | 
|  | CheckProcessingFails( | 
|  | packet, | 
|  | GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP), | 
|  | "Packet has no frames.", QUIC_MISSING_PAYLOAD); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StreamFrame) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 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) | 
|  | 0xFF, | 
|  | // 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(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | CheckStreamFrameBoundaries(packet, kQuicMaxStreamIdSize, !kIncludeVersion); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 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, | 
|  | // 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(UINT64_C(0x00020304), visitor_.stream_frames_[0]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[0]->fin); | 
|  | EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | const size_t stream_id_size = 3; | 
|  | CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 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) | 
|  | 0xFD, | 
|  | // 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(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | const size_t stream_id_size = 2; | 
|  | CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 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, | 
|  | // 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(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | const size_t stream_id_size = 1; | 
|  | CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StreamFrameWithVersion) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (version, 8 byte connection_id) | 
|  | 0x3D, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // version tag | 
|  | 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // 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_->public_header.version_flag); | 
|  | EXPECT_EQ(GetParam(), visitor_.header_->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(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | CheckStreamFrameBoundaries(packet, kQuicMaxStreamIdSize, kIncludeVersion); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, RejectPacket) { | 
|  | visitor_.accept_packet_ = false; | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 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) | 
|  | 0xFF, | 
|  | // 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(0u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, RejectPublicHeader) { | 
|  | visitor_.accept_public_header_ = false; | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | }; | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.public_header_.get()); | 
|  | ASSERT_FALSE(visitor_.header_.get()); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, RevivedStreamFrame) { | 
|  | unsigned char payload[] = { | 
|  | // frame type (stream frame with fin) | 
|  | 0xFF, | 
|  | // 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',  '!', | 
|  | }; | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210); | 
|  | header.public_header.reset_flag = false; | 
|  | header.public_header.version_flag = false; | 
|  | header.fec_flag = true; | 
|  | header.entropy_flag = true; | 
|  | header.packet_sequence_number = UINT64_C(0x123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | // Do not encrypt the payload because the revived payload is post-encryption. | 
|  | EXPECT_TRUE(framer_.ProcessRevivedPacket(&header, | 
|  | StringPiece(AsChars(payload), | 
|  | arraysize(payload)))); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_EQ(1, visitor_.revived_packets_); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_EQ(UINT64_C(0xFEDCBA9876543210), | 
|  | visitor_.header_->public_header.connection_id); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.reset_flag); | 
|  | EXPECT_FALSE(visitor_.header_->public_header.version_flag); | 
|  | EXPECT_TRUE(visitor_.header_->fec_flag); | 
|  | EXPECT_TRUE(visitor_.header_->entropy_flag); | 
|  | EXPECT_EQ(1 << (header.packet_sequence_number % 8), | 
|  | visitor_.header_->entropy_hash); | 
|  | EXPECT_EQ(UINT64_C(0x123456789ABC), visitor_.header_->packet_sequence_number); | 
|  | EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); | 
|  | EXPECT_EQ(0x00u, visitor_.header_->fec_group); | 
|  |  | 
|  | ASSERT_EQ(1u, visitor_.stream_frames_.size()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  | EXPECT_EQ(UINT64_C(0x01020304), visitor_.stream_frames_[0]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[0]->fin); | 
|  | EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StreamFrameInFecGroup) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 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) | 
|  | 0xFF, | 
|  | // 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(UINT64_C(0x341256789ABA), visitor_.header_->fec_group); | 
|  | const size_t fec_offset = | 
|  | GetStartOfFecProtectedData(PACKET_8BYTE_CONNECTION_ID, | 
|  | !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(UINT64_C(0x01020304), visitor_.stream_frames_[0]->stream_id); | 
|  | EXPECT_TRUE(visitor_.stream_frames_[0]->fin); | 
|  | EXPECT_EQ(UINT64_C(0xBA98FEDC32107654), visitor_.stream_frames_[0]->offset); | 
|  | CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, AckFrameTwoTimestamp) { | 
|  | 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. | 
|  | 0x00, 0x00, | 
|  | // 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(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(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) { | 
|  | 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 < 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) { | 
|  | 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. | 
|  | 0x00, 0x00, | 
|  | // 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(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(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) { | 
|  | 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. | 
|  | 0x00, 0x00, | 
|  | // 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(UINT64_C(0x0123456789ABF), frame.largest_observed); | 
|  | ASSERT_EQ(1u, frame.missing_packets.size()); | 
|  | SequenceNumberSet::const_iterator missing_iter = | 
|  | frame.missing_packets.begin(); | 
|  | EXPECT_EQ(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) { | 
|  | 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, AckFrameRevivedPackets) { | 
|  | 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. | 
|  | 0x00, 0x00, | 
|  | // num received packets. | 
|  | 0x00, | 
|  | // 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); | 
|  | 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(UINT64_C(0x0123456789ABF), frame.largest_observed); | 
|  | ASSERT_EQ(1u, frame.missing_packets.size()); | 
|  | SequenceNumberSet::const_iterator missing_iter = | 
|  | frame.missing_packets.begin(); | 
|  | EXPECT_EQ(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, AckFrameNoNacks) { | 
|  | 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. | 
|  | 0x00, 0x00, | 
|  | // Number of received 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(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 != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet), | 
|  | arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, AckFrame500Nacks) { | 
|  | 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. | 
|  | 0x00, 0x00, | 
|  | // No received packets. | 
|  | 0x00, | 
|  | // 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(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(UINT64_C(0x0123456789ABE) - 499, *first_missing_iter); | 
|  | SequenceNumberSet::const_reverse_iterator last_missing_iter = | 
|  | frame->missing_packets.rbegin(); | 
|  | EXPECT_EQ(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 != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, StopWaitingFrame) { | 
|  | 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) | 
|  | 0x06, | 
|  | // entropy hash of sent packets till least awaiting - 1. | 
|  | 0xAB, | 
|  | // least packet sequence number awaiting an ack, delta from sequence number. | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x00, | 
|  | }; | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  |  | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.header_.get()); | 
|  | EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); | 
|  |  | 
|  | EXPECT_EQ(0u, visitor_.stream_frames_.size()); | 
|  | ASSERT_EQ(1u, visitor_.stop_waiting_frames_.size()); | 
|  | const QuicStopWaitingFrame& frame = *visitor_.stop_waiting_frames_[0]; | 
|  | EXPECT_EQ(0xAB, frame.entropy_hash); | 
|  | EXPECT_EQ(UINT64_C(0x0123456789AA0), frame.least_unacked); | 
|  |  | 
|  | const size_t kSentEntropyOffset = kQuicFrameTypeSize; | 
|  | const size_t kLeastUnackedOffset = kSentEntropyOffset + kQuicEntropyHashSize; | 
|  | const size_t frame_size = 7; | 
|  | for (size_t i = kQuicFrameTypeSize; i < frame_size; ++i) { | 
|  | string expected_error; | 
|  | if (i < kLeastUnackedOffset) { | 
|  | expected_error = "Unable to read entropy hash for sent packets."; | 
|  | } else { | 
|  | expected_error = "Unable to read least unacked delta."; | 
|  | } | 
|  | CheckProcessingFails( | 
|  | packet, | 
|  | i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP), | 
|  | expected_error, QUIC_INVALID_STOP_WAITING_DATA); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, RstStreamFrameQuicVersion24) { | 
|  | if (version_ > QUIC_VERSION_24) { | 
|  | // QUIC_VERSION_25 removes the error_details field from QuicRstStreamFrame. | 
|  | return; | 
|  | } | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (rst stream frame) | 
|  | 0x01, | 
|  | // stream id | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  |  | 
|  | // sent byte offset | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  |  | 
|  | // error code | 
|  | 0x01, 0x00, 0x00, 0x00, | 
|  |  | 
|  | // error details length | 
|  | 0x0d, 0x00, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  |  | 
|  | 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(UINT64_C(0x01020304), visitor_.rst_stream_frame_.stream_id); | 
|  | EXPECT_EQ(0x01, visitor_.rst_stream_frame_.error_code); | 
|  | EXPECT_EQ("because I can", visitor_.rst_stream_frame_.error_details); | 
|  | EXPECT_EQ(UINT64_C(0x0807060504030201), | 
|  | visitor_.rst_stream_frame_.byte_offset); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = kQuicFrameTypeSize; | 
|  | i < QuicFramer::GetMinRstStreamFrameSize(); ++i) { | 
|  | string expected_error; | 
|  | if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) { | 
|  | expected_error = "Unable to read stream_id."; | 
|  | } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize + | 
|  | kQuicMaxStreamOffsetSize) { | 
|  | expected_error = "Unable to read rst stream sent byte offset."; | 
|  | } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize + | 
|  | kQuicMaxStreamOffsetSize + kQuicErrorCodeSize) { | 
|  | expected_error = "Unable to read rst stream error code."; | 
|  | } else { | 
|  | expected_error = "Unable to read rst stream error details."; | 
|  | } | 
|  | CheckProcessingFails( | 
|  | packet, | 
|  | i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP), | 
|  | expected_error, QUIC_INVALID_RST_STREAM_DATA); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, RstStreamFrameQuic) { | 
|  | if (version_ <= QUIC_VERSION_24) { | 
|  | // QUIC_VERSION_25 removes the error_details field from QuicRstStreamFrame. | 
|  | return; | 
|  | } | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (rst stream frame) | 
|  | 0x01, | 
|  | // stream id | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  |  | 
|  | // sent byte offset | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  |  | 
|  | // error code | 
|  | 0x01, 0x00, 0x00, 0x00, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | 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(UINT64_C(0x01020304), visitor_.rst_stream_frame_.stream_id); | 
|  | EXPECT_EQ(0x01, visitor_.rst_stream_frame_.error_code); | 
|  | EXPECT_EQ(UINT64_C(0x0807060504030201), | 
|  | visitor_.rst_stream_frame_.byte_offset); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetRstStreamFrameSize(); | 
|  | ++i) { | 
|  | string expected_error; | 
|  | if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) { | 
|  | expected_error = "Unable to read stream_id."; | 
|  | } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize + | 
|  | kQuicMaxStreamOffsetSize) { | 
|  | expected_error = "Unable to read rst stream sent byte offset."; | 
|  | } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize + | 
|  | kQuicMaxStreamOffsetSize + kQuicErrorCodeSize) { | 
|  | expected_error = "Unable to read rst stream error code."; | 
|  | } | 
|  | CheckProcessingFails( | 
|  | packet, | 
|  | i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP), | 
|  | expected_error, QUIC_INVALID_RST_STREAM_DATA); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, ConnectionCloseFrame) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (connection close frame) | 
|  | 0x02, | 
|  | // error code | 
|  | 0x11, 0x00, 0x00, 0x00, | 
|  |  | 
|  | // error details length | 
|  | 0x0d, 0x00, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  |  | 
|  | 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()); | 
|  |  | 
|  | EXPECT_EQ(0x11, visitor_.connection_close_frame_.error_code); | 
|  | EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details); | 
|  |  | 
|  | ASSERT_EQ(0u, visitor_.ack_frames_.size()); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = kQuicFrameTypeSize; | 
|  | i < QuicFramer::GetMinConnectionCloseFrameSize(); ++i) { | 
|  | string expected_error; | 
|  | if (i < kQuicFrameTypeSize + kQuicErrorCodeSize) { | 
|  | expected_error = "Unable to read connection close error code."; | 
|  | } else { | 
|  | expected_error = "Unable to read connection close error details."; | 
|  | } | 
|  | CheckProcessingFails( | 
|  | packet, | 
|  | i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP), | 
|  | expected_error, QUIC_INVALID_CONNECTION_CLOSE_DATA); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, GoAwayFrame) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (go away frame) | 
|  | 0x03, | 
|  | // error code | 
|  | 0x09, 0x00, 0x00, 0x00, | 
|  | // stream id | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  | // error details length | 
|  | 0x0d, 0x00, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  |  | 
|  | 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(UINT64_C(0x01020304), visitor_.goaway_frame_.last_good_stream_id); | 
|  | EXPECT_EQ(0x9, visitor_.goaway_frame_.error_code); | 
|  | EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase); | 
|  |  | 
|  | const size_t reason_size = arraysize("because I can") - 1; | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = kQuicFrameTypeSize; | 
|  | i < QuicFramer::GetMinGoAwayFrameSize() + reason_size; ++i) { | 
|  | string expected_error; | 
|  | if (i < kQuicFrameTypeSize + kQuicErrorCodeSize) { | 
|  | expected_error = "Unable to read go away error code."; | 
|  | } else if (i < kQuicFrameTypeSize + kQuicErrorCodeSize + | 
|  | kQuicMaxStreamIdSize) { | 
|  | expected_error = "Unable to read last good stream id."; | 
|  | } else { | 
|  | expected_error = "Unable to read goaway reason."; | 
|  | } | 
|  | CheckProcessingFails( | 
|  | packet, | 
|  | i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP), | 
|  | expected_error, QUIC_INVALID_GOAWAY_DATA); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, WindowUpdateFrame) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (window update frame) | 
|  | 0x04, | 
|  | // stream id | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  | // byte offset | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | 0x09, 0x0a, 0x0b, 0x0c, | 
|  | }; | 
|  |  | 
|  | 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(UINT64_C(0x01020304), visitor_.window_update_frame_.stream_id); | 
|  | EXPECT_EQ(UINT64_C(0x0c0b0a0908070605), | 
|  | visitor_.window_update_frame_.byte_offset); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = kQuicFrameTypeSize; | 
|  | i < QuicFramer::GetWindowUpdateFrameSize(); ++i) { | 
|  | string expected_error; | 
|  | if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) { | 
|  | expected_error = "Unable to read stream_id."; | 
|  | } else { | 
|  | expected_error = "Unable to read window byte_offset."; | 
|  | } | 
|  | CheckProcessingFails( | 
|  | packet, | 
|  | i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP), | 
|  | expected_error, QUIC_INVALID_WINDOW_UPDATE_DATA); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BlockedFrame) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (blocked frame) | 
|  | 0x05, | 
|  | // stream id | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  | }; | 
|  |  | 
|  | 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(UINT64_C(0x01020304), visitor_.blocked_frame_.stream_id); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetBlockedFrameSize(); | 
|  | ++i) { | 
|  | string expected_error = "Unable to read stream_id."; | 
|  | CheckProcessingFails( | 
|  | packet, | 
|  | i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP), | 
|  | expected_error, QUIC_INVALID_BLOCKED_DATA); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PingFrame) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (ping frame) | 
|  | 0x07, | 
|  | }; | 
|  |  | 
|  | 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(1u, visitor_.ping_frames_.size()); | 
|  |  | 
|  | // No need to check the PING frame boundaries because it has no payload. | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PublicResetPacket) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (public reset, 8 byte connection_id) | 
|  | 0x0E, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // message tag (kPRST) | 
|  | 'P', 'R', 'S', 'T', | 
|  | // num_entries (2) + padding | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | // tag kRNON | 
|  | 'R', 'N', 'O', 'N', | 
|  | // end offset 8 | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // tag kRSEQ | 
|  | 'R', 'S', 'E', 'Q', | 
|  | // end offset 16 | 
|  | 0x10, 0x00, 0x00, 0x00, | 
|  | // nonce proof | 
|  | 0x89, 0x67, 0x45, 0x23, | 
|  | 0x01, 0xEF, 0xCD, 0xAB, | 
|  | // rejected sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, 0x00, 0x00, | 
|  | }; | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  | ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.public_reset_packet_.get()); | 
|  | EXPECT_EQ(UINT64_C(0xFEDCBA9876543210), | 
|  | visitor_.public_reset_packet_->public_header.connection_id); | 
|  | EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag); | 
|  | EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag); | 
|  | EXPECT_EQ(UINT64_C(0xABCDEF0123456789), | 
|  | visitor_.public_reset_packet_->nonce_proof); | 
|  | EXPECT_EQ(UINT64_C(0x123456789ABC), | 
|  | visitor_.public_reset_packet_->rejected_sequence_number); | 
|  | EXPECT_TRUE( | 
|  | visitor_.public_reset_packet_->client_address.address().empty()); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = 0; i < arraysize(packet); ++i) { | 
|  | string expected_error; | 
|  | DVLOG(1) << "iteration: " << i; | 
|  | if (i < kConnectionIdOffset) { | 
|  | expected_error = "Unable to read public flags."; | 
|  | CheckProcessingFails(packet, i, expected_error, | 
|  | QUIC_INVALID_PACKET_HEADER); | 
|  | } else if (i < kPublicResetPacketMessageTagOffset) { | 
|  | expected_error = "Unable to read ConnectionId."; | 
|  | CheckProcessingFails(packet, i, expected_error, | 
|  | QUIC_INVALID_PACKET_HEADER); | 
|  | } else { | 
|  | expected_error = "Unable to read reset message."; | 
|  | CheckProcessingFails(packet, i, expected_error, | 
|  | QUIC_INVALID_PUBLIC_RST_PACKET); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PublicResetPacketWithTrailingJunk) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (public reset, 8 byte connection_id) | 
|  | 0x0E, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // message tag (kPRST) | 
|  | 'P', 'R', 'S', 'T', | 
|  | // num_entries (2) + padding | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | // tag kRNON | 
|  | 'R', 'N', 'O', 'N', | 
|  | // end offset 8 | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // tag kRSEQ | 
|  | 'R', 'S', 'E', 'Q', | 
|  | // end offset 16 | 
|  | 0x10, 0x00, 0x00, 0x00, | 
|  | // nonce proof | 
|  | 0x89, 0x67, 0x45, 0x23, | 
|  | 0x01, 0xEF, 0xCD, 0xAB, | 
|  | // rejected sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, 0x00, 0x00, | 
|  | // trailing junk | 
|  | 'j', 'u', 'n', 'k', | 
|  | }; | 
|  |  | 
|  | string expected_error = "Unable to read reset message."; | 
|  | CheckProcessingFails(packet, arraysize(packet), expected_error, | 
|  | QUIC_INVALID_PUBLIC_RST_PACKET); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, PublicResetPacketWithClientAddress) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (public reset, 8 byte connection_id) | 
|  | 0x0E, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // message tag (kPRST) | 
|  | 'P', 'R', 'S', 'T', | 
|  | // num_entries (3) + padding | 
|  | 0x03, 0x00, 0x00, 0x00, | 
|  | // tag kRNON | 
|  | 'R', 'N', 'O', 'N', | 
|  | // end offset 8 | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // tag kRSEQ | 
|  | 'R', 'S', 'E', 'Q', | 
|  | // end offset 16 | 
|  | 0x10, 0x00, 0x00, 0x00, | 
|  | // tag kCADR | 
|  | 'C', 'A', 'D', 'R', | 
|  | // end offset 24 | 
|  | 0x18, 0x00, 0x00, 0x00, | 
|  | // nonce proof | 
|  | 0x89, 0x67, 0x45, 0x23, | 
|  | 0x01, 0xEF, 0xCD, 0xAB, | 
|  | // rejected sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, 0x00, 0x00, | 
|  | // client address: 4.31.198.44:443 | 
|  | 0x02, 0x00, | 
|  | 0x04, 0x1F, 0xC6, 0x2C, | 
|  | 0xBB, 0x01, | 
|  | }; | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  | ASSERT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | ASSERT_TRUE(visitor_.public_reset_packet_.get()); | 
|  | EXPECT_EQ(UINT64_C(0xFEDCBA9876543210), | 
|  | visitor_.public_reset_packet_->public_header.connection_id); | 
|  | EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag); | 
|  | EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag); | 
|  | EXPECT_EQ(UINT64_C(0xABCDEF0123456789), | 
|  | visitor_.public_reset_packet_->nonce_proof); | 
|  | EXPECT_EQ(UINT64_C(0x123456789ABC), | 
|  | visitor_.public_reset_packet_->rejected_sequence_number); | 
|  | EXPECT_EQ("4.31.198.44", | 
|  | IPAddressToString(visitor_.public_reset_packet_-> | 
|  | client_address.address())); | 
|  | EXPECT_EQ(443, visitor_.public_reset_packet_->client_address.port()); | 
|  |  | 
|  | // Now test framing boundaries. | 
|  | for (size_t i = 0; i < arraysize(packet); ++i) { | 
|  | string expected_error; | 
|  | DVLOG(1) << "iteration: " << i; | 
|  | if (i < kConnectionIdOffset) { | 
|  | expected_error = "Unable to read public flags."; | 
|  | CheckProcessingFails(packet, i, expected_error, | 
|  | QUIC_INVALID_PACKET_HEADER); | 
|  | } else if (i < kPublicResetPacketMessageTagOffset) { | 
|  | expected_error = "Unable to read ConnectionId."; | 
|  | CheckProcessingFails(packet, i, expected_error, | 
|  | QUIC_INVALID_PACKET_HEADER); | 
|  | } else { | 
|  | expected_error = "Unable to read reset message."; | 
|  | CheckProcessingFails(packet, i, expected_error, | 
|  | QUIC_INVALID_PUBLIC_RST_PACKET); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, VersionNegotiationPacket) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (version, 8 byte connection_id) | 
|  | 0x3D, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // version tag | 
|  | 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), | 
|  | 'Q', '2', '.', '0', | 
|  | }; | 
|  |  | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  | 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(GetParam(), visitor_.version_negotiation_packet_->versions[0]); | 
|  |  | 
|  | for (size_t i = 0; i <= kPublicFlagsSize + PACKET_8BYTE_CONNECTION_ID; ++i) { | 
|  | string expected_error; | 
|  | QuicErrorCode error_code = QUIC_INVALID_PACKET_HEADER; | 
|  | if (i < kConnectionIdOffset) { | 
|  | expected_error = "Unable to read public flags."; | 
|  | } else if (i < kVersionOffset) { | 
|  | expected_error = "Unable to read ConnectionId."; | 
|  | } else { | 
|  | expected_error = "Unable to read supported version in negotiation."; | 
|  | error_code = QUIC_INVALID_VERSION_NEGOTIATION_PACKET; | 
|  | } | 
|  | CheckProcessingFails(packet, i, expected_error, error_code); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, FecPacket) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags (fec group & FEC) | 
|  | 0x06, | 
|  | // first fec protected packet offset | 
|  | 0x01, | 
|  |  | 
|  | // redundancy | 
|  | 'a',  'b',  'c',  'd', | 
|  | 'e',  'f',  'g',  'h', | 
|  | 'i',  'j',  'k',  'l', | 
|  | 'm',  'n',  'o',  'p', | 
|  | }; | 
|  |  | 
|  | 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()); | 
|  | EXPECT_EQ(0u, visitor_.ack_frames_.size()); | 
|  | ASSERT_EQ(1, visitor_.fec_count_); | 
|  | const QuicFecData& fec_data = *visitor_.fec_data_[0]; | 
|  | EXPECT_EQ(UINT64_C(0x0123456789ABB), fec_data.fec_group); | 
|  | EXPECT_EQ("abcdefghijklmnop", fec_data.redundancy); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildPaddingFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = UINT64_C(0x123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicPaddingFrame padding_frame; | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&padding_frame)); | 
|  |  | 
|  | unsigned char packet[kMaxPacketSize] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | uint64 header_size = | 
|  | GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); | 
|  | memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), | 
|  | arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210); | 
|  | header.public_header.reset_flag = false; | 
|  | header.public_header.version_flag = false; | 
|  | header.fec_flag = false; | 
|  | header.entropy_flag = false; | 
|  | header.public_header.sequence_number_length = PACKET_4BYTE_SEQUENCE_NUMBER; | 
|  | header.packet_sequence_number = UINT64_C(0x123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicPaddingFrame padding_frame; | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&padding_frame)); | 
|  |  | 
|  | unsigned char packet[kMaxPacketSize] = { | 
|  | // public flags (8 byte connection_id and 4 byte sequence number) | 
|  | 0x2C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | uint64 header_size = | 
|  | GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_4BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); | 
|  | memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), | 
|  | arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210); | 
|  | header.public_header.reset_flag = false; | 
|  | header.public_header.version_flag = false; | 
|  | header.fec_flag = false; | 
|  | header.entropy_flag = false; | 
|  | header.public_header.sequence_number_length = PACKET_2BYTE_SEQUENCE_NUMBER; | 
|  | header.packet_sequence_number = UINT64_C(0x123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicPaddingFrame padding_frame; | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&padding_frame)); | 
|  |  | 
|  | unsigned char packet[kMaxPacketSize] = { | 
|  | // public flags (8 byte connection_id and 2 byte sequence number) | 
|  | 0x1C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | uint64 header_size = | 
|  | GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_2BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); | 
|  | memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), | 
|  | arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210); | 
|  | header.public_header.reset_flag = false; | 
|  | header.public_header.version_flag = false; | 
|  | header.fec_flag = false; | 
|  | header.entropy_flag = false; | 
|  | header.public_header.sequence_number_length = PACKET_1BYTE_SEQUENCE_NUMBER; | 
|  | header.packet_sequence_number = UINT64_C(0x123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicPaddingFrame padding_frame; | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&padding_frame)); | 
|  |  | 
|  | unsigned char packet[kMaxPacketSize] = { | 
|  | // public flags (8 byte connection_id and 1 byte sequence number) | 
|  | 0x0C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (padding frame) | 
|  | 0x00, | 
|  | 0x00, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | uint64 header_size = | 
|  | GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, | 
|  | PACKET_1BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP); | 
|  | memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), | 
|  | arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildStreamFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = UINT64_C(0x77123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicStreamFrame stream_frame; | 
|  | stream_frame.stream_id = 0x01020304; | 
|  | stream_frame.fin = true; | 
|  | stream_frame.offset = UINT64_C(0xBA98FEDC32107654); | 
|  | stream_frame.data = MakeIOVector("hello world!"); | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&stream_frame)); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 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) | 
|  | 0xDF, | 
|  | // 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(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildStreamFramePacketInFecGroup) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = UINT64_C(0x77123456789ABC); | 
|  | header.is_in_fec_group = IN_FEC_GROUP; | 
|  | header.fec_group = UINT64_C(0x77123456789ABC); | 
|  |  | 
|  | QuicStreamFrame stream_frame; | 
|  | stream_frame.stream_id = 0x01020304; | 
|  | stream_frame.fin = true; | 
|  | stream_frame.offset = UINT64_C(0xBA98FEDC32107654); | 
|  | stream_frame.data = MakeIOVector("hello world!"); | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&stream_frame)); | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, | 
|  | // private flags (entropy, is_in_fec_group) | 
|  | 0x03, | 
|  | // FEC group | 
|  | 0x00, | 
|  | // frame type (stream frame with fin and data length field) | 
|  | 0xFF, | 
|  | // stream id | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  | // offset | 
|  | 0x54, 0x76, 0x10, 0x32, 0xDC, 0xFE, 0x98, 0xBA, | 
|  | // data length (since packet is in an FEC group) | 
|  | 0x0C, 0x00, | 
|  | // data | 
|  | 'h',  'e',  'l',  'l',  'o',  ' ',  'w',  'o',  'r', 'l', 'd', '!', | 
|  | }; | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210); | 
|  | header.public_header.reset_flag = false; | 
|  | header.public_header.version_flag = true; | 
|  | header.fec_flag = false; | 
|  | header.entropy_flag = true; | 
|  | header.packet_sequence_number = UINT64_C(0x77123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicStreamFrame stream_frame; | 
|  | stream_frame.stream_id = 0x01020304; | 
|  | stream_frame.fin = true; | 
|  | stream_frame.offset = UINT64_C(0xBA98FEDC32107654); | 
|  | stream_frame.data = MakeIOVector("hello world!"); | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&stream_frame)); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (version, 8 byte connection_id) | 
|  | 0x3D, | 
|  | // connection_id | 
|  | 0x10, | 
|  | 0x32, | 
|  | 0x54, | 
|  | 0x76, | 
|  | 0x98, | 
|  | 0xBA, | 
|  | 0xDC, | 
|  | 0xFE, | 
|  | // version tag | 
|  | 'Q', | 
|  | '0', | 
|  | GetQuicVersionDigitTens(), | 
|  | GetQuicVersionDigitOnes(), | 
|  | // packet sequence number | 
|  | 0xBC, | 
|  | 0x9A, | 
|  | 0x78, | 
|  | 0x56, | 
|  | 0x34, | 
|  | 0x12, | 
|  | // private flags (entropy) | 
|  | 0x01, | 
|  |  | 
|  | // frame type (stream frame with fin and no length) | 
|  | 0xDF, | 
|  | // 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', | 
|  | '!', | 
|  | }; | 
|  |  | 
|  | QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) { | 
|  | QuicPacketPublicHeader header; | 
|  | header.connection_id = UINT64_C(0xFEDCBA9876543210); | 
|  | header.reset_flag = false; | 
|  | header.version_flag = true; | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (version, 8 byte connection_id) | 
|  | 0x0D, | 
|  | // connection_id | 
|  | 0x10, | 
|  | 0x32, | 
|  | 0x54, | 
|  | 0x76, | 
|  | 0x98, | 
|  | 0xBA, | 
|  | 0xDC, | 
|  | 0xFE, | 
|  | // version tag | 
|  | 'Q', | 
|  | '0', | 
|  | GetQuicVersionDigitTens(), | 
|  | GetQuicVersionDigitOnes(), | 
|  | }; | 
|  |  | 
|  | QuicVersionVector versions; | 
|  | versions.push_back(GetParam()); | 
|  | scoped_ptr<QuicEncryptedPacket> data( | 
|  | framer_.BuildVersionNegotiationPacket(header, versions)); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet), | 
|  | arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildAckFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = UINT64_C(0x770123456789AA8); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicAckFrame ack_frame; | 
|  | ack_frame.entropy_hash = 0x43; | 
|  | ack_frame.largest_observed = UINT64_C(0x770123456789ABF); | 
|  | ack_frame.delta_time_largest_observed = QuicTime::Delta::Zero(); | 
|  | ack_frame.missing_packets.insert(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. | 
|  | 0x00, 0x00, | 
|  | // num received packets. | 
|  | 0x00, | 
|  | // 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 != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), arraysize(packet)); | 
|  | } | 
|  |  | 
|  | // 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, BuildTruncatedAckFrameLargePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = 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. | 
|  | 0x00, 0x00, | 
|  | // 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(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = 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. | 
|  | 0x00, 0x00, | 
|  | // 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(BuildDataPacket(header, frames, 37u)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  | // 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, BuildStopWaitingPacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = UINT64_C(0x770123456789AA8); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicStopWaitingFrame stop_waiting_frame; | 
|  | stop_waiting_frame.entropy_hash = 0x14; | 
|  | stop_waiting_frame.least_unacked = UINT64_C(0x770123456789AA0); | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&stop_waiting_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 (stop waiting frame) | 
|  | 0x06, | 
|  | // entropy hash of sent packets till least awaiting - 1. | 
|  | 0x14, | 
|  | // least packet sequence number awaiting an ack, delta from sequence number. | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x00, | 
|  | }; | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildRstFramePacketQuicVersion24) { | 
|  | if (version_ > QUIC_VERSION_24) { | 
|  | // QUIC_VERSION_25 removes the error_details field from QuicRstStreamFrame. | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = UINT64_C(0x123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicRstStreamFrame rst_frame; | 
|  | rst_frame.stream_id = 0x01020304; | 
|  | rst_frame.error_code = static_cast<QuicRstStreamErrorCode>(0x05060708); | 
|  | rst_frame.error_details = "because I can"; | 
|  | rst_frame.byte_offset = 0x0807060504030201; | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (rst stream frame) | 
|  | 0x01, | 
|  | // stream id | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  | // sent byte offset | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // error code | 
|  | 0x08, 0x07, 0x06, 0x05, | 
|  | // error details length | 
|  | 0x0d, 0x00, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&rst_frame)); | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet), | 
|  | arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildRstFramePacketQuic) { | 
|  | if (version_ <= QUIC_VERSION_24) { | 
|  | // QUIC_VERSION_25 removes the error_details field from QuicRstStreamFrame. | 
|  | return; | 
|  | } | 
|  |  | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = UINT64_C(0x123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicRstStreamFrame rst_frame; | 
|  | rst_frame.stream_id = 0x01020304; | 
|  | rst_frame.error_code = static_cast<QuicRstStreamErrorCode>(0x05060708); | 
|  | rst_frame.byte_offset = 0x0807060504030201; | 
|  |  | 
|  | // clang-format off | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags | 
|  | 0x00, | 
|  |  | 
|  | // frame type (rst stream frame) | 
|  | 0x01, | 
|  | // stream id | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  | // sent byte offset | 
|  | 0x01, 0x02, 0x03, 0x04, | 
|  | 0x05, 0x06, 0x07, 0x08, | 
|  | // error code | 
|  | 0x08, 0x07, 0x06, 0x05, | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&rst_frame)); | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet), | 
|  | arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildCloseFramePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = UINT64_C(0x123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicConnectionCloseFrame close_frame; | 
|  | close_frame.error_code = static_cast<QuicErrorCode>(0x05060708); | 
|  | close_frame.error_details = "because I can"; | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&close_frame)); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags (entropy) | 
|  | 0x01, | 
|  |  | 
|  | // frame type (connection close frame) | 
|  | 0x02, | 
|  | // error code | 
|  | 0x08, 0x07, 0x06, 0x05, | 
|  | // error details length | 
|  | 0x0d, 0x00, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildGoAwayPacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = UINT64_C(0x123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicGoAwayFrame goaway_frame; | 
|  | goaway_frame.error_code = static_cast<QuicErrorCode>(0x05060708); | 
|  | goaway_frame.last_good_stream_id = 0x01020304; | 
|  | goaway_frame.reason_phrase = "because I can"; | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&goaway_frame)); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags(entropy) | 
|  | 0x01, | 
|  |  | 
|  | // frame type (go away frame) | 
|  | 0x03, | 
|  | // error code | 
|  | 0x08, 0x07, 0x06, 0x05, | 
|  | // stream id | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  | // error details length | 
|  | 0x0d, 0x00, | 
|  | // error details | 
|  | 'b',  'e',  'c',  'a', | 
|  | 'u',  's',  'e',  ' ', | 
|  | 'I',  ' ',  'c',  'a', | 
|  | 'n', | 
|  | }; | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildWindowUpdatePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = UINT64_C(0x123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicWindowUpdateFrame window_update_frame; | 
|  | window_update_frame.stream_id = 0x01020304; | 
|  | window_update_frame.byte_offset = 0x1122334455667788; | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&window_update_frame)); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags(entropy) | 
|  | 0x01, | 
|  |  | 
|  | // frame type (window update frame) | 
|  | 0x04, | 
|  | // stream id | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  | // byte offset | 
|  | 0x88, 0x77, 0x66, 0x55, | 
|  | 0x44, 0x33, 0x22, 0x11, | 
|  | }; | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet), | 
|  | arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildBlockedPacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = UINT64_C(0x123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicBlockedFrame blocked_frame; | 
|  | blocked_frame.stream_id = 0x01020304; | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&blocked_frame)); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags(entropy) | 
|  | 0x01, | 
|  |  | 
|  | // frame type (blocked frame) | 
|  | 0x05, | 
|  | // stream id | 
|  | 0x04, 0x03, 0x02, 0x01, | 
|  | }; | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet), | 
|  | arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildPingPacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = UINT64_C(0x123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicPingFrame ping_frame; | 
|  |  | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&ping_frame)); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags(entropy) | 
|  | 0x01, | 
|  |  | 
|  | // frame type (ping frame) | 
|  | 0x07, | 
|  | }; | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", data->data(), | 
|  | data->length(), AsChars(packet), | 
|  | arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildPublicResetPacket) { | 
|  | QuicPublicResetPacket reset_packet; | 
|  | reset_packet.public_header.connection_id = UINT64_C(0xFEDCBA9876543210); | 
|  | reset_packet.public_header.reset_flag = true; | 
|  | reset_packet.public_header.version_flag = false; | 
|  | reset_packet.rejected_sequence_number = UINT64_C(0x123456789ABC); | 
|  | reset_packet.nonce_proof = UINT64_C(0xABCDEF0123456789); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (public reset, 8 byte ConnectionId) | 
|  | 0x0E, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // message tag (kPRST) | 
|  | 'P', 'R', 'S', 'T', | 
|  | // num_entries (2) + padding | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | // tag kRNON | 
|  | 'R', 'N', 'O', 'N', | 
|  | // end offset 8 | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // tag kRSEQ | 
|  | 'R', 'S', 'E', 'Q', | 
|  | // end offset 16 | 
|  | 0x10, 0x00, 0x00, 0x00, | 
|  | // nonce proof | 
|  | 0x89, 0x67, 0x45, 0x23, | 
|  | 0x01, 0xEF, 0xCD, 0xAB, | 
|  | // rejected sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, 0x00, 0x00, | 
|  | }; | 
|  |  | 
|  | scoped_ptr<QuicEncryptedPacket> data( | 
|  | framer_.BuildPublicResetPacket(reset_packet)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildPublicResetPacketWithClientAddress) { | 
|  | QuicPublicResetPacket reset_packet; | 
|  | reset_packet.public_header.connection_id = UINT64_C(0xFEDCBA9876543210); | 
|  | reset_packet.public_header.reset_flag = true; | 
|  | reset_packet.public_header.version_flag = false; | 
|  | reset_packet.rejected_sequence_number = UINT64_C(0x123456789ABC); | 
|  | reset_packet.nonce_proof = UINT64_C(0xABCDEF0123456789); | 
|  | reset_packet.client_address = IPEndPoint(Loopback4(), 0x1234); | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (public reset, 8 byte ConnectionId) | 
|  | 0x0E, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // message tag (kPRST) | 
|  | 'P', 'R', 'S', 'T', | 
|  | // num_entries (3) + padding | 
|  | 0x03, 0x00, 0x00, 0x00, | 
|  | // tag kRNON | 
|  | 'R', 'N', 'O', 'N', | 
|  | // end offset 8 | 
|  | 0x08, 0x00, 0x00, 0x00, | 
|  | // tag kRSEQ | 
|  | 'R', 'S', 'E', 'Q', | 
|  | // end offset 16 | 
|  | 0x10, 0x00, 0x00, 0x00, | 
|  | // tag kCADR | 
|  | 'C', 'A', 'D', 'R', | 
|  | // end offset 24 | 
|  | 0x18, 0x00, 0x00, 0x00, | 
|  | // nonce proof | 
|  | 0x89, 0x67, 0x45, 0x23, | 
|  | 0x01, 0xEF, 0xCD, 0xAB, | 
|  | // rejected sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, 0x00, 0x00, | 
|  | // client address | 
|  | 0x02, 0x00, | 
|  | 0x7F, 0x00, 0x00, 0x01, | 
|  | 0x34, 0x12, | 
|  | }; | 
|  |  | 
|  | scoped_ptr<QuicEncryptedPacket> data( | 
|  | framer_.BuildPublicResetPacket(reset_packet)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, BuildFecPacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = UINT64_C(0xFEDCBA9876543210); | 
|  | header.public_header.reset_flag = false; | 
|  | header.public_header.version_flag = false; | 
|  | header.fec_flag = true; | 
|  | header.entropy_flag = true; | 
|  | header.packet_sequence_number = (UINT64_C(0x123456789ABC)); | 
|  | header.is_in_fec_group = IN_FEC_GROUP; | 
|  | header.fec_group = UINT64_C(0x123456789ABB); | 
|  | ; | 
|  |  | 
|  | QuicFecData fec_data; | 
|  | fec_data.fec_group = 1; | 
|  | fec_data.redundancy = "abcdefghijklmnop"; | 
|  |  | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags (entropy & fec group & fec packet) | 
|  | 0x07, | 
|  | // first fec protected packet offset | 
|  | 0x01, | 
|  |  | 
|  | // redundancy | 
|  | 'a',  'b',  'c',  'd', | 
|  | 'e',  'f',  'g',  'h', | 
|  | 'i',  'j',  'k',  'l', | 
|  | 'm',  'n',  'o',  'p', | 
|  | }; | 
|  |  | 
|  | scoped_ptr<QuicPacket> data(framer_.BuildFecPacket(header, fec_data)); | 
|  | ASSERT_TRUE(data != nullptr); | 
|  |  | 
|  | test::CompareCharArraysWithHexError("constructed packet", | 
|  | data->data(), data->length(), | 
|  | AsChars(packet), arraysize(packet)); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, EncryptPacket) { | 
|  | QuicPacketSequenceNumber sequence_number = UINT64_C(0x123456789ABC); | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags (fec group & fec packet) | 
|  | 0x06, | 
|  | // first fec protected packet offset | 
|  | 0x01, | 
|  |  | 
|  | // redundancy | 
|  | 'a',  'b',  'c',  'd', | 
|  | 'e',  'f',  'g',  'h', | 
|  | 'i',  'j',  'k',  'l', | 
|  | 'm',  'n',  'o',  'p', | 
|  | }; | 
|  |  | 
|  | scoped_ptr<QuicPacket> raw(new QuicPacket( | 
|  | AsChars(packet), arraysize(packet), false, PACKET_8BYTE_CONNECTION_ID, | 
|  | !kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER)); | 
|  | char buffer[kMaxPacketSize]; | 
|  | scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket( | 
|  | ENCRYPTION_NONE, sequence_number, *raw, buffer, kMaxPacketSize)); | 
|  |  | 
|  | ASSERT_TRUE(encrypted.get() != nullptr); | 
|  | EXPECT_TRUE(CheckEncryption(sequence_number, raw.get())); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) { | 
|  | QuicPacketSequenceNumber sequence_number = UINT64_C(0x123456789ABC); | 
|  | unsigned char packet[] = { | 
|  | // public flags (version, 8 byte connection_id) | 
|  | 0x3D, | 
|  | // connection_id | 
|  | 0x10, 0x32, 0x54, 0x76, | 
|  | 0x98, 0xBA, 0xDC, 0xFE, | 
|  | // version tag | 
|  | 'Q', '.', '1', '0', | 
|  | // packet sequence number | 
|  | 0xBC, 0x9A, 0x78, 0x56, | 
|  | 0x34, 0x12, | 
|  | // private flags (fec group & fec flags) | 
|  | 0x06, | 
|  | // first fec protected packet offset | 
|  | 0x01, | 
|  |  | 
|  | // redundancy | 
|  | 'a',  'b',  'c',  'd', | 
|  | 'e',  'f',  'g',  'h', | 
|  | 'i',  'j',  'k',  'l', | 
|  | 'm',  'n',  'o',  'p', | 
|  | }; | 
|  |  | 
|  | scoped_ptr<QuicPacket> raw(new QuicPacket( | 
|  | AsChars(packet), arraysize(packet), false, PACKET_8BYTE_CONNECTION_ID, | 
|  | kIncludeVersion, PACKET_6BYTE_SEQUENCE_NUMBER)); | 
|  | char buffer[kMaxPacketSize]; | 
|  | scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket( | 
|  | ENCRYPTION_NONE, sequence_number, *raw, buffer, kMaxPacketSize)); | 
|  |  | 
|  | ASSERT_TRUE(encrypted.get() != nullptr); | 
|  | EXPECT_TRUE(CheckEncryption(sequence_number, raw.get())); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, AckTruncationLargePacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = 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(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(raw_ack_packet != nullptr); | 
|  | char buffer[kMaxPacketSize]; | 
|  | scoped_ptr<QuicEncryptedPacket> ack_packet( | 
|  | framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number, | 
|  | *raw_ack_packet, buffer, kMaxPacketSize)); | 
|  | // 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(510u, processed_ack_frame.largest_observed); | 
|  | ASSERT_EQ(255u, 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(509u, *last_missing_iter); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, AckTruncationSmallPacket) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = 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(BuildDataPacket(header, frames, 500)); | 
|  | ASSERT_TRUE(raw_ack_packet != nullptr); | 
|  | char buffer[kMaxPacketSize]; | 
|  | scoped_ptr<QuicEncryptedPacket> ack_packet( | 
|  | framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number, | 
|  | *raw_ack_packet, buffer, kMaxPacketSize)); | 
|  | // 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, CleanTruncation) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = 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 = UINT64_C(0x123456789ABC); | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicAckFrame ack_frame; | 
|  | ack_frame.largest_observed = 201; | 
|  | for (uint64 i = 1; i < ack_frame.largest_observed; ++i) { | 
|  | ack_frame.missing_packets.insert(i); | 
|  | } | 
|  |  | 
|  | // Create a packet with just the ack. | 
|  | QuicFrame frame; | 
|  | frame.type = ACK_FRAME; | 
|  | frame.ack_frame = &ack_frame; | 
|  | QuicFrames frames; | 
|  | frames.push_back(frame); | 
|  |  | 
|  | scoped_ptr<QuicPacket> raw_ack_packet(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(raw_ack_packet != nullptr); | 
|  |  | 
|  | char buffer[kMaxPacketSize]; | 
|  | scoped_ptr<QuicEncryptedPacket> ack_packet( | 
|  | framer_.EncryptPacket(ENCRYPTION_NONE, header.packet_sequence_number, | 
|  | *raw_ack_packet, buffer, kMaxPacketSize)); | 
|  |  | 
|  | // Now make sure we can turn our ack packet back into an ack frame. | 
|  | ASSERT_TRUE(framer_.ProcessPacket(*ack_packet)); | 
|  |  | 
|  | // Test for clean truncation of the ack by comparing the length of the | 
|  | // original packets to the re-serialized packets. | 
|  | frames.clear(); | 
|  | frame.type = ACK_FRAME; | 
|  | frame.ack_frame = visitor_.ack_frames_[0]; | 
|  | frames.push_back(frame); | 
|  |  | 
|  | size_t original_raw_length = raw_ack_packet->length(); | 
|  | raw_ack_packet.reset(BuildDataPacket(header, frames)); | 
|  | ASSERT_TRUE(raw_ack_packet != nullptr); | 
|  | EXPECT_EQ(original_raw_length, raw_ack_packet->length()); | 
|  | ASSERT_TRUE(raw_ack_packet != nullptr); | 
|  | } | 
|  |  | 
|  | TEST_P(QuicFramerTest, EntropyFlagTest) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 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) | 
|  | 0xDF, | 
|  | // 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, FecEntropyTest) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 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) | 
|  | 0xDF, | 
|  | // 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, StopPacketProcessing) { | 
|  | unsigned char packet[] = { | 
|  | // public flags (8 byte connection_id) | 
|  | 0x3C, | 
|  | // connection_id | 
|  | 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) | 
|  | 0xFF, | 
|  | // 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) | 
|  | 0x40, | 
|  | // 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()); | 
|  | EXPECT_CALL(visitor, OnUnauthenticatedPublicHeader(_)).WillOnce(Return(true)); | 
|  | EXPECT_CALL(visitor, OnUnauthenticatedHeader(_)).WillOnce(Return(true)); | 
|  | EXPECT_CALL(visitor, OnDecryptedPacket(_)); | 
|  |  | 
|  | QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); | 
|  | EXPECT_TRUE(framer_.ProcessPacket(encrypted)); | 
|  | EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
|  | } | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace net |