| Index: net/quic/quic_framer_test.cc | 
| diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..ae14d5d61a69d94a03303153b6325a7a069ca8bf | 
| --- /dev/null | 
| +++ b/net/quic/quic_framer_test.cc | 
| @@ -0,0 +1,2057 @@ | 
| +// 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 <algorithm> | 
| +#include <vector> | 
| + | 
| +#include "base/hash_tables.h" | 
| +#include "base/logging.h" | 
| +#include "base/memory/scoped_ptr.h" | 
| +#include "base/stl_util.h" | 
| +#include "net/quic/quic_framer.h" | 
| +#include "net/quic/quic_protocol.h" | 
| +#include "net/quic/quic_utils.h" | 
| +#include "net/quic/test_tools/quic_test_utils.h" | 
| + | 
| +using base::hash_set; | 
| +using base::StringPiece; | 
| +using std::string; | 
| +using std::vector; | 
| + | 
| +namespace net { | 
| + | 
| +namespace test { | 
| + | 
| +class TestEncrypter : public QuicEncrypter { | 
| + public: | 
| +  virtual ~TestEncrypter() {} | 
| +  virtual QuicData* Encrypt(StringPiece associated_data, | 
| +                            StringPiece plaintext) { | 
| +    associated_data_ = associated_data.as_string(); | 
| +    plaintext_ = plaintext.as_string(); | 
| +    return new QuicData(plaintext.data(), plaintext.length()); | 
| +  } | 
| +  virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) { | 
| +    return ciphertext_size; | 
| +  } | 
| +  virtual size_t GetCiphertextSize(size_t plaintext_size) { | 
| +    return plaintext_size; | 
| +  } | 
| +  string associated_data_; | 
| +  string plaintext_; | 
| +}; | 
| + | 
| +class TestDecrypter : public QuicDecrypter { | 
| + public: | 
| +  virtual ~TestDecrypter() {} | 
| +  virtual QuicData* Decrypt(StringPiece associated_data, | 
| +                            StringPiece ciphertext) { | 
| +    associated_data_ = associated_data.as_string(); | 
| +    ciphertext_ = ciphertext.as_string(); | 
| +    return new QuicData(ciphertext.data(), ciphertext.length()); | 
| +  } | 
| +  string associated_data_; | 
| +  string ciphertext_; | 
| +}; | 
| + | 
| +// The offset of congestion info in our tests, given the size of our usual ack | 
| +// fragment.  This does NOT work for all packets. | 
| +const int kCongestionInfoOffset = kPacketHeaderSize + 54; | 
| + | 
| +class TestQuicVisitor : public ::net::QuicFramerVisitorInterface { | 
| + public: | 
| +  TestQuicVisitor() | 
| +      : error_count_(0), | 
| +        packet_count_(0), | 
| +        fragment_count_(0), | 
| +        fec_count_(0), | 
| +        complete_packets_(0), | 
| +        accept_packet_(true) { | 
| +  } | 
| + | 
| +  ~TestQuicVisitor() { | 
| +    STLDeleteElements(&stream_fragments_); | 
| +    STLDeleteElements(&ack_fragments_); | 
| +    STLDeleteElements(&fec_data_); | 
| +  } | 
| + | 
| +  virtual void OnError(QuicFramer* f) { | 
| +    DLOG(INFO) << "QuicFramer Error: " << QuicUtils::ErrorToString(f->error()) | 
| +               << " (" << f->error() << ")"; | 
| +    error_count_++; | 
| +  } | 
| + | 
| +  virtual void OnPacket(const IPEndPoint& client_address) { | 
| +    address_ = client_address; | 
| +  } | 
| + | 
| +  virtual bool OnPacketHeader(const QuicPacketHeader& header) { | 
| +    packet_count_++; | 
| +    header_.reset(new QuicPacketHeader(header)); | 
| +    return accept_packet_; | 
| +  } | 
| + | 
| +  virtual void OnStreamFragment(const QuicStreamFragment& fragment) { | 
| +    fragment_count_++; | 
| +    stream_fragments_.push_back(new QuicStreamFragment(fragment)); | 
| +  } | 
| + | 
| +  virtual void OnFecProtectedPayload(StringPiece payload) { | 
| +    fec_protected_payload_ = payload.as_string(); | 
| +  } | 
| + | 
| +  virtual void OnAckFragment(const QuicAckFragment& fragment) { | 
| +    fragment_count_++; | 
| +    ack_fragments_.push_back(new QuicAckFragment(fragment)); | 
| +  } | 
| + | 
| +  virtual void OnFecData(const QuicFecData& fec) { | 
| +    fec_count_++; | 
| +    fec_data_.push_back(new QuicFecData(fec)); | 
| +  } | 
| + | 
| +  virtual void OnPacketComplete() { | 
| +    complete_packets_++; | 
| +  } | 
| + | 
| +  virtual void OnRstStreamFragment(const QuicRstStreamFragment& fragment) { | 
| +    rst_stream_fragment_ = fragment; | 
| +  } | 
| + | 
| +  virtual void OnConnectionCloseFragment( | 
| +      const QuicConnectionCloseFragment& fragment) { | 
| +    connection_close_fragment_ = fragment; | 
| +  } | 
| + | 
| +  // Counters from the visitor_ callbacks. | 
| +  int error_count_; | 
| +  int packet_count_; | 
| +  int fragment_count_; | 
| +  int fec_count_; | 
| +  int complete_packets_; | 
| +  bool accept_packet_; | 
| + | 
| +  IPEndPoint address_; | 
| +  scoped_ptr<QuicPacketHeader> header_; | 
| +  vector<QuicStreamFragment*> stream_fragments_; | 
| +  vector<QuicAckFragment*> ack_fragments_; | 
| +  vector<QuicFecData*> fec_data_; | 
| +  string fec_protected_payload_; | 
| +  QuicRstStreamFragment rst_stream_fragment_; | 
| +  QuicConnectionCloseFragment connection_close_fragment_; | 
| +}; | 
| + | 
| +class QuicFramerTest : public ::testing::Test { | 
| + public: | 
| +  QuicFramerTest() | 
| +      : encrypter_(new test::TestEncrypter()), | 
| +        decrypter_(new test::TestDecrypter()), | 
| +        framer_(decrypter_, encrypter_) { | 
| +    framer_.set_visitor(&visitor_); | 
| +  } | 
| + | 
| +  bool CheckEncryption(StringPiece packet) { | 
| +    StringPiece associated_data( | 
| +        packet.substr(kStartOfHashData, | 
| +                      kStartOfEncryptedData - kStartOfHashData)); | 
| +    if (associated_data != encrypter_->associated_data_) { | 
| +      LOG(ERROR) << "Encrypted incorrect associated data.  expected " | 
| +                 << associated_data << " actual: " | 
| +                 << encrypter_->associated_data_; | 
| +      return false; | 
| +    } | 
| +    StringPiece plaintext(packet.substr(kStartOfEncryptedData)); | 
| +    if (plaintext != encrypter_->plaintext_) { | 
| +      LOG(ERROR) << "Encrypted incorrect plaintext data.  expected " | 
| +                 << plaintext << " actual: " | 
| +                 << encrypter_->plaintext_; | 
| +      return false; | 
| +    } | 
| +    return true; | 
| +  } | 
| + | 
| +  bool CheckDecryption(StringPiece packet) { | 
| +    StringPiece associated_data( | 
| +        packet.substr(kStartOfHashData, | 
| +                      kStartOfEncryptedData - kStartOfHashData)); | 
| +    if (associated_data != decrypter_->associated_data_) { | 
| +      LOG(ERROR) << "Decrypted incorrect associated data.  expected " | 
| +                 << associated_data << " actual: " | 
| +                 << decrypter_->associated_data_; | 
| +      return false; | 
| +    } | 
| +    StringPiece plaintext(packet.substr(kStartOfEncryptedData)); | 
| +    if (plaintext != decrypter_->ciphertext_) { | 
| +      LOG(ERROR) << "Decrypted incorrect chipertext data.  expected " | 
| +                 << plaintext << " actual: " | 
| +                 << decrypter_->ciphertext_; | 
| +      return false; | 
| +    } | 
| +    return true; | 
| +  } | 
| + | 
| +  char* AsChars(unsigned char* data) { | 
| +    return reinterpret_cast<char*>(data); | 
| +  } | 
| + | 
| +  test::TestEncrypter* encrypter_; | 
| +  test::TestDecrypter* decrypter_; | 
| +  QuicFramer framer_; | 
| +  test::TestQuicVisitor visitor_; | 
| +  IPEndPoint address_; | 
| +}; | 
| + | 
| +TEST_F(QuicFramerTest, EmptyPacket) { | 
| +  char packet[] = { 0x00 }; | 
| +  EXPECT_FALSE(framer_.ProcessPacket(address_, | 
| +                                     QuicEncryptedPacket(packet, 0, false))); | 
| +  EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, LargePacket) { | 
| +  unsigned char packet[kMaxPacketSize + 1] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| +    // fragment count | 
| +    0x01, | 
| +  }; | 
| + | 
| +  LOG(INFO) << "here!"; | 
| +  memset(packet + kPacketHeaderSize, 0, kMaxPacketSize - kPacketHeaderSize + 1); | 
| + | 
| +  LOG(INFO) << "here!"; | 
| +  EXPECT_FALSE(framer_.ProcessPacket( | 
| +      address_, QuicEncryptedPacket(AsChars(packet), | 
| +                                    arraysize(packet), false))); | 
| + | 
| +  LOG(INFO) << "here!"; | 
| +  ASSERT_TRUE(visitor_.header_.get()); | 
| +  // Make sure we've parsed the packet header, so we can send an error. | 
| +  LOG(INFO) << "here!"; | 
| +  EXPECT_EQ(0xFEDCBA9876543210, visitor_.header_->guid); | 
| +  // Make sure the correct error is propogated. | 
| +  LOG(INFO) << "here!"; | 
| +  EXPECT_EQ(QUIC_PACKET_TOO_LARGE, framer_.error()); | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, PacketHeader) { | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| +  }; | 
| + | 
| +  EXPECT_FALSE(framer_.ProcessPacket( | 
| +      address_, QuicEncryptedPacket(AsChars(packet), | 
| +                                    arraysize(packet), false))); | 
| + | 
| +  EXPECT_EQ(QUIC_INVALID_FRAGMENT_DATA, framer_.error()); | 
| +  ASSERT_TRUE(visitor_.header_.get()); | 
| +  EXPECT_EQ(0xFEDCBA9876543210, visitor_.header_->guid); | 
| +  EXPECT_EQ(0x1, visitor_.header_->retransmission_count); | 
| +  EXPECT_EQ(static_cast<uint64>(0x123456789ABC), | 
| +            visitor_.header_->packet_sequence_number); | 
| +  EXPECT_EQ(static_cast<uint64>(0xF0E1D2C3B4A59687), | 
| +            visitor_.header_->transmission_time); | 
| +  EXPECT_EQ(0x00, visitor_.header_->flags); | 
| +  EXPECT_EQ(0x00, visitor_.header_->fec_group); | 
| + | 
| +  // Now test framing boundaries | 
| +  for (int i = 0; i < 25; ++i) { | 
| +    string expected_error; | 
| +    if (i < 8) { | 
| +      expected_error = "Unable to read GUID."; | 
| +    } else if (i < 14) { | 
| +      expected_error = "Unable to read sequence number."; | 
| +    } else if (i < 15) { | 
| +      expected_error = "Unable to read retransmission count."; | 
| +    } else if (i < 23) { | 
| +      expected_error = "Unable to read transmission time."; | 
| +    } else if (i < 24) { | 
| +      expected_error = "Unable to read flags."; | 
| +    } else if (i < 25) { | 
| +      expected_error = "Unable to read fec group."; | 
| +    } | 
| + | 
| +    EXPECT_FALSE(framer_.ProcessPacket( | 
| +        address_, QuicEncryptedPacket(AsChars(packet), i, false))); | 
| +    EXPECT_EQ(expected_error, framer_.detailed_error()); | 
| +    EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); | 
| +  } | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, StreamFragment) { | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (stream fragment) | 
| +    0x00, | 
| +    // stream id | 
| +    0x04, 0x03, 0x02, 0x01, | 
| +    // fin | 
| +    0x01, | 
| +    // offset | 
| +    0x54, 0x76, 0x10, 0x32, | 
| +    0xDC, 0xFE, 0x98, 0xBA, | 
| +    // data length | 
| +    0x0c, 0x00, | 
| +    // data | 
| +    'h',  'e',  'l',  'l', | 
| +    'o',  ' ',  'w',  'o', | 
| +    'r',  'l',  'd',  '!', | 
| +  }; | 
| + | 
| +  EXPECT_TRUE(framer_.ProcessPacket( | 
| +      address_, QuicEncryptedPacket(AsChars(packet), | 
| +                                    arraysize(packet), false))); | 
| + | 
| +  EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); | 
| +  EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
| +  ASSERT_TRUE(visitor_.header_.get()); | 
| +  ASSERT_EQ(address_, visitor_.address_); | 
| + | 
| +  ASSERT_EQ(1u, visitor_.stream_fragments_.size()); | 
| +  EXPECT_EQ(0u, visitor_.ack_fragments_.size()); | 
| +  EXPECT_EQ(static_cast<uint64>(0x01020304), | 
| +            visitor_.stream_fragments_[0]->stream_id); | 
| +  EXPECT_TRUE(visitor_.stream_fragments_[0]->fin); | 
| +  EXPECT_EQ(0xBA98FEDC32107654, visitor_.stream_fragments_[0]->offset); | 
| +  EXPECT_EQ("hello world!", visitor_.stream_fragments_[0]->data); | 
| + | 
| +  // Now test framing boundaries | 
| +  for (size_t i = kPacketHeaderSize; i < kPacketHeaderSize + 29; ++i) { | 
| +    string expected_error; | 
| +    if (i < kPacketHeaderSize + 1) { | 
| +      expected_error = "Unable to read fragment count."; | 
| +    } else if (i < kPacketHeaderSize + 2) { | 
| +      expected_error = "Unable to read fragment type."; | 
| +    } else if (i < kPacketHeaderSize + 6) { | 
| +      expected_error = "Unable to read stream_id."; | 
| +    } else if (i < kPacketHeaderSize + 7) { | 
| +      expected_error = "Unable to read fin."; | 
| +    } else if (i < kPacketHeaderSize + 15) { | 
| +      expected_error = "Unable to read offset."; | 
| +    } else if (i < kPacketHeaderSize + 29) { | 
| +      expected_error = "Unable to read fragment data."; | 
| +    } | 
| + | 
| +    EXPECT_FALSE(framer_.ProcessPacket( | 
| +        address_, QuicEncryptedPacket(AsChars(packet), i, false))); | 
| +    EXPECT_EQ(expected_error, framer_.detailed_error()); | 
| +    EXPECT_EQ(QUIC_INVALID_FRAGMENT_DATA, framer_.error()); | 
| +  } | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, RejectPacket) { | 
| +  visitor_.accept_packet_ = false; | 
| + | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (stream fragment) | 
| +    0x00, | 
| +    // stream id | 
| +    0x04, 0x03, 0x02, 0x01, | 
| +    // fin | 
| +    0x01, | 
| +    // offset | 
| +    0x54, 0x76, 0x10, 0x32, | 
| +    0xDC, 0xFE, 0x98, 0xBA, | 
| +    // data length | 
| +    0x0c, 0x00, | 
| +    // data | 
| +    'h',  'e',  'l',  'l', | 
| +    'o',  ' ',  'w',  'o', | 
| +    'r',  'l',  'd',  '!', | 
| +  }; | 
| + | 
| +  EXPECT_TRUE(framer_.ProcessPacket( | 
| +      address_, QuicEncryptedPacket(AsChars(packet), | 
| +                                    arraysize(packet), false))); | 
| + | 
| +  EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); | 
| +  EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
| +  ASSERT_TRUE(visitor_.header_.get()); | 
| +  ASSERT_EQ(address_, visitor_.address_); | 
| + | 
| +  ASSERT_EQ(0u, visitor_.stream_fragments_.size()); | 
| +  EXPECT_EQ(0u, visitor_.ack_fragments_.size()); | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, RevivedStreamFragment) { | 
| +  unsigned char payload[] = { | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (stream fragment) | 
| +    0x00, | 
| +    // stream id | 
| +    0x04, 0x03, 0x02, 0x01, | 
| +    // fin | 
| +    0x01, | 
| +    // offset | 
| +    0x54, 0x76, 0x10, 0x32, | 
| +    0xDC, 0xFE, 0x98, 0xBA, | 
| +    // data length | 
| +    0x0c, 0x00, | 
| +    // data | 
| +    'h',  'e',  'l',  'l', | 
| +    'o',  ' ',  'w',  'o', | 
| +    'r',  'l',  'd',  '!', | 
| +  }; | 
| + | 
| +  QuicPacketHeader header; | 
| +  header.guid = 0xFEDCBA9876543210; | 
| +  header.retransmission_count = 0x01; | 
| +  header.packet_sequence_number = 0x123456789ABC; | 
| +  header.transmission_time = 0xF0E1D2C3B4A59687; | 
| +  header.flags = PACKET_FLAGS_NONE; | 
| +  header.fec_group = 0; | 
| + | 
| +  // Do not encrypt the payload because the revived payload is post-encryption. | 
| +  EXPECT_TRUE(framer_.ProcessRevivedPacket(address_, | 
| +                                           header, | 
| +                                           StringPiece(AsChars(payload), | 
| +                                                       arraysize(payload)))); | 
| + | 
| +  EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
| +  ASSERT_EQ(address_, visitor_.address_); | 
| +  ASSERT_TRUE(visitor_.header_.get()); | 
| +  EXPECT_EQ(0xFEDCBA9876543210, visitor_.header_->guid); | 
| +  EXPECT_EQ(0x1, visitor_.header_->retransmission_count); | 
| +  EXPECT_EQ(static_cast<uint64>(0x123456789ABC), | 
| +            visitor_.header_->packet_sequence_number); | 
| +  EXPECT_EQ(static_cast<uint64>(0xF0E1D2C3B4A59687), | 
| +            visitor_.header_->transmission_time); | 
| +  EXPECT_EQ(0x00, visitor_.header_->flags); | 
| +  EXPECT_EQ(0x00, visitor_.header_->fec_group); | 
| + | 
| + | 
| +  ASSERT_EQ(1u, visitor_.stream_fragments_.size()); | 
| +  EXPECT_EQ(0u, visitor_.ack_fragments_.size()); | 
| +  EXPECT_EQ(static_cast<uint64>(0x01020304), | 
| +            visitor_.stream_fragments_[0]->stream_id); | 
| +  EXPECT_TRUE(visitor_.stream_fragments_[0]->fin); | 
| +  EXPECT_EQ(0xBA98FEDC32107654, visitor_.stream_fragments_[0]->offset); | 
| +  EXPECT_EQ("hello world!", visitor_.stream_fragments_[0]->data); | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, StreamFragmentInFecGroup) { | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x12, 0x34, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x02, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (stream fragment) | 
| +    0x00, | 
| +    // stream id | 
| +    0x04, 0x03, 0x02, 0x01, | 
| +    // fin | 
| +    0x01, | 
| +    // offset | 
| +    0x54, 0x76, 0x10, 0x32, | 
| +    0xDC, 0xFE, 0x98, 0xBA, | 
| +    // data length | 
| +    0x0c, 0x00, | 
| +    // data | 
| +    'h',  'e',  'l',  'l', | 
| +    'o',  ' ',  'w',  'o', | 
| +    'r',  'l',  'd',  '!', | 
| +  }; | 
| + | 
| +  EXPECT_TRUE(framer_.ProcessPacket( | 
| +      address_, QuicEncryptedPacket(AsChars(packet), | 
| +                                    arraysize(packet), false))); | 
| + | 
| +  EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); | 
| +  EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
| +  ASSERT_TRUE(visitor_.header_.get()); | 
| +  EXPECT_EQ(2, visitor_.header_->fec_group); | 
| +  EXPECT_EQ(string(AsChars(packet) + kStartOfFecProtectedData, | 
| +                   arraysize(packet) - kStartOfFecProtectedData), | 
| +            visitor_.fec_protected_payload_); | 
| +  ASSERT_EQ(address_, visitor_.address_); | 
| + | 
| +  ASSERT_EQ(1u, visitor_.stream_fragments_.size()); | 
| +  EXPECT_EQ(0u, visitor_.ack_fragments_.size()); | 
| +  EXPECT_EQ(static_cast<uint64>(0x01020304), | 
| +            visitor_.stream_fragments_[0]->stream_id); | 
| +  EXPECT_TRUE(visitor_.stream_fragments_[0]->fin); | 
| +  EXPECT_EQ(0xBA98FEDC32107654, visitor_.stream_fragments_[0]->offset); | 
| +  EXPECT_EQ("hello world!", visitor_.stream_fragments_[0]->data); | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, AckFragment) { | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (ack fragment) | 
| +    0x02, | 
| +    // largest received packet sequence number | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // time delta | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // num_unacked_packets | 
| +    0x02, | 
| +    // unacked packet sequence number | 
| +    0xBA, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // unacked packet sequence number | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // least packet sequence number awaiting an ack | 
| +    0xA0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // num non retransmitting packets | 
| +    0x03, | 
| +    // non retransmitting packet sequence number | 
| +    0xAE, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xAF, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xB0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // congestion feedback type (none) | 
| +    0x00, | 
| +  }; | 
| + | 
| +  EXPECT_TRUE(framer_.ProcessPacket( | 
| +      address_, QuicEncryptedPacket(AsChars(packet), | 
| +                                    arraysize(packet), false))); | 
| + | 
| +  EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); | 
| +  EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
| +  ASSERT_TRUE(visitor_.header_.get()); | 
| + | 
| +  EXPECT_EQ(0u, visitor_.stream_fragments_.size()); | 
| +  ASSERT_EQ(1u, visitor_.ack_fragments_.size()); | 
| +  const QuicAckFragment& fragment = *visitor_.ack_fragments_[0]; | 
| +  EXPECT_EQ(static_cast<uint64>(0x0123456789ABC), | 
| +            fragment.received_info.largest_received); | 
| +  EXPECT_EQ(0xF0E1D2C3B4A59687, fragment.received_info.time_received); | 
| + | 
| +  const hash_set<QuicPacketSequenceNumber>* sequence_nums = | 
| +      &fragment.received_info.missing_packets; | 
| +  ASSERT_EQ(2u, sequence_nums->size()); | 
| +  EXPECT_TRUE(sequence_nums->find(0x0123456789ABB) != sequence_nums->end()); | 
| +  EXPECT_TRUE(sequence_nums->find(0x0123456789ABA) != sequence_nums->end()); | 
| +  EXPECT_EQ(static_cast<uint64>(0x0123456789AA0), | 
| +            fragment.sent_info.least_unacked); | 
| +  ASSERT_EQ(3u, fragment.sent_info.non_retransmiting.size()); | 
| +  const hash_set<QuicPacketSequenceNumber>* non_retrans = | 
| +      &fragment.sent_info.non_retransmiting; | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AB0) != non_retrans->end()); | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AAF) != non_retrans->end()); | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AAE) != non_retrans->end()); | 
| +  ASSERT_EQ(kNone, fragment.congestion_info.type); | 
| + | 
| +  // Now test framing boundaries | 
| +  for (size_t i = kPacketHeaderSize; i < kPacketHeaderSize + 55; ++i) { | 
| +    string expected_error; | 
| +    if (i < kPacketHeaderSize + 1) { | 
| +      expected_error = "Unable to read fragment count."; | 
| +    } else if (i < kPacketHeaderSize + 2) { | 
| +      expected_error = "Unable to read fragment type."; | 
| +    } else if (i < kPacketHeaderSize + 8) { | 
| +      expected_error = "Unable to read largest received."; | 
| +    } else if (i < kPacketHeaderSize + 16) { | 
| +      expected_error = "Unable to read time received."; | 
| +    } else if (i < kPacketHeaderSize + 17) { | 
| +      expected_error = "Unable to read num unacked packets."; | 
| +    } else if (i < kPacketHeaderSize + 29) { | 
| +      expected_error = "Unable to read sequence number in unacked packets."; | 
| +    } else if (i < kPacketHeaderSize + 35) { | 
| +      expected_error = "Unable to read least unacked."; | 
| +    } else if (i < kPacketHeaderSize + 36) { | 
| +      expected_error = "Unable to read num non-retransmitting."; | 
| +    } else if (i < kPacketHeaderSize + 54) { | 
| +      expected_error = "Unable to read sequence number in non-retransmitting."; | 
| +    } else if (i < kPacketHeaderSize + 55) { | 
| +      expected_error = "Unable to read congestion info type."; | 
| +    } | 
| + | 
| +    EXPECT_FALSE(framer_.ProcessPacket( | 
| +        address_, QuicEncryptedPacket(AsChars(packet), i, false))); | 
| +    EXPECT_EQ(expected_error, framer_.detailed_error()); | 
| +    EXPECT_EQ(QUIC_INVALID_FRAGMENT_DATA, framer_.error()); | 
| +  } | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, AckFragmentTCP) { | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (ack fragment) | 
| +    0x02, | 
| +    // largest received packet sequence number | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // time delta | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // num_unacked_packets | 
| +    0x02, | 
| +    // unacked packet sequence number | 
| +    0xBA, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // unacked packet sequence number | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // least packet sequence number awaiting an ack | 
| +    0xA0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // num non retransmitting packets | 
| +    0x03, | 
| +    // non retransmitting packet sequence number | 
| +    0xAE, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xAF, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xB0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // congestion feedback type (tcp) | 
| +    0x01, | 
| +    // ack_fragment.congestion_info.tcp.accumulated_number_of_lost_packets | 
| +    0x01, 0x02, | 
| +    // ack_fragment.congestion_info.tcp.receive_window | 
| +    0x03, 0x04, | 
| +  }; | 
| + | 
| +  EXPECT_TRUE(framer_.ProcessPacket( | 
| +      address_, QuicEncryptedPacket(AsChars(packet), | 
| +                                    arraysize(packet), false))); | 
| + | 
| +  EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); | 
| +  EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
| +  ASSERT_TRUE(visitor_.header_.get()); | 
| + | 
| +  EXPECT_EQ(0u, visitor_.stream_fragments_.size()); | 
| +  ASSERT_EQ(1u, visitor_.ack_fragments_.size()); | 
| +  const QuicAckFragment& fragment = *visitor_.ack_fragments_[0]; | 
| +  EXPECT_EQ(static_cast<uint64>(0x0123456789ABC), | 
| +            fragment.received_info.largest_received); | 
| +  EXPECT_EQ(0xF0E1D2C3B4A59687, fragment.received_info.time_received); | 
| + | 
| +  const hash_set<QuicPacketSequenceNumber>* sequence_nums = | 
| +      &fragment.received_info.missing_packets; | 
| +  ASSERT_EQ(2u, sequence_nums->size()); | 
| +  EXPECT_TRUE(sequence_nums->find(0x0123456789ABB) != sequence_nums->end()); | 
| +  EXPECT_TRUE(sequence_nums->find(0x0123456789ABA) != sequence_nums->end()); | 
| +  EXPECT_EQ(static_cast<uint64>(0x0123456789AA0), | 
| +            fragment.sent_info.least_unacked); | 
| +  ASSERT_EQ(3u, fragment.sent_info.non_retransmiting.size()); | 
| +  const hash_set<QuicPacketSequenceNumber>* non_retrans = | 
| +      &fragment.sent_info.non_retransmiting; | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AB0) != non_retrans->end()); | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AAF) != non_retrans->end()); | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AAE) != non_retrans->end()); | 
| +  ASSERT_EQ(kTCP, fragment.congestion_info.type); | 
| +  EXPECT_EQ(0x0201, | 
| +            fragment.congestion_info.tcp.accumulated_number_of_lost_packets); | 
| +  EXPECT_EQ(0x0403, fragment.congestion_info.tcp.receive_window); | 
| + | 
| +  // Now test framing boundaries | 
| +  for (size_t i = kCongestionInfoOffset; i < kCongestionInfoOffset + 5; ++i) { | 
| +    string expected_error; | 
| +    if (i < kCongestionInfoOffset + 1) { | 
| +      expected_error = "Unable to read congestion info type."; | 
| +    } else if (i < kCongestionInfoOffset + 3) { | 
| +      expected_error = "Unable to read accumulated number of lost packets."; | 
| +    } else if (i < kCongestionInfoOffset + 5) { | 
| +      expected_error = "Unable to read receive window."; | 
| +    } | 
| + | 
| +    EXPECT_FALSE(framer_.ProcessPacket( | 
| +        address_, QuicEncryptedPacket(AsChars(packet), i, false))); | 
| +    EXPECT_EQ(expected_error, framer_.detailed_error()); | 
| +    EXPECT_EQ(QUIC_INVALID_FRAGMENT_DATA, framer_.error()); | 
| +  } | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, AckFragmentInterArrival) { | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (ack fragment) | 
| +    0x02, | 
| +    // largest received packet sequence number | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // time delta | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // num_unacked_packets | 
| +    0x02, | 
| +    // unacked packet sequence number | 
| +    0xBA, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // unacked packet sequence number | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // least packet sequence number awaiting an ack | 
| +    0xA0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // num non retransmitting packets | 
| +    0x03, | 
| +    // non retransmitting packet sequence number | 
| +    0xAE, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xAF, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xB0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // congestion feedback type (inter arrival) | 
| +    0x02, | 
| +    // accumulated_number_of_lost_packets | 
| +    0x02, 0x03, | 
| +    // offset_time | 
| +    0x04, 0x05, | 
| +    // delta_time | 
| +    0x06, 0x07, | 
| +  }; | 
| + | 
| +  EXPECT_TRUE(framer_.ProcessPacket( | 
| +      address_, QuicEncryptedPacket(AsChars(packet), | 
| +                                    arraysize(packet), false))); | 
| + | 
| +  EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); | 
| +  EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
| +  ASSERT_TRUE(visitor_.header_.get()); | 
| + | 
| +  EXPECT_EQ(0u, visitor_.stream_fragments_.size()); | 
| +  ASSERT_EQ(1u, visitor_.ack_fragments_.size()); | 
| +  const QuicAckFragment& fragment = *visitor_.ack_fragments_[0]; | 
| +  EXPECT_EQ(static_cast<uint64>(0x0123456789ABC), | 
| +            fragment.received_info.largest_received); | 
| +  EXPECT_EQ(0xF0E1D2C3B4A59687, fragment.received_info.time_received); | 
| + | 
| +  const hash_set<QuicPacketSequenceNumber>* sequence_nums = | 
| +      &fragment.received_info.missing_packets; | 
| +  ASSERT_EQ(2u, sequence_nums->size()); | 
| +  EXPECT_TRUE(sequence_nums->find(0x0123456789ABB) != sequence_nums->end()); | 
| +  EXPECT_TRUE(sequence_nums->find(0x0123456789ABA) != sequence_nums->end()); | 
| +  EXPECT_EQ(static_cast<uint64>(0x0123456789AA0), | 
| +            fragment.sent_info.least_unacked); | 
| +  ASSERT_EQ(3u, fragment.sent_info.non_retransmiting.size()); | 
| +  const hash_set<QuicPacketSequenceNumber>* non_retrans = | 
| +      &fragment.sent_info.non_retransmiting; | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AB0) != non_retrans->end()); | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AAF) != non_retrans->end()); | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AAE) != non_retrans->end()); | 
| +  ASSERT_EQ(kInterArrival, fragment.congestion_info.type); | 
| +  EXPECT_EQ(0x0302, fragment.congestion_info.inter_arrival. | 
| +            accumulated_number_of_lost_packets); | 
| +  EXPECT_EQ(0x0504, | 
| +            fragment.congestion_info.inter_arrival.offset_time); | 
| +  EXPECT_EQ(0x0706, | 
| +            fragment.congestion_info.inter_arrival.delta_time); | 
| + | 
| +  // Now test framing boundaries | 
| +  for (size_t i = kCongestionInfoOffset; i < kCongestionInfoOffset + 5; ++i) { | 
| +    string expected_error; | 
| +    if (i < kCongestionInfoOffset + 1) { | 
| +      expected_error = "Unable to read congestion info type."; | 
| +    } else if (i < kCongestionInfoOffset + 3) { | 
| +      expected_error = "Unable to read accumulated number of lost packets."; | 
| +    } else if (i < kCongestionInfoOffset + 5) { | 
| +      expected_error = "Unable to read offset time."; | 
| +    } else if (i < kCongestionInfoOffset + 7) { | 
| +      expected_error = "Unable to read delta time."; | 
| +    } | 
| +    EXPECT_FALSE(framer_.ProcessPacket( | 
| +        address_, QuicEncryptedPacket(AsChars(packet), i, false))); | 
| +    EXPECT_EQ(expected_error, framer_.detailed_error()); | 
| +    EXPECT_EQ(QUIC_INVALID_FRAGMENT_DATA, framer_.error()); | 
| +  } | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, AckFragmentFixRate) { | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (ack fragment) | 
| +    0x02, | 
| +    // largest received packet sequence number | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // time delta | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // num_unacked_packets | 
| +    0x02, | 
| +    // unacked packet sequence number | 
| +    0xBA, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // unacked packet sequence number | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // least packet sequence number awaiting an ack | 
| +    0xA0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // num non retransmitting packets | 
| +    0x03, | 
| +    // non retransmitting packet sequence number | 
| +    0xAE, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xAF, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xB0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // congestion feedback type (fix rate) | 
| +    0x03, | 
| +    // bitrate_in_bytes_per_second; | 
| +    0x01, 0x02, 0x03, 0x04, | 
| +  }; | 
| + | 
| +  EXPECT_TRUE(framer_.ProcessPacket( | 
| +      address_, QuicEncryptedPacket(AsChars(packet), | 
| +                                    arraysize(packet), false))); | 
| + | 
| +  EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); | 
| +  EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
| +  ASSERT_TRUE(visitor_.header_.get()); | 
| + | 
| +  EXPECT_EQ(0u, visitor_.stream_fragments_.size()); | 
| +  ASSERT_EQ(1u, visitor_.ack_fragments_.size()); | 
| +  const QuicAckFragment& fragment = *visitor_.ack_fragments_[0]; | 
| +  EXPECT_EQ(static_cast<uint64>(0x0123456789ABC), | 
| +            fragment.received_info.largest_received); | 
| +  EXPECT_EQ(0xF0E1D2C3B4A59687, fragment.received_info.time_received); | 
| + | 
| +  const hash_set<QuicPacketSequenceNumber>* sequence_nums = | 
| +      &fragment.received_info.missing_packets; | 
| +  ASSERT_EQ(2u, sequence_nums->size()); | 
| +  EXPECT_TRUE(sequence_nums->find(0x0123456789ABB) != sequence_nums->end()); | 
| +  EXPECT_TRUE(sequence_nums->find(0x0123456789ABA) != sequence_nums->end()); | 
| +  EXPECT_EQ(static_cast<uint64>(0x0123456789AA0), | 
| +            fragment.sent_info.least_unacked); | 
| +  ASSERT_EQ(3u, fragment.sent_info.non_retransmiting.size()); | 
| +  const hash_set<QuicPacketSequenceNumber>* non_retrans = | 
| +      &fragment.sent_info.non_retransmiting; | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AB0) != non_retrans->end()); | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AAF) != non_retrans->end()); | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AAE) != non_retrans->end()); | 
| +  ASSERT_EQ(kFixRate, fragment.congestion_info.type); | 
| +  EXPECT_EQ(static_cast<uint32>(0x04030201), | 
| +            fragment.congestion_info.fix_rate.bitrate_in_bytes_per_second); | 
| + | 
| +  // Now test framing boundaries | 
| +  for (size_t i = kCongestionInfoOffset; i < kCongestionInfoOffset + 5; ++i) { | 
| +    string expected_error; | 
| +    if (i < kCongestionInfoOffset + 1) { | 
| +      expected_error = "Unable to read congestion info type."; | 
| +    } else if (i < kCongestionInfoOffset + 5) { | 
| +      expected_error = "Unable to read bitrate."; | 
| +    } | 
| +    EXPECT_FALSE(framer_.ProcessPacket( | 
| +        address_, QuicEncryptedPacket(AsChars(packet), i, false))); | 
| +    EXPECT_EQ(expected_error, framer_.detailed_error()); | 
| +    EXPECT_EQ(QUIC_INVALID_FRAGMENT_DATA, framer_.error()); | 
| +  } | 
| +} | 
| + | 
| + | 
| +TEST_F(QuicFramerTest, AckFragmentInvalidFeedback) { | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (ack fragment) | 
| +    0x02, | 
| +    // largest received packet sequence number | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // time delta | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // num_unacked_packets | 
| +    0x02, | 
| +    // unacked packet sequence number | 
| +    0xBA, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // unacked packet sequence number | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // least packet sequence number awaiting an ack | 
| +    0xA0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // num non retransmitting packets | 
| +    0x03, | 
| +    // non retransmitting packet sequence number | 
| +    0xAE, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xAF, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xB0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // congestion feedback type (invalid) | 
| +    0x04, | 
| +  }; | 
| + | 
| +  EXPECT_FALSE(framer_.ProcessPacket( | 
| +      address_, QuicEncryptedPacket(AsChars(packet), | 
| +                                    arraysize(packet), false))); | 
| +  EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); | 
| +  EXPECT_EQ(QUIC_INVALID_FRAGMENT_DATA, framer_.error()); | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, RstStreamFragment) { | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (rst stream fragment) | 
| +    0x03, | 
| +    // stream id | 
| +    0x04, 0x03, 0x02, 0x01, | 
| +    // offset | 
| +    0x54, 0x76, 0x10, 0x32, | 
| +    0xDC, 0xFE, 0x98, 0xBA, | 
| +    // details | 
| +    0x08, 0x07, 0x06, 0x05, | 
| +  }; | 
| + | 
| +  EXPECT_TRUE(framer_.ProcessPacket( | 
| +      address_, QuicEncryptedPacket(AsChars(packet), | 
| +                                    arraysize(packet), false))); | 
| + | 
| +  EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); | 
| +  EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
| +  ASSERT_TRUE(visitor_.header_.get()); | 
| +  ASSERT_EQ(address_, visitor_.address_); | 
| + | 
| +  EXPECT_EQ(static_cast<uint64>(0x01020304), | 
| +            visitor_.rst_stream_fragment_.stream_id); | 
| +  EXPECT_EQ(0x05060708, visitor_.rst_stream_fragment_.details); | 
| +  EXPECT_EQ(0xBA98FEDC32107654, visitor_.rst_stream_fragment_.offset); | 
| + | 
| +  // Now test framing boundaries | 
| +  for (size_t i = kPacketHeaderSize + 3; i < kPacketHeaderSize + 18; ++i) { | 
| +    string expected_error; | 
| +    if (i < kPacketHeaderSize + 6) { | 
| +      expected_error = "Unable to read stream_id."; | 
| +    } else if (i < kPacketHeaderSize + 14) { | 
| +      expected_error = "Unable to read offset in rst fragment."; | 
| +    } else if (i < kPacketHeaderSize + 18) { | 
| +      expected_error = "Unable to read rst stream details."; | 
| +    } | 
| +    EXPECT_FALSE(framer_.ProcessPacket( | 
| +        address_, QuicEncryptedPacket(AsChars(packet), i, false))); | 
| +    EXPECT_EQ(expected_error, framer_.detailed_error()); | 
| +    EXPECT_EQ(QUIC_INVALID_RST_STREAM_DATA, framer_.error()); | 
| +  } | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, ConnectionCloseFragment) { | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (connection close fragment) | 
| +    0x04, | 
| +    // details | 
| +    0x08, 0x07, 0x06, 0x05, | 
| + | 
| +    // Ack fragment. | 
| + | 
| +    // largest received packet sequence number | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // time delta | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // num_unacked_packets | 
| +    0x02, | 
| +    // unacked packet sequence number | 
| +    0xBA, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // unacked packet sequence number | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // least packet sequence number awaiting an ack | 
| +    0xA0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // num non retransmitting packets | 
| +    0x03, | 
| +    // non retransmitting packet sequence number | 
| +    0xAE, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xAF, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xB0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // congestion feedback type (inter arrival) | 
| +    0x02, | 
| +    // accumulated_number_of_lost_packets | 
| +    0x02, 0x03, | 
| +    // offset_time | 
| +    0x04, 0x05, | 
| +    // delta_time | 
| +    0x06, 0x07, | 
| +  }; | 
| + | 
| +  EXPECT_TRUE(framer_.ProcessPacket( | 
| +      address_, QuicEncryptedPacket(AsChars(packet), | 
| +                                    arraysize(packet), false))); | 
| + | 
| +  EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); | 
| +  EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
| +  ASSERT_TRUE(visitor_.header_.get()); | 
| + | 
| +  EXPECT_EQ(0u, visitor_.stream_fragments_.size()); | 
| + | 
| +  EXPECT_EQ(0x05060708, visitor_.connection_close_fragment_.details); | 
| + | 
| +  ASSERT_EQ(1u, visitor_.ack_fragments_.size()); | 
| +  const QuicAckFragment& fragment = *visitor_.ack_fragments_[0]; | 
| +  EXPECT_EQ(static_cast<uint64>(0x0123456789ABC), | 
| +            fragment.received_info.largest_received); | 
| +  EXPECT_EQ(0xF0E1D2C3B4A59687, fragment.received_info.time_received); | 
| + | 
| +  const hash_set<QuicPacketSequenceNumber>* sequence_nums = | 
| +      &fragment.received_info.missing_packets; | 
| +  ASSERT_EQ(2u, sequence_nums->size()); | 
| +  EXPECT_TRUE(sequence_nums->find(0x0123456789ABB) != sequence_nums->end()); | 
| +  EXPECT_TRUE(sequence_nums->find(0x0123456789ABA) != sequence_nums->end()); | 
| +  EXPECT_EQ(static_cast<uint64>(0x0123456789AA0), | 
| +            fragment.sent_info.least_unacked); | 
| +  ASSERT_EQ(3u, fragment.sent_info.non_retransmiting.size()); | 
| +  const hash_set<QuicPacketSequenceNumber>* non_retrans = | 
| +      &fragment.sent_info.non_retransmiting; | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AB0) != non_retrans->end()); | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AAF) != non_retrans->end()); | 
| +  EXPECT_TRUE(non_retrans->find(0x0123456789AAE) != non_retrans->end()); | 
| +  ASSERT_EQ(kInterArrival, fragment.congestion_info.type); | 
| +  EXPECT_EQ(0x0302, fragment.congestion_info.inter_arrival. | 
| +            accumulated_number_of_lost_packets); | 
| +  EXPECT_EQ(0x0504, | 
| +            fragment.congestion_info.inter_arrival.offset_time); | 
| +  EXPECT_EQ(0x0706, | 
| +            fragment.congestion_info.inter_arrival.delta_time); | 
| + | 
| +  // Now test framing boundaries | 
| +  for (size_t i = kPacketHeaderSize + 3; i < kPacketHeaderSize + 6; ++i) { | 
| +    string expected_error; | 
| +    if (i < kPacketHeaderSize + 6) { | 
| +      expected_error = "Unable to read connection close details."; | 
| +    } | 
| +    EXPECT_FALSE(framer_.ProcessPacket( | 
| +        address_, QuicEncryptedPacket(AsChars(packet), i, false))); | 
| +    EXPECT_EQ(expected_error, framer_.detailed_error()); | 
| +    EXPECT_EQ(QUIC_INVALID_CONNECTION_CLOSE_DATA, framer_.error()); | 
| +  } | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, FecPacket) { | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags (FEC) | 
| +    0x01, | 
| +    // fec group | 
| +    0x01, | 
| + | 
| +    // first protected packet | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // redundancy | 
| +    'a',  'b',  'c',  'd', | 
| +    'e',  'f',  'g',  'h', | 
| +    'i',  'j',  'k',  'l', | 
| +    'm',  'n',  'o',  'p', | 
| +  }; | 
| + | 
| +  EXPECT_TRUE(framer_.ProcessPacket( | 
| +      address_, QuicEncryptedPacket(AsChars(packet), | 
| +                                    arraysize(packet), false))); | 
| + | 
| +  EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); | 
| +  EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); | 
| +  ASSERT_TRUE(visitor_.header_.get()); | 
| + | 
| +  EXPECT_EQ(0u, visitor_.stream_fragments_.size()); | 
| +  EXPECT_EQ(0u, visitor_.ack_fragments_.size()); | 
| +  ASSERT_EQ(1, visitor_.fec_count_); | 
| +  const QuicFecData& fec_data = *visitor_.fec_data_[0]; | 
| +  EXPECT_EQ(static_cast<uint64>(0x0123456789ABB), | 
| +            fec_data.first_protected_packet_sequence_number); | 
| +  EXPECT_EQ("abcdefghijklmnop", fec_data.redundancy); | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, ConstructStreamFragmentPacket) { | 
| +  QuicPacketHeader header; | 
| +  header.guid = 0xFEDCBA9876543210; | 
| +  header.retransmission_count = 0x01; | 
| +  header.packet_sequence_number = 0x123456789ABC; | 
| +  header.transmission_time = 0xF0E1D2C3B4A59687; | 
| +  header.flags = PACKET_FLAGS_NONE; | 
| +  header.fec_group = 0; | 
| + | 
| +  QuicStreamFragment stream_fragment; | 
| +  stream_fragment.stream_id = 0x01020304; | 
| +  stream_fragment.fin = true; | 
| +  stream_fragment.offset = 0xBA98FEDC32107654; | 
| +  stream_fragment.data = "hello world!"; | 
| + | 
| +  QuicFragment fragment; | 
| +  fragment.type = STREAM_FRAGMENT; | 
| +  fragment.stream_fragment = &stream_fragment; | 
| + | 
| +  QuicFragments fragments; | 
| +  fragments.push_back(fragment); | 
| + | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (stream fragment) | 
| +    0x00, | 
| +    // stream id | 
| +    0x04, 0x03, 0x02, 0x01, | 
| +    // fin | 
| +    0x01, | 
| +    // offset | 
| +    0x54, 0x76, 0x10, 0x32, | 
| +    0xDC, 0xFE, 0x98, 0xBA, | 
| +    // data length | 
| +    0x0c, 0x00, | 
| +    // data | 
| +    'h',  'e',  'l',  'l', | 
| +    'o',  ' ',  'w',  'o', | 
| +    'r',  'l',  'd',  '!', | 
| +  }; | 
| + | 
| +  QuicPacket* data; | 
| +  ASSERT_TRUE(framer_.ConstructFragementDataPacket(header, fragments, &data)); | 
| + | 
| +  test::CompareCharArraysWithHexError("constructed packet", | 
| +                                      data->data(), data->length(), | 
| +                                      AsChars(packet), arraysize(packet)); | 
| + | 
| +  delete data; | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, ConstructAckFragmentPacket) { | 
| +  QuicPacketHeader header; | 
| +  header.guid = 0xFEDCBA9876543210; | 
| +  header.retransmission_count = 0x01; | 
| +  header.packet_sequence_number = 0x123456789ABC; | 
| +  header.transmission_time = 0xF0E1D2C3B4A59687; | 
| +  header.flags = PACKET_FLAGS_NONE; | 
| +  header.fec_group = 0; | 
| + | 
| +  QuicAckFragment ack_fragment; | 
| +  ack_fragment.received_info.largest_received = 0x0123456789ABC; | 
| +  ack_fragment.received_info.time_received = 0xF0E1D2C3B4A59687; | 
| +  ack_fragment.received_info.missing_packets.insert(0x0123456789ABB); | 
| +  ack_fragment.received_info.missing_packets.insert(0x0123456789ABA); | 
| +  ack_fragment.sent_info.least_unacked = 0x0123456789AA0; | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AB0); | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AAF); | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AAE); | 
| +  ack_fragment.congestion_info.type = kNone; | 
| + | 
| +  QuicFragment fragment; | 
| +  fragment.type = ACK_FRAGMENT; | 
| +  fragment.ack_fragment = &ack_fragment; | 
| + | 
| +  QuicFragments fragments; | 
| +  fragments.push_back(fragment); | 
| + | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (ack fragment) | 
| +    0x02, | 
| +    // largest received packet sequence number | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // time delta | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // num_unacked_packets | 
| +    0x02, | 
| +    // unacked packet sequence number | 
| +    0xBA, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // unacked packet sequence number | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // least packet sequence number awaiting an ack | 
| +    0xA0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // num non retransmitting packets | 
| +    0x03, | 
| +    // non retransmitting packet sequence number | 
| +    0xAE, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xAF, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xB0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // congestion feedback type (none) | 
| +    0x00, | 
| +  }; | 
| + | 
| +  QuicPacket* data; | 
| +  EXPECT_TRUE(framer_.ConstructFragementDataPacket(header, fragments, &data)); | 
| + | 
| +  test::CompareCharArraysWithHexError("constructed packet", | 
| +                                      data->data(), data->length(), | 
| +                                      AsChars(packet), arraysize(packet)); | 
| + | 
| +  delete data; | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, ConstructAckFragmentPacketTCP) { | 
| +  QuicPacketHeader header; | 
| +  header.guid = 0xFEDCBA9876543210; | 
| +  header.retransmission_count = 0x01; | 
| +  header.packet_sequence_number = 0x123456789ABC; | 
| +  header.transmission_time = 0xF0E1D2C3B4A59687; | 
| +  header.flags = PACKET_FLAGS_NONE; | 
| +  header.fec_group = 0; | 
| + | 
| +  QuicAckFragment ack_fragment; | 
| +  ack_fragment.received_info.largest_received = 0x0123456789ABC; | 
| +  ack_fragment.received_info.time_received = 0xF0E1D2C3B4A59687; | 
| +  ack_fragment.received_info.missing_packets.insert(0x0123456789ABB); | 
| +  ack_fragment.received_info.missing_packets.insert(0x0123456789ABA); | 
| +  ack_fragment.sent_info.least_unacked = 0x0123456789AA0; | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AB0); | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AAF); | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AAE); | 
| +  ack_fragment.congestion_info.type = kTCP; | 
| +  ack_fragment.congestion_info.tcp.accumulated_number_of_lost_packets = 0x0201; | 
| +  ack_fragment.congestion_info.tcp.receive_window = 0x0403; | 
| + | 
| +  QuicFragment fragment; | 
| +  fragment.type = ACK_FRAGMENT; | 
| +  fragment.ack_fragment = &ack_fragment; | 
| + | 
| +  QuicFragments fragments; | 
| +  fragments.push_back(fragment); | 
| + | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (ack fragment) | 
| +    0x02, | 
| +    // largest received packet sequence number | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // time delta | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // num_unacked_packets | 
| +    0x02, | 
| +    // unacked packet sequence number | 
| +    0xBA, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // unacked packet sequence number | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // least packet sequence number awaiting an ack | 
| +    0xA0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // num non retransmitting packets | 
| +    0x03, | 
| +    // non retransmitting packet sequence number | 
| +    0xAE, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xAF, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xB0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // congestion feedback type (tcp) | 
| +    0x01, | 
| +    // ack_fragment.congestion_info.tcp.accumulated_number_of_lost_packets | 
| +    0x01, 0x02, | 
| +    // ack_fragment.congestion_info.tcp.receive_window | 
| +    0x03, 0x04, | 
| +  }; | 
| + | 
| +  QuicPacket* data; | 
| +  EXPECT_TRUE(framer_.ConstructFragementDataPacket(header, fragments, &data)); | 
| + | 
| +  test::CompareCharArraysWithHexError("constructed packet", | 
| +                                      data->data(), data->length(), | 
| +                                      AsChars(packet), arraysize(packet)); | 
| + | 
| +  delete data; | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, ConstructAckFragmentPacketInterArrival) { | 
| +  QuicPacketHeader header; | 
| +  header.guid = 0xFEDCBA9876543210; | 
| +  header.retransmission_count = 0x01; | 
| +  header.packet_sequence_number = 0x123456789ABC; | 
| +  header.transmission_time = 0xF0E1D2C3B4A59687; | 
| +  header.flags = PACKET_FLAGS_NONE; | 
| +  header.fec_group = 0; | 
| + | 
| +  QuicAckFragment ack_fragment; | 
| +  ack_fragment.received_info.largest_received = 0x0123456789ABC; | 
| +  ack_fragment.received_info.time_received = 0xF0E1D2C3B4A59687; | 
| +  ack_fragment.received_info.missing_packets.insert(0x0123456789ABB); | 
| +  ack_fragment.received_info.missing_packets.insert(0x0123456789ABA); | 
| +  ack_fragment.sent_info.least_unacked = 0x0123456789AA0; | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AB0); | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AAF); | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AAE); | 
| +  ack_fragment.congestion_info.type = kInterArrival; | 
| +  ack_fragment.congestion_info.inter_arrival.accumulated_number_of_lost_packets | 
| +      = 0x0302; | 
| +  ack_fragment.congestion_info.inter_arrival.offset_time = 0x0504; | 
| +  ack_fragment.congestion_info.inter_arrival.delta_time = 0x0706; | 
| + | 
| +  QuicFragment fragment; | 
| +  fragment.type = ACK_FRAGMENT; | 
| +  fragment.ack_fragment = &ack_fragment; | 
| + | 
| +  QuicFragments fragments; | 
| +  fragments.push_back(fragment); | 
| + | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (ack fragment) | 
| +    0x02, | 
| +    // largest received packet sequence number | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // time delta | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // num_unacked_packets | 
| +    0x02, | 
| +    // unacked packet sequence number | 
| +    0xBA, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // unacked packet sequence number | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // least packet sequence number awaiting an ack | 
| +    0xA0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // num non retransmitting packets | 
| +    0x03, | 
| +    // non retransmitting packet sequence number | 
| +    0xAE, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xAF, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xB0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // congestion feedback type (inter arrival) | 
| +    0x02, | 
| +    // accumulated_number_of_lost_packets | 
| +    0x02, 0x03, | 
| +    // offset_time | 
| +    0x04, 0x05, | 
| +    // delta_time | 
| +    0x06, 0x07, | 
| +  }; | 
| + | 
| +  QuicPacket* data; | 
| +  EXPECT_TRUE(framer_.ConstructFragementDataPacket(header, fragments, &data)); | 
| + | 
| +  test::CompareCharArraysWithHexError("constructed packet", | 
| +                                      data->data(), data->length(), | 
| +                                      AsChars(packet), arraysize(packet)); | 
| + | 
| +  delete data; | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, ConstructAckFragmentPacketFixRate) { | 
| +  QuicPacketHeader header; | 
| +  header.guid = 0xFEDCBA9876543210; | 
| +  header.retransmission_count = 0x01; | 
| +  header.packet_sequence_number = 0x123456789ABC; | 
| +  header.transmission_time = 0xF0E1D2C3B4A59687; | 
| +  header.flags = PACKET_FLAGS_NONE; | 
| +  header.fec_group = 0; | 
| + | 
| +  QuicAckFragment ack_fragment; | 
| +  ack_fragment.received_info.largest_received = 0x0123456789ABC; | 
| +  ack_fragment.received_info.time_received = 0xF0E1D2C3B4A59687; | 
| +  ack_fragment.received_info.missing_packets.insert(0x0123456789ABB); | 
| +  ack_fragment.received_info.missing_packets.insert(0x0123456789ABA); | 
| +  ack_fragment.sent_info.least_unacked = 0x0123456789AA0; | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AB0); | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AAF); | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AAE); | 
| +  ack_fragment.congestion_info.type = kFixRate; | 
| +  ack_fragment.congestion_info.fix_rate.bitrate_in_bytes_per_second | 
| +      = 0x04030201; | 
| + | 
| +  QuicFragment fragment; | 
| +  fragment.type = ACK_FRAGMENT; | 
| +  fragment.ack_fragment = &ack_fragment; | 
| + | 
| +  QuicFragments fragments; | 
| +  fragments.push_back(fragment); | 
| + | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (ack fragment) | 
| +    0x02, | 
| +    // largest received packet sequence number | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // time delta | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // num_unacked_packets | 
| +    0x02, | 
| +    // unacked packet sequence number | 
| +    0xBA, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // unacked packet sequence number | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // least packet sequence number awaiting an ack | 
| +    0xA0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // num non retransmitting packets | 
| +    0x03, | 
| +    // non retransmitting packet sequence number | 
| +    0xAE, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xAF, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xB0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // congestion feedback type (fix rate) | 
| +    0x03, | 
| +    // bitrate_in_bytes_per_second; | 
| +    0x01, 0x02, 0x03, 0x04, | 
| +  }; | 
| + | 
| +  QuicPacket* data; | 
| +  EXPECT_TRUE(framer_.ConstructFragementDataPacket(header, fragments, &data)); | 
| + | 
| +  test::CompareCharArraysWithHexError("constructed packet", | 
| +                                      data->data(), data->length(), | 
| +                                      AsChars(packet), arraysize(packet)); | 
| + | 
| +  delete data; | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, ConstructAckFragmentPacketInvalidFeedback) { | 
| +  QuicPacketHeader header; | 
| +  header.guid = 0xFEDCBA9876543210; | 
| +  header.retransmission_count = 0x01; | 
| +  header.packet_sequence_number = 0x123456789ABC; | 
| +  header.transmission_time = 0xF0E1D2C3B4A59687; | 
| +  header.flags = PACKET_FLAGS_NONE; | 
| +  header.fec_group = 0; | 
| + | 
| +  QuicAckFragment ack_fragment; | 
| +  ack_fragment.received_info.largest_received = 0x0123456789ABC; | 
| +  ack_fragment.received_info.time_received = 0xF0E1D2C3B4A59687; | 
| +  ack_fragment.received_info.missing_packets.insert(0x0123456789ABB); | 
| +  ack_fragment.received_info.missing_packets.insert(0x0123456789ABA); | 
| +  ack_fragment.sent_info.least_unacked = 0x0123456789AA0; | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AB0); | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AAF); | 
| +  ack_fragment.sent_info.non_retransmiting.insert(0x0123456789AAE); | 
| +  ack_fragment.congestion_info.type = | 
| +      static_cast<CongestionFeedbackType>(kFixRate + 1); | 
| + | 
| +  QuicFragment fragment; | 
| +  fragment.type = ACK_FRAGMENT; | 
| +  fragment.ack_fragment = &ack_fragment; | 
| + | 
| +  QuicFragments fragments; | 
| +  fragments.push_back(fragment); | 
| + | 
| +  QuicPacket* data; | 
| +  EXPECT_FALSE(framer_.ConstructFragementDataPacket(header, fragments, &data)); | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, ConstructRstFragmentPacket) { | 
| +  QuicPacketHeader header; | 
| +  header.guid = 0xFEDCBA9876543210; | 
| +  header.retransmission_count = 0x01; | 
| +  header.packet_sequence_number = 0x123456789ABC; | 
| +  header.transmission_time = 0xF0E1D2C3B4A59687; | 
| +  header.flags = PACKET_FLAGS_NONE; | 
| +  header.fec_group = 0; | 
| + | 
| +  QuicRstStreamFragment rst_fragment; | 
| +  rst_fragment.stream_id = 0x01020304; | 
| +  rst_fragment.details = static_cast<QuicErrorCode>(0x05060708); | 
| +  rst_fragment.offset = 0xBA98FEDC32107654; | 
| + | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (rst stream fragment) | 
| +    0x03, | 
| +    // stream id | 
| +    0x04, 0x03, 0x02, 0x01, | 
| +    // offset | 
| +    0x54, 0x76, 0x10, 0x32, | 
| +    0xDC, 0xFE, 0x98, 0xBA, | 
| +    // details | 
| +    0x08, 0x07, 0x06, 0x05, | 
| +  }; | 
| + | 
| +  QuicFragment fragment(&rst_fragment); | 
| + | 
| +  QuicFragments fragments; | 
| +  fragments.push_back(fragment); | 
| + | 
| +  QuicPacket* data; | 
| +  EXPECT_TRUE(framer_.ConstructFragementDataPacket(header, fragments, &data)); | 
| + | 
| +  test::CompareCharArraysWithHexError("constructed packet", | 
| +                                      data->data(), data->length(), | 
| +                                      AsChars(packet), arraysize(packet)); | 
| + | 
| +  delete data; | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, ConstructCloseFragmentPacket) { | 
| +  QuicPacketHeader header; | 
| +  header.guid = 0xFEDCBA9876543210; | 
| +  header.retransmission_count = 0x01; | 
| +  header.packet_sequence_number = 0x123456789ABC; | 
| +  header.transmission_time = 0xF0E1D2C3B4A59687; | 
| +  header.flags = PACKET_FLAGS_NONE; | 
| +  header.fec_group = 0; | 
| + | 
| +  QuicConnectionCloseFragment close_fragment; | 
| +  close_fragment.details = static_cast<QuicErrorCode>(0x05060708); | 
| + | 
| +  QuicAckFragment* ack_fragment = &close_fragment.ack_fragment; | 
| +  ack_fragment->received_info.largest_received = 0x0123456789ABC; | 
| +  ack_fragment->received_info.time_received = 0xF0E1D2C3B4A59687; | 
| +  ack_fragment->received_info.missing_packets.insert(0x0123456789ABB); | 
| +  ack_fragment->received_info.missing_packets.insert(0x0123456789ABA); | 
| +  ack_fragment->sent_info.least_unacked = 0x0123456789AA0; | 
| +  ack_fragment->sent_info.non_retransmiting.insert(0x0123456789AB0); | 
| +  ack_fragment->sent_info.non_retransmiting.insert(0x0123456789AAF); | 
| +  ack_fragment->sent_info.non_retransmiting.insert(0x0123456789AAE); | 
| +  ack_fragment->congestion_info.type = kInterArrival; | 
| +  ack_fragment->congestion_info.inter_arrival.accumulated_number_of_lost_packets | 
| +      = 0x0302; | 
| +  ack_fragment->congestion_info.inter_arrival.offset_time = 0x0504; | 
| +  ack_fragment->congestion_info.inter_arrival.delta_time = 0x0706; | 
| + | 
| +  QuicFragment fragment(&close_fragment); | 
| + | 
| +  QuicFragments fragments; | 
| +  fragments.push_back(fragment); | 
| + | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x00, | 
| +    // fec group | 
| +    0x00, | 
| + | 
| +    // fragment count | 
| +    0x01, | 
| +    // fragment type (connection close fragment) | 
| +    0x04, | 
| +    // details | 
| +    0x08, 0x07, 0x06, 0x05, | 
| + | 
| +    // Ack fragment. | 
| + | 
| +    // largest received packet sequence number | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // time delta | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // num_unacked_packets | 
| +    0x02, | 
| +    // unacked packet sequence number | 
| +    0xBA, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // unacked packet sequence number | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // least packet sequence number awaiting an ack | 
| +    0xA0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // num non retransmitting packets | 
| +    0x03, | 
| +    // non retransmitting packet sequence number | 
| +    0xAE, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xAF, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // non retransmitting packet sequence number | 
| +    0xB0, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // congestion feedback type (inter arrival) | 
| +    0x02, | 
| +    // accumulated_number_of_lost_packets | 
| +    0x02, 0x03, | 
| +    // offset_time | 
| +    0x04, 0x05, | 
| +    // delta_time | 
| +    0x06, 0x07, | 
| +  }; | 
| + | 
| +  QuicPacket* data; | 
| +  EXPECT_TRUE(framer_.ConstructFragementDataPacket(header, fragments, &data)); | 
| + | 
| +  test::CompareCharArraysWithHexError("constructed packet", | 
| +                                      data->data(), data->length(), | 
| +                                      AsChars(packet), arraysize(packet)); | 
| + | 
| +  delete data; | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, ConstructFecPacket) { | 
| +  QuicPacketHeader header; | 
| +  header.guid = 0xFEDCBA9876543210; | 
| +  header.retransmission_count = 0x01; | 
| +  header.packet_sequence_number = 0x123456789ABC; | 
| +  header.transmission_time = 0xF0E1D2C3B4A59687; | 
| +  header.flags = PACKET_FLAGS_FEC; | 
| +  header.fec_group = 1; | 
| + | 
| +  QuicFecData fec_data; | 
| +  fec_data.fec_group = 1; | 
| +  fec_data.first_protected_packet_sequence_number = 0x123456789ABB; | 
| +  fec_data.redundancy = "abcdefghijklmnop"; | 
| + | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x01, | 
| +    // fec group | 
| +    0x01, | 
| +    // first protected packet | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // redundancy | 
| +    'a',  'b',  'c',  'd', | 
| +    'e',  'f',  'g',  'h', | 
| +    'i',  'j',  'k',  'l', | 
| +    'm',  'n',  'o',  'p', | 
| +  }; | 
| + | 
| +  QuicPacket* data; | 
| +  EXPECT_TRUE(framer_.ConstructFecPacket(header, fec_data, &data)); | 
| + | 
| +  test::CompareCharArraysWithHexError("constructed packet", | 
| +                                      data->data(), data->length(), | 
| +                                      AsChars(packet), arraysize(packet)); | 
| + | 
| +  delete data; | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, IncrementRetransmitCount) { | 
| +  QuicPacketHeader header; | 
| +  header.guid = 0xFEDCBA9876543210; | 
| +  header.retransmission_count = 1; | 
| +  header.packet_sequence_number = 0x123456789ABC; | 
| +  header.transmission_time = 0xF0E1D2C3B4A59687; | 
| +  header.flags = PACKET_FLAGS_NONE; | 
| +  header.fec_group = 0; | 
| + | 
| +  QuicStreamFragment stream_fragment; | 
| +  stream_fragment.stream_id = 0x01020304; | 
| +  stream_fragment.fin = true; | 
| +  stream_fragment.offset = 0xBA98FEDC32107654; | 
| +  stream_fragment.data = "hello world!"; | 
| + | 
| +  QuicFragment fragment; | 
| +  fragment.type = STREAM_FRAGMENT; | 
| +  fragment.stream_fragment = &stream_fragment; | 
| + | 
| +  QuicFragments fragments; | 
| +  fragments.push_back(fragment); | 
| + | 
| +  QuicPacket *original; | 
| +  ASSERT_TRUE(framer_.ConstructFragementDataPacket( | 
| +      header, fragments, &original)); | 
| +  EXPECT_EQ(header.retransmission_count, framer_.GetRetransmitCount(original)); | 
| + | 
| +  header.retransmission_count = 2; | 
| +  QuicPacket *retransmitted; | 
| +  ASSERT_TRUE(framer_.ConstructFragementDataPacket( | 
| +      header, fragments, &retransmitted)); | 
| + | 
| +  framer_.IncrementRetransmitCount(original); | 
| +  EXPECT_EQ(header.retransmission_count, framer_.GetRetransmitCount(original)); | 
| + | 
| +  test::CompareCharArraysWithHexError( | 
| +      "constructed packet", original->data(), original->length(), | 
| +      retransmitted->data(), retransmitted->length()); | 
| +  delete original; | 
| +  delete retransmitted; | 
| +} | 
| + | 
| +TEST_F(QuicFramerTest, EncryptPacket) { | 
| +  unsigned char packet[] = { | 
| +    // guid | 
| +    0x10, 0x32, 0x54, 0x76, | 
| +    0x98, 0xBA, 0xDC, 0xFE, | 
| +    // packet id | 
| +    0xBC, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // retransmission count | 
| +    0x01, | 
| +    // transmission time | 
| +    0x87, 0x96, 0xA5, 0xB4, | 
| +    0xC3, 0xD2, 0xE1, 0xF0, | 
| +    // flags | 
| +    0x01, | 
| +    // fec group | 
| +    0x01, | 
| +    // first protected packet | 
| +    0xBB, 0x9A, 0x78, 0x56, | 
| +    0x34, 0x12, | 
| +    // redundancy | 
| +    'a',  'b',  'c',  'd', | 
| +    'e',  'f',  'g',  'h', | 
| +    'i',  'j',  'k',  'l', | 
| +    'm',  'n',  'o',  'p', | 
| +  }; | 
| + | 
| +  scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket( | 
| +      QuicPacket(AsChars(packet), arraysize(packet), false))); | 
| +  ASSERT_TRUE(encrypted.get() != NULL); | 
| +  EXPECT_TRUE(CheckEncryption(StringPiece(AsChars(packet), arraysize(packet)))); | 
| +} | 
| + | 
| +}  // namespace test | 
| + | 
| +}  // namespace net | 
|  |