diff options
author | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-03 07:22:41 +0000 |
---|---|---|
committer | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-03 07:22:41 +0000 |
commit | 5351cc4b92a85cd508cf6944386141945a913f5e (patch) | |
tree | 4f91215a3fb703da4e17f3663f430d02d8f65592 /net | |
parent | 20ba262d5122abe134b6e78ddb574c1a419505ab (diff) | |
download | chromium_src-5351cc4b92a85cd508cf6944386141945a913f5e.zip chromium_src-5351cc4b92a85cd508cf6944386141945a913f5e.tar.gz chromium_src-5351cc4b92a85cd508cf6944386141945a913f5e.tar.bz2 |
Land Recent QUIC Changes
Fix a merging error in the previous checkin.
visitor_ is now a scoped_ptr so the visitor_(NULL) initializer
was removed.
Merge internal change: 43199271
More cleanups that fell out of recent Chrome merges.
Merge internal change: 43195667
Implement framing for version flag and field.
Merge internal change: 43155434
Reduce the usage of magic numbers by moving most of them to quic_protocol.h
Merge internal change: 43133922
Expose functions to calculate offsets and packet sizes from quic_protocol.h.
Merge internal change: 43123088
Various cleanups from landing recent changes in Chrome.
Merge internal change: 43060871
Moving the quic session's write blocked list over such that we won't add a given session multiple times.
Merge internal change: 42920586
Factoring our blocked list out into a separate class.
Merge internal change: 42919835
R=jar@chromium.org
Review URL: https://chromiumcodereview.appspot.com/12374030
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@185797 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
33 files changed, 927 insertions, 329 deletions
diff --git a/net/net.gyp b/net/net.gyp index 8777fc2..12e618a 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -673,6 +673,7 @@ 'proxy/proxy_server_mac.cc', 'proxy/proxy_service.cc', 'proxy/proxy_service.h', + 'quic/blocked_list.h', 'quic/congestion_control/cubic.cc', 'quic/congestion_control/cubic.h', 'quic/congestion_control/fix_rate_receiver.cc', @@ -1521,6 +1522,7 @@ 'proxy/proxy_script_fetcher_impl_unittest.cc', 'proxy/proxy_server_unittest.cc', 'proxy/proxy_service_unittest.cc', + 'quic/blocked_list_test.cc', 'quic/congestion_control/cubic_test.cc', 'quic/congestion_control/fix_rate_test.cc', 'quic/congestion_control/hybrid_slow_start_test.cc', diff --git a/net/quic/blocked_list.h b/net/quic/blocked_list.h new file mode 100644 index 0000000..b6be96d --- /dev/null +++ b/net/quic/blocked_list.h @@ -0,0 +1,91 @@ +// 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. +// +// A combined list/hash set for read or write-blocked entities. + +#ifndef NET_QUIC_BLOCKED_LIST_H_ +#define NET_QUIC_BLOCKED_LIST_H_ + +#include <list> + +#include "base/hash_tables.h" +#include "base/logging.h" + +namespace net { + +template <typename Object> +class BlockedList { + public: + // Called to add an object to the blocked list. This indicates + // the object should be notified when it can use the socket again. + // + // If this object is already on the list, it will not be added again. + void AddBlockedObject(Object object) { + // Only add the object to the list if we successfully add it to the set. + if (object_set_.insert(object).second) { + object_list_.push_back(object); + } + } + + // Called to remove an object from a blocked list. This should be + // called in the event the object is being deleted before the list is. + void RemoveBlockedObject(Object object) { + // Remove the object from the set. We'll check the set before calling + // OnCanWrite on a object from the list. + // + // There is potentially ordering unfairness should a session be removed and + // then readded (as it keeps its position in the list) but it's not worth + // the overhead to walk the list and remove it. + object_set_.erase(object); + } + + // Called when the socket is usable and some objects can access it. Returns + // the first object and removes it from the list. + Object GetNextBlockedObject() { + DCHECK(!IsEmpty()); + + // Walk the list to find the first object which was not removed from the + // set. + while (!object_list_.empty()) { + Object object = *object_list_.begin(); + object_list_.pop_front(); + int removed = object_set_.erase(object); + if (removed > 0) { + return object; + } + } + + // This is a bit of a hack: It's illegal to call GetNextBlockedObject() if + // the list is empty (see DCHECK above) but we must return something. This + // compiles for ints (returns 0) and pointers in the case that someone has a + // bug in their call site. + return 0; + }; + + // Returns the number of objects in the blocked list. + int NumObjects() { + return object_set_.size(); + }; + + // Returns true if there are no objects in the list, false otherwise. + bool IsEmpty() { + return object_set_.empty(); + }; + + private: + // A set tracking the objects. This is the authoritative container for + // determining if an object is blocked. Objects in the list will always + // be in the set. + base::hash_set<Object> object_set_; + // A list tracking the order in which objects were added to the list. + // Objects are added to the back and pulled off the front, but only get + // resumption calls if they're still in the set. + // It's possible to be in the list twice, but only the first entry will get an + // OnCanWrite call. + std::list<Object> object_list_; +}; + +} // namespace net + +#endif // NET_QUIC_BLOCKED_LIST_H_ diff --git a/net/quic/blocked_list_test.cc b/net/quic/blocked_list_test.cc new file mode 100644 index 0000000..074b6f5 --- /dev/null +++ b/net/quic/blocked_list_test.cc @@ -0,0 +1,83 @@ +// 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/blocked_list.h" +#include "net/quic/quic_connection.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(COMPILER_GCC) +namespace BASE_HASH_NAMESPACE { +template<> +struct hash<const int*> { + std::size_t operator()(const int* ptr) const { + return hash<size_t>()(reinterpret_cast<size_t>(ptr)); + } +}; +} +#endif + +namespace net { +namespace test { +namespace { + +class BlockedListTest : public ::testing::Test { + protected: + BlockedListTest() : + item1_(0), + item2_(0), + item3_(0) { + } + + BlockedList<const int*> list_; + const int item1_; + const int item2_; + const int item3_; +}; + +TEST_F(BlockedListTest, BasicAdd) { + list_.AddBlockedObject(&item1_); + list_.AddBlockedObject(&item3_); + list_.AddBlockedObject(&item2_); + ASSERT_EQ(3, list_.NumObjects()); + ASSERT_FALSE(list_.IsEmpty()); + + EXPECT_EQ(&item1_, list_.GetNextBlockedObject()); + EXPECT_EQ(&item3_, list_.GetNextBlockedObject()); + EXPECT_EQ(&item2_, list_.GetNextBlockedObject()); +} + +TEST_F(BlockedListTest, AddAndRemove) { + list_.AddBlockedObject(&item1_); + list_.AddBlockedObject(&item3_); + list_.AddBlockedObject(&item2_); + ASSERT_EQ(3, list_.NumObjects()); + + list_.RemoveBlockedObject(&item3_); + ASSERT_EQ(2, list_.NumObjects()); + + EXPECT_EQ(&item1_, list_.GetNextBlockedObject()); + EXPECT_EQ(&item2_, list_.GetNextBlockedObject()); +} + +TEST_F(BlockedListTest, DuplicateAdd) { + list_.AddBlockedObject(&item1_); + list_.AddBlockedObject(&item3_); + list_.AddBlockedObject(&item2_); + + list_.AddBlockedObject(&item3_); + list_.AddBlockedObject(&item2_); + list_.AddBlockedObject(&item1_); + + ASSERT_EQ(3, list_.NumObjects()); + ASSERT_FALSE(list_.IsEmpty()); + + // Call in the original insert order. + EXPECT_EQ(&item1_, list_.GetNextBlockedObject()); + EXPECT_EQ(&item3_, list_.GetNextBlockedObject()); + EXPECT_EQ(&item2_, list_.GetNextBlockedObject()); +} + +} // namespace +} // namespace test +} // namespace net diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h index 64b258c..dc4c1a5 100644 --- a/net/quic/crypto/crypto_protocol.h +++ b/net/quic/crypto/crypto_protocol.h @@ -65,14 +65,6 @@ struct NET_EXPORT_PRIVATE CryptoHandshakeMessage { CryptoTagValueMap tag_value_map; }; -// Crypto tags are written to the wire with a big-endian -// representation of the name of the tag. For example -// the client hello tag (CHLO) will be written as the -// following 4 bytes: 'C' 'H' 'L' 'O'. Since it is -// stored in memory as a little endian uint32, we need -// to reverse the order of the bytes. -#define MAKE_TAG(a, b, c, d) (d << 24) + (c << 16) + (b << 8) + a - const CryptoTag kCHLO = MAKE_TAG('C', 'H', 'L', 'O'); // Client hello const CryptoTag kSHLO = MAKE_TAG('S', 'H', 'L', 'O'); // Server hello const CryptoTag kSCFG = MAKE_TAG('S', 'H', 'L', 'O'); // Server config diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc index 9e95366..aeb010b 100644 --- a/net/quic/quic_client_session_test.cc +++ b/net/quic/quic_client_session_test.cc @@ -104,7 +104,9 @@ TEST_F(QuicClientSessionTest, Logging) { // TODO(rch): Add some helper methods to simplify packet creation in tests. // Receive a packet, and verify that it was logged. - QuicFramer framer(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); + QuicFramer framer(kQuicVersion1, + QuicDecrypter::Create(kNULL), + QuicEncrypter::Create(kNULL)); QuicRstStreamFrame frame; frame.stream_id = 2; frame.error_code = QUIC_CONNECTION_TIMED_OUT; diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index b61fd91..96dae37 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -41,8 +41,10 @@ const QuicPacketSequenceNumber kMaxPacketGap = 5000; // 16 - Min ack frame size. // 16 - Crypto hash for integrity. Not a static value. Use // QuicEncrypter::GetMaxPlaintextSize. -const QuicPacketSequenceNumber kMaxUnackedPackets = - (kMaxPacketSize - kPacketHeaderSize - 16 - 16) / kSequenceNumberSize; +size_t GetMaxUnackedPackets(bool include_version) { + return (kMaxPacketSize - GetPacketHeaderSize(include_version) - 16 - 16) / + kSequenceNumberSize; +} // We want to make sure if we get a large nack packet, we don't queue up too // many packets at once. 10 is arbitrary. @@ -79,7 +81,9 @@ QuicConnection::QuicConnection(QuicGuid guid, IPEndPoint address, QuicConnectionHelperInterface* helper) : helper_(helper), - framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)), + framer_(kQuicVersion1, + QuicDecrypter::Create(kNULL), + QuicEncrypter::Create(kNULL)), clock_(helper->GetClock()), random_generator_(helper->GetRandomGenerator()), guid_(guid), @@ -221,7 +225,8 @@ void QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) { // peer_largest_observed_packet. Fix either by resetting it in // MaybeRetransmitPacketForRTO or keeping an explicit flag for ack truncation. received_truncated_ack_ = - incoming_ack.received_info.missing_packets.size() >= kMaxUnackedPackets; + incoming_ack.received_info.missing_packets.size() >= + GetMaxUnackedPackets(last_header_.public_header.version_flag); UpdatePacketInformationReceivedByPeer(incoming_ack); UpdatePacketInformationSentByPeer(incoming_ack); @@ -276,7 +281,7 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) { // We can't have too many unacked packets, or our ack frames go over // kMaxPacketSize. DCHECK_LE(incoming_ack.received_info.missing_packets.size(), - kMaxUnackedPackets); + GetMaxUnackedPackets(last_header_.public_header.version_flag)); if (incoming_ack.sent_info.least_unacked < peer_least_packet_awaiting_ack_) { DLOG(ERROR) << "Client sent low least_unacked: " @@ -790,16 +795,16 @@ bool QuicConnection::OnSerializedPacket( unacked_packets_.rbegin()->first < serialized_packet.sequence_number); unacked_packets_.insert( - make_pair(serialized_packet.sequence_number, - serialized_packet.retransmittable_frames)); + make_pair(serialized_packet.sequence_number, + serialized_packet.retransmittable_frames)); // All unacked packets might be retransmitted. retransmission_map_.insert( make_pair(serialized_packet.sequence_number, RetransmissionInfo(serialized_packet.sequence_number))); } return SendOrQueuePacket(serialized_packet.sequence_number, - serialized_packet.packet, - serialized_packet.entropy_hash); + serialized_packet.packet, + serialized_packet.entropy_hash); } bool QuicConnection::SendOrQueuePacket(QuicPacketSequenceNumber sequence_number, diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc index cc6288f..1d0c062 100644 --- a/net/quic/quic_connection_helper_test.cc +++ b/net/quic/quic_connection_helper_test.cc @@ -58,7 +58,9 @@ class QuicConnectionHelperTest : public ::testing::Test { QuicConnectionHelperTest() : guid_(2), - framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)), + framer_(kQuicVersion1, + QuicDecrypter::Create(kNULL), + QuicEncrypter::Create(kNULL)), creator_(guid_, &framer_, QuicRandom::GetInstance()), net_log_(BoundNetLog()), frame_(1, false, 0, kData) { diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index a6e4e60..8f4fdbf 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -96,7 +96,8 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { virtual int WritePacketToWire(const QuicEncryptedPacket& packet, int* error) OVERRIDE { - QuicFramer framer(QuicDecrypter::Create(kNULL), + QuicFramer framer(kQuicVersion1, + QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); FramerVisitorCapturingFrames visitor; framer.set_visitor(&visitor); @@ -151,13 +152,15 @@ class TestConnectionHelper : public QuicConnectionHelperInterface { QuicPacketHeader* header() { return &header_; } - size_t frame_count() { return frame_count_; } + size_t frame_count() const { return frame_count_; } QuicAckFrame* ack() { return ack_.get(); } QuicCongestionFeedbackFrame* feedback() { return feedback_.get(); } - const vector<QuicStreamFrame>* stream_frames() { return &stream_frames_; } + const vector<QuicStreamFrame>* stream_frames() const { + return &stream_frames_; + } void set_blocked(bool blocked) { blocked_ = blocked; } @@ -216,7 +219,9 @@ class QuicConnectionTest : public ::testing::Test { protected: QuicConnectionTest() : guid_(42), - framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)), + framer_(kQuicVersion1, + QuicDecrypter::Create(kNULL), + QuicEncrypter::Create(kNULL)), creator_(guid_, &framer_, QuicRandom::GetInstance()), send_algorithm_(new StrictMock<MockSendAlgorithm>), helper_(new TestConnectionHelper(&clock_, &random_generator_)), @@ -338,8 +343,9 @@ class QuicConnectionTest : public ::testing::Test { // redundancy is either equal to that payload or the xor of that payload // with itself, depending on the number of packets. if (((number - min_protected_packet) % 2) == 0) { - for (size_t i = kStartOfFecProtectedData; i < data_packet->length(); - ++i) { + for (size_t i = GetStartOfFecProtectedData( + header_.public_header.version_flag); + i < data_packet->length(); ++i) { data_packet->mutable_data()[i] ^= data_packet->data()[i]; } } @@ -723,9 +729,8 @@ TEST_F(QuicConnectionTest, BasicSending) { TEST_F(QuicConnectionTest, FECSending) { // Limit to one byte per packet. - size_t ciphertext_size = NullEncrypter().GetCiphertextSize(1); connection_.options()->max_packet_length = - ciphertext_size + QuicUtils::StreamFramePacketOverhead(1); + GetPacketLengthForOneStream(!kIncludeVersion, 1); // And send FEC every two packets. connection_.options()->max_packets_per_fec_group = 2; @@ -738,9 +743,8 @@ TEST_F(QuicConnectionTest, FECSending) { TEST_F(QuicConnectionTest, FECQueueing) { // Limit to one byte per packet. - size_t ciphertext_size = NullEncrypter().GetCiphertextSize(1); connection_.options()->max_packet_length = - ciphertext_size + QuicUtils::StreamFramePacketOverhead(1); + GetPacketLengthForOneStream(!kIncludeVersion, 1); // And send FEC every two packets. connection_.options()->max_packets_per_fec_group = 2; @@ -1325,9 +1329,8 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenSend) { } TEST_F(QuicConnectionTest, SendSchedulerDelayThenRetransmit) { - EXPECT_CALL(*send_algorithm_, - TimeUntilSend(_, !kIsRetransmission)).WillRepeatedly( - testing::Return(QuicTime::Delta::Zero())); + EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)) + .WillRepeatedly(testing::Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, !kIsRetransmission)); connection_.SendStreamData(1, "foo", 0, !kFin); EXPECT_EQ(0u, connection_.NumQueuedPackets()); @@ -1421,9 +1424,8 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) { TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) { // Limit to one byte per packet. - size_t ciphertext_size = NullEncrypter().GetCiphertextSize(1); connection_.options()->max_packet_length = - ciphertext_size + QuicUtils::StreamFramePacketOverhead(1); + GetPacketLengthForOneStream(!kIncludeVersion, 1); // Queue the first packet. EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, !kIsRetransmission)).WillOnce( @@ -1435,9 +1437,8 @@ TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) { TEST_F(QuicConnectionTest, LoopThroughSendingPackets) { // Limit to one byte per packet. - size_t ciphertext_size = NullEncrypter().GetCiphertextSize(1); connection_.options()->max_packet_length = - ciphertext_size + QuicUtils::StreamFramePacketOverhead(1); + GetPacketLengthForOneStream(!kIncludeVersion, 1); // Queue the first packet. EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(17); diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc index 262b108..2395607 100644 --- a/net/quic/quic_crypto_client_stream_test.cc +++ b/net/quic/quic_crypto_client_stream_test.cc @@ -83,7 +83,8 @@ class TestMockHelper : public MockHelper { void TestMockHelper::CheckClientHelloPacket( const QuicEncryptedPacket& packet) { - QuicFramer quic_framer(QuicDecrypter::Create(kNULL), + QuicFramer quic_framer(kQuicVersion1, + QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); TestQuicVisitor quic_visitor; quic_framer.set_visitor(&quic_visitor); diff --git a/net/quic/quic_fec_group.h b/net/quic/quic_fec_group.h index f9d4e28..e421074 100644 --- a/net/quic/quic_fec_group.h +++ b/net/quic/quic_fec_group.h @@ -88,6 +88,8 @@ class NET_EXPORT_PRIVATE QuicFecGroup { char payload_parity_[kMaxPacketSize]; size_t payload_parity_len_; bool entropy_parity_; + + DISALLOW_COPY_AND_ASSIGN(QuicFecGroup); }; } // namespace net diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index db3de8d5..af8e4f9 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc @@ -43,13 +43,17 @@ QuicPacketSequenceNumber ClosestTo(QuicPacketSequenceNumber target, } // namespace -QuicFramer::QuicFramer(QuicDecrypter* decrypter, QuicEncrypter* encrypter) +QuicFramer::QuicFramer(QuicVersionTag version, + QuicDecrypter* decrypter, + QuicEncrypter* encrypter) : visitor_(NULL), fec_builder_(NULL), error_(QUIC_NO_ERROR), last_sequence_number_(0), + quic_version_(version), decrypter_(decrypter), encrypter_(encrypter) { + DCHECK_EQ(kQuicVersion1, version); } QuicFramer::~QuicFramer() {} @@ -62,14 +66,43 @@ bool CanTruncate(const QuicFrame& frame) { return false; } +// static +size_t QuicFramer::GetMinStreamFrameSize() { + return kQuicFrameTypeSize + kQuicStreamIdSize + + kQuicStreamFinSize + kQuicStreamOffsetSize + kQuicStreamPayloadLengthSize; +} + +// static +size_t QuicFramer::GetMinAckFrameSize() { + return kQuicFrameTypeSize + kQuicEntropyHashSize + kSequenceNumberSize + + kQuicEntropyHashSize + kSequenceNumberSize + kNumberOfMissingPacketsSize; +} + +// static +size_t QuicFramer::GetMinRstStreamFrameSize() { + return kQuicFrameTypeSize + kQuicStreamIdSize + kQuicErrorCodeSize + + kQuicErrorDetailsLengthSize; +} + +// static +size_t QuicFramer::GetMinConnectionCloseFrameSize() { + return kQuicFrameTypeSize + kQuicErrorCodeSize + kQuicErrorDetailsLengthSize + + GetMinAckFrameSize(); +} + +// static +size_t QuicFramer::GetMinGoAwayFrameSize() { + return kQuicFrameTypeSize + kQuicErrorCodeSize + kQuicErrorDetailsLengthSize + + kQuicStreamIdSize; +} + size_t QuicFramer::GetSerializedFrameLength( const QuicFrame& frame, size_t free_bytes, bool first_frame) { if (frame.type == PADDING_FRAME) { // PADDING implies end of packet. return free_bytes; } - size_t frame_len = kFrameTypeSize; - frame_len += ComputeFramePayloadLength(frame); + size_t frame_len = ComputeFrameLength(frame); if (frame_len > free_bytes) { // Only truncate the first frame in a packet, so if subsequent ones go // over, stop including more frames. @@ -100,7 +133,7 @@ SerializedPacket QuicFramer::ConstructFrameDataPacket( const QuicPacketHeader& header, const QuicFrames& frames) { const size_t max_plaintext_size = GetMaxPlaintextSize(kMaxPacketSize); - size_t packet_size = kPacketHeaderSize; + size_t packet_size = GetPacketHeaderSize(header.public_header.version_flag); for (size_t i = 0; i < frames.size(); ++i) { DCHECK_LE(packet_size, max_plaintext_size); const size_t frame_size = GetSerializedFrameLength( @@ -174,7 +207,8 @@ SerializedPacket QuicFramer::ConstructFrameDataPacket( // Less than or equal because truncated acks end up with max_plaintex_size // length, even though they're typically slightly shorter. DCHECK_LE(len, packet_size); - QuicPacket* packet = QuicPacket::NewDataPacket(writer.take(), len, true); + QuicPacket* packet = QuicPacket::NewDataPacket( + writer.take(), len, true, header.public_header.version_flag); if (fec_builder_) { fec_builder_->OnBuiltFecProtectedPayload(header, @@ -187,7 +221,7 @@ SerializedPacket QuicFramer::ConstructFrameDataPacket( SerializedPacket QuicFramer::ConstructFecPacket(const QuicPacketHeader& header, const QuicFecData& fec) { - size_t len = kPacketHeaderSize; + size_t len = GetPacketHeaderSize(header.public_header.version_flag); len += fec.redundancy.length(); QuicDataWriter writer(len); @@ -201,7 +235,9 @@ SerializedPacket QuicFramer::ConstructFecPacket(const QuicPacketHeader& header, } return SerializedPacket(header.packet_sequence_number, - QuicPacket::NewFecPacket(writer.take(), len, true), + QuicPacket::NewFecPacket( + writer.take(), len, true, + header.public_header.version_flag), GetPacketEntropyHash(header), NULL); } @@ -210,7 +246,7 @@ QuicEncryptedPacket* QuicFramer::ConstructPublicResetPacket( const QuicPublicResetPacket& packet) { DCHECK(packet.public_header.reset_flag); DCHECK(!packet.public_header.version_flag); - size_t len = kPublicResetPacketSize; + size_t len = GetPublicResetPacketSize(); QuicDataWriter writer(len); if (!writer.WriteUInt64(packet.public_header.guid)) { @@ -245,6 +281,10 @@ bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) { reader_.reset(NULL); return RaiseError(QUIC_INVALID_PACKET_HEADER); } + // TODO(satyamshekhar): Handle version negotiation. + if (public_header.version_flag && public_header.version != quic_version_) { + return false; + } bool rv; if (public_header.reset_flag) { @@ -361,6 +401,10 @@ bool QuicFramer::WritePacketHeader(const QuicPacketHeader& header, return false; } + if (header.public_header.version_flag) { + writer->WriteUInt32(quic_version_); + } + if (!AppendPacketSequenceNumber(header.packet_sequence_number, writer)) { return false; } @@ -436,6 +480,12 @@ bool QuicFramer::ProcessPublicHeader(QuicPacketPublicHeader* public_header) { public_header->version_flag = (public_flags & PACKET_PUBLIC_FLAGS_VERSION) != 0; + if (public_header->version_flag && + !reader_->ReadUInt32(&public_header->version)) { + set_detailed_error("Unable to read protocol version."); + return false; + } + return true; } @@ -459,7 +509,9 @@ bool QuicFramer::ProcessPacketHeader( return false; } - if (!DecryptPayload(header->packet_sequence_number, packet)) { + if (!DecryptPayload(header->packet_sequence_number, + header->public_header.version_flag, + packet)) { DLOG(WARNING) << "Unable to decrypt payload."; return RaiseError(QUIC_DECRYPTION_FAILURE); } @@ -833,6 +885,13 @@ bool QuicFramer::ProcessGoAwayFrame() { return true; } +StringPiece QuicFramer::GetAssociatedDataFromEncryptedPacket( + const QuicEncryptedPacket& encrypted, bool includes_version) { + return StringPiece(encrypted.data() + kStartOfHashData, + GetStartOfEncryptedData(includes_version) + - kStartOfHashData); +} + QuicEncryptedPacket* QuicFramer::EncryptPacket( QuicPacketSequenceNumber packet_sequence_number, const QuicPacket& packet) { @@ -843,11 +902,12 @@ QuicEncryptedPacket* QuicFramer::EncryptPacket( RaiseError(QUIC_ENCRYPTION_FAILURE); return NULL; } - size_t len = kStartOfEncryptedData + out->length(); + StringPiece header_data = packet.BeforePlaintext(); + size_t len = header_data.length() + out->length(); char* buffer = new char[len]; // TODO(rch): eliminate this buffer copy by passing in a buffer to Encrypt(). - memcpy(buffer, packet.data(), kStartOfEncryptedData); - memcpy(buffer + kStartOfEncryptedData, out->data(), out->length()); + memcpy(buffer, header_data.data(), header_data.length()); + memcpy(buffer + header_data.length(), out->data(), out->length()); return new QuicEncryptedPacket(buffer, len, true); } @@ -856,14 +916,17 @@ size_t QuicFramer::GetMaxPlaintextSize(size_t ciphertext_size) { } bool QuicFramer::DecryptPayload(QuicPacketSequenceNumber sequence_number, + bool version_flag, const QuicEncryptedPacket& packet) { StringPiece encrypted; if (!reader_->ReadStringPiece(&encrypted, reader_->BytesRemaining())) { return false; } DCHECK(decrypter_.get() != NULL); - decrypted_.reset(decrypter_->Decrypt(sequence_number, - packet.AssociatedData(), encrypted)); + decrypted_.reset(decrypter_->Decrypt( + sequence_number, + GetAssociatedDataFromEncryptedPacket(packet, version_flag), + encrypted)); if (decrypted_.get() == NULL) { return false; } @@ -872,29 +935,17 @@ bool QuicFramer::DecryptPayload(QuicPacketSequenceNumber sequence_number, return true; } -size_t QuicFramer::ComputeFramePayloadLength(const QuicFrame& frame) { - size_t len = 0; - // We use "magic numbers" here because sizeof(member_) is not necessarily the - // same as sizeof(member_wire_format). +size_t QuicFramer::ComputeFrameLength(const QuicFrame& frame) { switch (frame.type) { case STREAM_FRAME: - len += 4; // Stream id of the frame. - len += 1; // A byte for fin. - len += 8; // Byte offset. - len += 2; // Space for the 16 bit length. - len += frame.stream_frame->data.size(); - break; + return GetMinStreamFrameSize() + frame.stream_frame->data.size(); case ACK_FRAME: { const QuicAckFrame& ack = *frame.ack_frame; - len += 1; // Commutative hash of entropy of the packets received. - len += 6; // Least packet sequence number awaiting an ack. - len += 1; // Hash of entropy of the packets sent up to largest observed. - len += 6; // Largest observed packet sequence number. - len += 1; // Number of missing packets. - len += 6 * ack.received_info.missing_packets.size(); - break; + return GetMinAckFrameSize() + + kSequenceNumberSize * ack.received_info.missing_packets.size(); } case CONGESTION_FEEDBACK_FRAME: { + size_t len = kQuicFrameTypeSize; const QuicCongestionFeedbackFrame& congestion_feedback = *frame.congestion_feedback_frame; len += 1; // Congestion feedback type. @@ -906,10 +957,11 @@ size_t QuicFramer::ComputeFramePayloadLength(const QuicFrame& frame) { len += 2; len += 1; // Number received packets. if (inter_arrival.received_packet_times.size() > 0) { - len += 6; // Smallest received. + len += kSequenceNumberSize; // Smallest received. len += 8; // Time. // 2 bytes per sequence number delta plus 4 bytes per delta time. - len += 6 * (inter_arrival.received_packet_times.size() - 1); + len += kSequenceNumberSize * + (inter_arrival.received_packet_times.size() - 1); } break; } @@ -924,33 +976,29 @@ size_t QuicFramer::ComputeFramePayloadLength(const QuicFrame& frame) { DLOG(INFO) << "Illegal feedback type: " << congestion_feedback.type; break; } - break; + return len; } case RST_STREAM_FRAME: - len += 4; // Stream id of the frame. - len += 4; // Error code. - len += 2; // Error details size. - len += frame.rst_stream_frame->error_details.size(); - break; - case CONNECTION_CLOSE_FRAME: - len += 4; // Error code. - len += 2; // Error details size. - len += frame.connection_close_frame->error_details.size(); - len += ComputeFramePayloadLength( - QuicFrame(&frame.connection_close_frame->ack_frame)); - break; + return GetMinRstStreamFrameSize() + + frame.rst_stream_frame->error_details.size(); + case CONNECTION_CLOSE_FRAME: { + const QuicAckFrame& ack = frame.connection_close_frame->ack_frame; + return GetMinConnectionCloseFrameSize() + + frame.connection_close_frame->error_details.size() + + kSequenceNumberSize * ack.received_info.missing_packets.size(); + } case GOAWAY_FRAME: - len += 4; // error code - len += 4; // last good stream id - len += 2; // reason phrase length - len += frame.goaway_frame->reason_phrase.size(); - break; - default: - set_detailed_error("Illegal frame type."); - DLOG(INFO) << "Illegal frame type: " << frame.type; - break; + return GetMinGoAwayFrameSize() + frame.goaway_frame->reason_phrase.size(); + case PADDING_FRAME: + DCHECK(false); + return 0; + case NUM_FRAME_TYPES: + DCHECK(false); + return 0; } - return len; + // Not reachable, but some Chrome compilers can't figure that out. + DCHECK(false); + return 0; } // static diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h index bcf551c..008c99d 100644 --- a/net/quic/quic_framer.h +++ b/net/quic/quic_framer.h @@ -26,6 +26,27 @@ class QuicDecrypter; class QuicEncrypter; class QuicFramer; +// Number of bytes reserved for the frame type preceding each frame. +const size_t kQuicFrameTypeSize = 1; +// Number of bytes reserved for error code. +const size_t kQuicErrorCodeSize = 4; +// Number of bytes reserved to denote the length of error details field. +const size_t kQuicErrorDetailsLengthSize = 2; + +// Number of bytes reserved for stream id +const size_t kQuicStreamIdSize = 4; +// Number of bytes reserved for fin flag in stream frame. +const size_t kQuicStreamFinSize = 1; +// Number of bytes reserved for byte offset in stream frame. +const size_t kQuicStreamOffsetSize = 8; +// Number of bytes reserved to store payload length in stream frame. +const size_t kQuicStreamPayloadLengthSize = 2; + +// Size in bytes of the entropy hash sent in ack frames. +const size_t kQuicEntropyHashSize = 1; +// Size in bytes reserved for the number of missing packets in ack frames. +const size_t kNumberOfMissingPacketsSize = 1; + // This class receives callbacks from the framer when packets // are processed. class NET_EXPORT_PRIVATE QuicFramerVisitorInterface { @@ -115,7 +136,9 @@ class NET_EXPORT_PRIVATE QuicReceivedEntropyHashCalculatorInterface { class NET_EXPORT_PRIVATE QuicFramer { public: // Constructs a new framer that will own |decrypter| and |encrypter|. - QuicFramer(QuicDecrypter* decrypter, QuicEncrypter* encrypter); + QuicFramer(QuicVersionTag quic_version, + QuicDecrypter* decrypter, + QuicEncrypter* encrypter); virtual ~QuicFramer(); @@ -141,6 +164,10 @@ class NET_EXPORT_PRIVATE QuicFramer { fec_builder_ = builder; } + QuicVersionTag version() const { + return quic_version_; + } + // Set entropy calculator to be called from the framer when it needs the // entropy of a truncated ack frame. An entropy calculator must be set or else // the framer will likely crash. If this is called multiple times, only the @@ -168,12 +195,29 @@ class NET_EXPORT_PRIVATE QuicFramer { bool ProcessRevivedPacket(QuicPacketHeader* header, base::StringPiece payload); + // Size in bytes of all stream frame fields without the payload. + static size_t GetMinStreamFrameSize(); + // Size in bytes of all ack frame fields without the missing packets. + static size_t GetMinAckFrameSize(); + // Size in bytes of all reset stream frame without the error details. + static size_t GetMinRstStreamFrameSize(); + // Size in bytes of all connection close frame fields without the error + // details and the missing packets from the enclosed ack frame. + static size_t GetMinConnectionCloseFrameSize(); + // Size in bytes of all GoAway frame fields without the reason phrase. + static size_t GetMinGoAwayFrameSize(); + // Returns the number of bytes added to the packet for the specified frame, // and 0 if the frame doesn't fit. Includes the header size for the first // frame. size_t GetSerializedFrameLength( const QuicFrame& frame, size_t free_bytes, bool first_frame); + // Returns the associated data from the encrypted packet |encrypted| as a + // stringpiece. + static base::StringPiece GetAssociatedDataFromEncryptedPacket( + const QuicEncryptedPacket& encrypted, bool includes_version); + // Returns a SerializedPacket whose |packet| member is owned by the caller, // and is populated with the fields in |header| and |frames|, or is NULL if // the packet could not be created. @@ -192,7 +236,7 @@ class NET_EXPORT_PRIVATE QuicFramer { // and is populated with the fields in |header| and |fec|, or is NULL if the // packet could not be created. SerializedPacket ConstructFecPacket(const QuicPacketHeader& header, - const QuicFecData& fec); + const QuicFecData& fec); // Returns a new public reset packet, owned by the caller. static QuicEncryptedPacket* ConstructPublicResetPacket( @@ -245,6 +289,7 @@ class NET_EXPORT_PRIVATE QuicFramer { bool ProcessGoAwayFrame(); bool DecryptPayload(QuicPacketSequenceNumber packet_sequence_number, + bool version_flag, const QuicEncryptedPacket& packet); // Returns the full packet sequence number from the truncated @@ -253,7 +298,7 @@ class NET_EXPORT_PRIVATE QuicFramer { QuicPacketSequenceNumber packet_sequence_number) const; // Computes the wire size in bytes of the payload of |frame|. - size_t ComputeFramePayloadLength(const QuicFrame& frame); + size_t ComputeFrameLength(const QuicFrame& frame); static bool AppendPacketSequenceNumber( QuicPacketSequenceNumber packet_sequence_number, @@ -292,6 +337,8 @@ class NET_EXPORT_PRIVATE QuicFramer { QuicPacketSequenceNumber last_sequence_number_; // Buffer containing decrypted payload data during parsing. scoped_ptr<QuicData> decrypted_; + // Version of the protocol being used. + QuicVersionTag quic_version_; // Decrypter used to decrypt packets during parsing. scoped_ptr<QuicDecrypter> decrypter_; // Encrypter used to encrypt packets via EncryptPacket(). diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index a0170f2..eeecd08 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc @@ -33,6 +33,37 @@ namespace test { const QuicPacketSequenceNumber kEpoch = GG_UINT64_C(1) << 48; const QuicPacketSequenceNumber kMask = kEpoch - 1; +// Index into the guid offset in the header. +const size_t kGuidOffset = 0; +// Index into the flags offset in the header. +const size_t kPublicFlagsOffset = kQuicGuidSize; +// Index into the version string in the header. (if present). +const size_t kVersionOffset = kPublicFlagsOffset + kPublicFlagsSize; + +// Index into the sequence number offset in the header. +size_t GetSequenceNumberOffset(bool include_version) { + return kPublicFlagsOffset + kPublicFlagsSize + + (include_version ? kQuicVersionSize : 0); +} + +// Index into the private flags offset in the data packet header. +size_t GetPrivateFlagsOffset(bool include_version) { + return GetSequenceNumberOffset(include_version) + kSequenceNumberSize; +} + +// Index into the fec group offset in the header. +size_t GetFecGroupOffset(bool include_version) { + return GetPrivateFlagsOffset(include_version) + kPrivateFlagsSize; +} + +// Index into the nonce proof of the public reset packet. +const size_t kPublicResetPacketNonceProofOffset = + kPublicFlagsOffset + + kPublicFlagsSize; +// Index into the rejected sequence number of the public reset packet. +const size_t kPublicResetPacketRejectedSequenceNumberOffset = + kPublicResetPacketNonceProofOffset + kPublicResetNonceSize; + class QuicFramerPeer { public: static QuicPacketSequenceNumber CalculatePacketSequenceNumberFromWire( @@ -59,7 +90,7 @@ class TestEncrypter : public QuicEncrypter { } virtual QuicData* Encrypt(QuicPacketSequenceNumber sequence_number, StringPiece associated_data, - StringPiece plaintext) OVERRIDE{ + StringPiece plaintext) OVERRIDE { sequence_number_ = sequence_number; associated_data_ = associated_data.as_string(); plaintext_ = plaintext.as_string(); @@ -68,7 +99,7 @@ class TestEncrypter : public QuicEncrypter { virtual size_t GetKeySize() const OVERRIDE { return 0; } - virtual size_t GetNoncePrefixSize() const OVERRIDE{ + virtual size_t GetNoncePrefixSize() const OVERRIDE { return 0; } virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) const OVERRIDE { @@ -93,7 +124,7 @@ class TestDecrypter : public QuicDecrypter { } virtual QuicData* Decrypt(QuicPacketSequenceNumber sequence_number, StringPiece associated_data, - StringPiece ciphertext) OVERRIDE{ + StringPiece ciphertext) OVERRIDE { sequence_number_ = sequence_number; associated_data_ = associated_data.as_string(); ciphertext_ = ciphertext.as_string(); @@ -215,39 +246,36 @@ class QuicFramerTest : public ::testing::Test { QuicFramerTest() : encrypter_(new test::TestEncrypter()), decrypter_(new test::TestDecrypter()), - framer_(decrypter_, encrypter_) { + framer_(kQuicVersion1, decrypter_, encrypter_) { framer_.set_visitor(&visitor_); framer_.set_entropy_calculator(&entropy_calculator_); } bool CheckEncryption(QuicPacketSequenceNumber sequence_number, - StringPiece packet) { + QuicPacket* packet) { if (sequence_number != encrypter_->sequence_number_) { LOG(ERROR) << "Encrypted incorrect packet sequence number. expected " << sequence_number << " actual: " << encrypter_->sequence_number_; return false; } - StringPiece associated_data( - packet.substr(kStartOfHashData, - kStartOfEncryptedData - kStartOfHashData)); - if (associated_data != encrypter_->associated_data_) { + if (packet->AssociatedData() != encrypter_->associated_data_) { LOG(ERROR) << "Encrypted incorrect associated data. expected " - << associated_data << " actual: " + << packet->AssociatedData() << " actual: " << encrypter_->associated_data_; return false; } - StringPiece plaintext(packet.substr(kStartOfEncryptedData)); - if (plaintext != encrypter_->plaintext_) { + if (packet->Plaintext() != encrypter_->plaintext_) { LOG(ERROR) << "Encrypted incorrect plaintext data. expected " - << plaintext << " actual: " + << packet->Plaintext() << " actual: " << encrypter_->plaintext_; return false; } return true; } - bool CheckDecryption(StringPiece packet) { + 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 " @@ -255,16 +283,16 @@ class QuicFramerTest : public ::testing::Test { << decrypter_->sequence_number_; return false; } - StringPiece associated_data( - packet.substr(kStartOfHashData, - kStartOfEncryptedData - kStartOfHashData)); - if (associated_data != decrypter_->associated_data_) { + if (QuicFramer::GetAssociatedDataFromEncryptedPacket( + encrypted, includes_version) != decrypter_->associated_data_) { LOG(ERROR) << "Decrypted incorrect associated data. expected " - << associated_data << " actual: " - << decrypter_->associated_data_; + << QuicFramer::GetAssociatedDataFromEncryptedPacket( + encrypted, includes_version) + << " actual: " << decrypter_->associated_data_; return false; } - StringPiece ciphertext(packet.substr(kStartOfEncryptedData)); + StringPiece ciphertext(encrypted.AsStringPiece().substr( + GetStartOfEncryptedData(includes_version))); if (ciphertext != decrypter_->ciphertext_) { LOG(ERROR) << "Decrypted incorrect chipertext data. expected " << ciphertext << " actual: " @@ -437,7 +465,8 @@ TEST_F(QuicFramerTest, LargePacket) { 0xFF }; - memset(packet + kPacketHeaderSize, 0, kMaxPacketSize - kPacketHeaderSize + 1); + memset(packet + GetPacketHeaderSize(!kIncludeVersion), 0, + kMaxPacketSize - GetPacketHeaderSize(!kIncludeVersion) + 1); QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); @@ -483,15 +512,70 @@ TEST_F(QuicFramerTest, PacketHeader) { EXPECT_EQ(0x00u, visitor_.header_->fec_group); // Now test framing boundaries - for (size_t i = 0; i < kPacketHeaderSize; ++i) { + for (size_t i = 0; i < GetPacketHeaderSize(!kIncludeVersion); ++i) { + string expected_error; + if (i < kPublicFlagsOffset) { + expected_error = "Unable to read GUID."; + } else if (i < GetSequenceNumberOffset(!kIncludeVersion)) { + expected_error = "Unable to read public flags."; + } 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_F(QuicFramerTest, PacketHeaderWithVersionFlag) { + unsigned char packet[] = { + // guid + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // public flags (version) + 0x01, + // version tag + 'Q', '1', '.', '0', + // packet sequence number + 0xBC, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags + 0x00, + // first fec protected packet offset + 0xFF, + }; + + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210), + visitor_.header_->public_header.guid); + EXPECT_FALSE(visitor_.header_->public_header.reset_flag); + EXPECT_TRUE(visitor_.header_->public_header.version_flag); + EXPECT_EQ(kQuicVersion1, visitor_.header_->public_header.version); + EXPECT_FALSE(visitor_.header_->fec_flag); + EXPECT_FALSE(visitor_.header_->entropy_flag); + EXPECT_FALSE(visitor_.header_->fec_entropy_flag); + EXPECT_EQ(0, visitor_.header_->entropy_hash); + EXPECT_EQ(GG_UINT64_C(0x123456789ABC), + visitor_.header_->packet_sequence_number); + EXPECT_EQ(0x00u, visitor_.header_->fec_group); + + // Now test framing boundaries + for (size_t i = 0; i < GetPacketHeaderSize(kIncludeVersion); ++i) { string expected_error; if (i < kPublicFlagsOffset) { expected_error = "Unable to read GUID."; - } else if (i < kSequenceNumberOffset) { + } else if (i < kVersionOffset) { expected_error = "Unable to read public flags."; - } else if (i < kPrivateFlagsOffset) { + } 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 < kFecGroupOffset) { + } else if (i < GetFecGroupOffset(kIncludeVersion)) { expected_error = "Unable to read private flags."; } else { expected_error = "Unable to read first fec protected packet offset."; @@ -500,6 +584,7 @@ TEST_F(QuicFramerTest, PacketHeader) { } } + TEST_F(QuicFramerTest, InvalidPublicFlag) { unsigned char packet[] = { // guid @@ -611,29 +696,93 @@ TEST_F(QuicFramerTest, PaddingFrame) { EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + 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(!kIncludeVersion), + "Unable to read frame type.", QUIC_INVALID_FRAME_DATA); +} + +TEST_F(QuicFramerTest, StreamFrame) { + unsigned char packet[] = { + // guid + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // public flags + 0x00, + // packet sequence number + 0xBC, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags + 0x00, + // first fec protected packet offset + 0xFF, + + // frame type (stream frame) + 0x01, + // 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', '!', + }; + + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); + + ASSERT_EQ(1u, visitor_.stream_frames_.size()); + EXPECT_EQ(0u, visitor_.ack_frames_.size()); + EXPECT_EQ(static_cast<uint64>(0x01020304), + visitor_.stream_frames_[0]->stream_id); + EXPECT_TRUE(visitor_.stream_frames_[0]->fin); + EXPECT_EQ(GG_UINT64_C(0xBA98FEDC32107654), + visitor_.stream_frames_[0]->offset); + EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data); // Now test framing boundaries - for (size_t i = 0; i < 1; ++i) { + for (size_t i = 0; i < QuicFramer::GetMinStreamFrameSize(); ++i) { string expected_error; - if (i < 1) { + if (i < kQuicFrameTypeSize) { expected_error = "Unable to read frame type."; + } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize) { + expected_error = "Unable to read stream_id."; + } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize + + kQuicStreamFinSize) { + expected_error = "Unable to read fin."; + } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize + + kQuicStreamFinSize + kQuicStreamOffsetSize) { + expected_error = "Unable to read offset."; + } else { + expected_error = "Unable to read frame data."; } - CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, - QUIC_INVALID_FRAME_DATA); + CheckProcessingFails(packet, i + GetPacketHeaderSize(!kIncludeVersion), + expected_error, QUIC_INVALID_FRAME_DATA); } } -TEST_F(QuicFramerTest, StreamFrame) { +TEST_F(QuicFramerTest, StreamFrameWithVersion) { unsigned char packet[] = { // guid 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // public flags - 0x00, + // public flags (version) + 0x01, + // version tag + 'Q', '1', '.', '0', // packet sequence number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, @@ -664,7 +813,9 @@ TEST_F(QuicFramerTest, StreamFrame) { EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(visitor_.header_.get()->public_header.version_flag); + EXPECT_EQ(kQuicVersion1, visitor_.header_.get()->public_header.version); + EXPECT_TRUE(CheckDecryption(encrypted, kIncludeVersion)); ASSERT_EQ(1u, visitor_.stream_frames_.size()); EXPECT_EQ(0u, visitor_.ack_frames_.size()); @@ -676,21 +827,23 @@ TEST_F(QuicFramerTest, StreamFrame) { EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data); // Now test framing boundaries - for (size_t i = 0; i < 28; ++i) { + for (size_t i = 0; i < QuicFramer::GetMinStreamFrameSize(); ++i) { string expected_error; - if (i < 1) { + if (i < kQuicFrameTypeSize) { expected_error = "Unable to read frame type."; - } else if (i < 5) { + } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize) { expected_error = "Unable to read stream_id."; - } else if (i < 6) { + } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize + + kQuicStreamFinSize) { expected_error = "Unable to read fin."; - } else if (i < 14) { + } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize + + kQuicStreamFinSize + kQuicStreamOffsetSize) { expected_error = "Unable to read offset."; - } else if (i < 28) { + } else { expected_error = "Unable to read frame data."; } - CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, - QUIC_INVALID_FRAME_DATA); + CheckProcessingFails(packet, i + GetPacketHeaderSize(kIncludeVersion), + expected_error, QUIC_INVALID_FRAME_DATA); } } @@ -733,7 +886,7 @@ TEST_F(QuicFramerTest, RejectPacket) { EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); ASSERT_EQ(0u, visitor_.stream_frames_.size()); EXPECT_EQ(0u, visitor_.ack_frames_.size()); @@ -835,12 +988,13 @@ TEST_F(QuicFramerTest, StreamFrameInFecGroup) { EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); EXPECT_EQ(GG_UINT64_C(0x341256789ABA), visitor_.header_->fec_group); - EXPECT_EQ(string(AsChars(packet) + kStartOfFecProtectedData, - arraysize(packet) - kStartOfFecProtectedData), - visitor_.fec_protected_payload_); + EXPECT_EQ( + string(AsChars(packet) + GetStartOfFecProtectedData(!kIncludeVersion), + arraysize(packet) - GetStartOfFecProtectedData(!kIncludeVersion)), + visitor_.fec_protected_payload_); ASSERT_EQ(1u, visitor_.stream_frames_.size()); EXPECT_EQ(0u, visitor_.ack_frames_.size()); @@ -890,7 +1044,7 @@ TEST_F(QuicFramerTest, AckFrame) { EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); EXPECT_EQ(0u, visitor_.stream_frames_.size()); ASSERT_EQ(1u, visitor_.ack_frames_.size()); @@ -904,26 +1058,38 @@ TEST_F(QuicFramerTest, AckFrame) { EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter); EXPECT_EQ(GG_UINT64_C(0x0123456789AA0), frame.sent_info.least_unacked); + const size_t kSentEntropyOffset = kQuicFrameTypeSize; + const size_t kLeastUnackedOffset = kSentEntropyOffset + kQuicEntropyHashSize; + const size_t kReceivedEntropyOffset = kLeastUnackedOffset + + kSequenceNumberSize; + const size_t kLargestObservedOffset = kReceivedEntropyOffset + + kQuicEntropyHashSize; + const size_t kNumMissingPacketOffset = kLargestObservedOffset + + kSequenceNumberSize; + const size_t kMissingPacketsOffset = kNumMissingPacketOffset + + kNumberOfMissingPacketsSize; // Now test framing boundaries - for (size_t i = 0; i < 22; ++i) { + const size_t missing_packets_size = 1 * kSequenceNumberSize; + for (size_t i = 0; + i < QuicFramer::GetMinAckFrameSize() + missing_packets_size; ++i) { string expected_error; - if (i < 1) { + if (i < kSentEntropyOffset) { expected_error = "Unable to read frame type."; - } else if (i < 2) { + } else if (i < kLeastUnackedOffset) { expected_error = "Unable to read entropy hash for sent packets."; - } else if (i < 8) { + } else if (i < kReceivedEntropyOffset) { expected_error = "Unable to read least unacked."; - } else if (i < 9) { + } else if (i < kLargestObservedOffset) { expected_error = "Unable to read entropy hash for received packets."; - } else if (i < 15) { + } else if (i < kNumMissingPacketOffset) { expected_error = "Unable to read largest observed."; - } else if (i < 16) { + } else if (i < kMissingPacketsOffset) { expected_error = "Unable to read num missing packets."; } else { expected_error = "Unable to read sequence number in missing packets."; } - CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, - QUIC_INVALID_FRAME_DATA); + CheckProcessingFails(packet, i + GetPacketHeaderSize(!kIncludeVersion), + expected_error, QUIC_INVALID_FRAME_DATA); } } @@ -957,7 +1123,7 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameTCP) { EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); EXPECT_EQ(0u, visitor_.stream_frames_.size()); ASSERT_EQ(1u, visitor_.congestion_feedback_frames_.size()); @@ -980,8 +1146,8 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameTCP) { } else if (i < 6) { expected_error = "Unable to read receive window."; } - CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, - QUIC_INVALID_FRAME_DATA); + CheckProcessingFails(packet, i + GetPacketHeaderSize(!kIncludeVersion), + expected_error, QUIC_INVALID_FRAME_DATA); } } @@ -1029,7 +1195,7 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) { EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); EXPECT_EQ(0u, visitor_.stream_frames_.size()); ASSERT_EQ(1u, visitor_.congestion_feedback_frames_.size()); @@ -1077,8 +1243,8 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInterArrival) { } else if (i < 31) { expected_error = "Unable to read time delta in received packets."; } - CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, - QUIC_INVALID_FRAME_DATA); + CheckProcessingFails(packet, i + GetPacketHeaderSize(!kIncludeVersion), + expected_error, QUIC_INVALID_FRAME_DATA); } } @@ -1110,7 +1276,7 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameFixRate) { EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); EXPECT_EQ(0u, visitor_.stream_frames_.size()); ASSERT_EQ(1u, visitor_.congestion_feedback_frames_.size()); @@ -1130,8 +1296,8 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameFixRate) { } else if (i < 6) { expected_error = "Unable to read bitrate."; } - CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, - QUIC_INVALID_FRAME_DATA); + CheckProcessingFails(packet, i + GetPacketHeaderSize(!kIncludeVersion), + expected_error, QUIC_INVALID_FRAME_DATA); } } @@ -1159,7 +1325,7 @@ TEST_F(QuicFramerTest, CongestionFeedbackFrameInvalidFeedback) { QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error()); } @@ -1199,7 +1365,7 @@ TEST_F(QuicFramerTest, RstStreamFrame) { EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); EXPECT_EQ(GG_UINT64_C(0x01020304), visitor_.rst_stream_frame_.stream_id); EXPECT_EQ(0x05060708, visitor_.rst_stream_frame_.error_code); @@ -1208,15 +1374,16 @@ TEST_F(QuicFramerTest, RstStreamFrame) { // Now test framing boundaries for (size_t i = 2; i < 24; ++i) { string expected_error; - if (i < 5) { + if (i < kQuicFrameTypeSize + kQuicStreamIdSize) { expected_error = "Unable to read stream_id."; - } else if (i < 9) { + } else if (i < kQuicFrameTypeSize + kQuicStreamIdSize + + kQuicErrorCodeSize) { expected_error = "Unable to read rst stream error code."; - } else if (i < 24) { + } else { expected_error = "Unable to read rst stream error details."; } - CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, - QUIC_INVALID_RST_STREAM_DATA); + CheckProcessingFails(packet, i + GetPacketHeaderSize(!kIncludeVersion), + expected_error, QUIC_INVALID_RST_STREAM_DATA); } } @@ -1271,7 +1438,7 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) { EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); EXPECT_EQ(0u, visitor_.stream_frames_.size()); @@ -1290,15 +1457,17 @@ TEST_F(QuicFramerTest, ConnectionCloseFrame) { EXPECT_EQ(GG_UINT64_C(0x0123456789ABE), *missing_iter); // Now test framing boundaries - for (size_t i = 2; i < 20; ++i) { + for (size_t i = kQuicFrameTypeSize; + i < QuicFramer::GetMinConnectionCloseFrameSize() - + QuicFramer::GetMinAckFrameSize(); ++i) { string expected_error; - if (i < 5) { + if (i < kQuicFrameTypeSize + kQuicErrorCodeSize) { expected_error = "Unable to read connection close error code."; - } else if (i < 20) { + } else { expected_error = "Unable to read connection close error details."; } - CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, - QUIC_INVALID_CONNECTION_CLOSE_DATA); + CheckProcessingFails(packet, i + GetPacketHeaderSize(!kIncludeVersion), + expected_error, QUIC_INVALID_CONNECTION_CLOSE_DATA); } } @@ -1337,25 +1506,28 @@ TEST_F(QuicFramerTest, GoAwayFrame) { EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); EXPECT_EQ(GG_UINT64_C(0x01020304), visitor_.goaway_frame_.last_good_stream_id); EXPECT_EQ(0x05060708, 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 = 2; i < 24; ++i) { + for (size_t i = kQuicFrameTypeSize; + i < QuicFramer::GetMinGoAwayFrameSize() + reason_size; ++i) { string expected_error; - if (i < 5) { + if (i < kQuicFrameTypeSize + kQuicErrorCodeSize) { expected_error = "Unable to read go away error code."; - } else if (i < 9) { + } else if (i < kQuicFrameTypeSize + kQuicErrorCodeSize + + kQuicStreamIdSize) { expected_error = "Unable to read last good stream id."; - } else if (i < 24) { + } else { expected_error = "Unable to read goaway reason."; } - CheckProcessingFails(packet, i + kPacketHeaderSize, expected_error, - QUIC_INVALID_GOAWAY_DATA); + CheckProcessingFails(packet, i + GetPacketHeaderSize(!kIncludeVersion), + expected_error, QUIC_INVALID_GOAWAY_DATA); } } @@ -1388,7 +1560,7 @@ TEST_F(QuicFramerTest, PublicResetPacket) { visitor_.public_reset_packet_->rejected_sequence_number); // Now test framing boundaries - for (size_t i = 0; i < kPublicResetPacketSize; ++i) { + for (size_t i = 0; i < GetPublicResetPacketSize(); ++i) { string expected_error; if (i < kPublicFlagsOffset) { expected_error = "Unable to read GUID."; @@ -1430,7 +1602,7 @@ TEST_F(QuicFramerTest, FecPacket) { EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion)); EXPECT_EQ(0u, visitor_.stream_frames_.size()); EXPECT_EQ(0u, visitor_.ack_frames_.size()); @@ -1474,9 +1646,8 @@ TEST_F(QuicFramerTest, ConstructPaddingFramePacket) { 0x00, }; - // unsigned char packet[kMaxPacketSize]; - memset(packet + kPacketHeaderSize + 1, 0x00, - kMaxPacketSize - kPacketHeaderSize - 1); + memset(packet + GetPacketHeaderSize(!kIncludeVersion) + 1, 0x00, + kMaxPacketSize - GetPacketHeaderSize(!kIncludeVersion) - 1); scoped_ptr<QuicPacket> data( framer_.ConstructFrameDataPacket(header, frames).packet); @@ -1547,6 +1718,69 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacket) { AsChars(packet), arraysize(packet)); } +TEST_F(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) { + QuicPacketHeader header; + header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); + header.public_header.reset_flag = false; + header.public_header.version_flag = true; + header.fec_flag = false; + header.entropy_flag = true; + header.fec_entropy_flag = false; + header.packet_sequence_number = GG_UINT64_C(0x77123456789ABC); + header.fec_group = 0; + + QuicStreamFrame stream_frame; + stream_frame.stream_id = 0x01020304; + stream_frame.fin = true; + stream_frame.offset = GG_UINT64_C(0xBA98FEDC32107654); + stream_frame.data = "hello world!"; + + QuicFrames frames; + frames.push_back(QuicFrame(&stream_frame)); + + unsigned char packet[] = { + // guid + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // public flags (version) + 0x01, + // version tag + 'Q', '1', '.', '0', + // packet sequence number + 0xBC, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags (entropy) + 0x02, + // first fec protected packet offset + 0xFF, + + // frame type (stream frame) + 0x01, + // 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', '!', + }; + + scoped_ptr<QuicPacket> data( + framer_.ConstructFrameDataPacket(header, frames).packet); + ASSERT_TRUE(data != NULL); + + test::CompareCharArraysWithHexError("constructed packet", + data->data(), data->length(), + AsChars(packet), arraysize(packet)); +} + + TEST_F(QuicFramerTest, ConstructAckFramePacket) { QuicPacketHeader header; header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210); @@ -2101,13 +2335,48 @@ TEST_F(QuicFramerTest, EncryptPacket) { }; scoped_ptr<QuicPacket> raw( - QuicPacket::NewDataPacket(AsChars(packet), arraysize(packet), false)); + QuicPacket::NewDataPacket(AsChars(packet), arraysize(packet), false, + !kIncludeVersion)); + scoped_ptr<QuicEncryptedPacket> encrypted( + framer_.EncryptPacket(sequence_number, *raw)); + + ASSERT_TRUE(encrypted.get() != NULL); + EXPECT_TRUE(CheckEncryption(sequence_number, raw.get())); +} + +TEST_F(QuicFramerTest, EncryptPacketWithVersionFlag) { + QuicPacketSequenceNumber sequence_number = GG_UINT64_C(0x123456789ABC); + unsigned char packet[] = { + // guid + 0x10, 0x32, 0x54, 0x76, + 0x98, 0xBA, 0xDC, 0xFE, + // public flags (version) + 0x01, + // version tag + 'Q', '.', '1', '0', + // packet sequence number + 0xBC, 0x9A, 0x78, 0x56, + 0x34, 0x12, + // private flags + 0x01, + // 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( + QuicPacket::NewDataPacket(AsChars(packet), arraysize(packet), false, + kIncludeVersion)); scoped_ptr<QuicEncryptedPacket> encrypted( framer_.EncryptPacket(sequence_number, *raw)); ASSERT_TRUE(encrypted.get() != NULL); - EXPECT_TRUE(CheckEncryption(sequence_number, - StringPiece(AsChars(packet), arraysize(packet)))); + EXPECT_TRUE(CheckEncryption(sequence_number, raw.get())); } // TODO(rch): re-enable after https://codereview.chromium.org/11820005/ diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index 01b04be..4a04712 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc @@ -116,7 +116,9 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> { use_closing_stream_(false), read_buffer_(new IOBufferWithSize(4096)), guid_(2), - framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)), + framer_(kQuicVersion1, + QuicDecrypter::Create(kNULL), + QuicEncrypter::Create(kNULL)), creator_(guid_, &framer_, &random_) { IPAddressNumber ip; CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip)); diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index c3c7061..b50a25b 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc @@ -89,14 +89,16 @@ class QuicNetworkTransactionTest : public PlatformTest { clock_, &random_generator_, host)); - QuicFramer framer(QuicDecrypter::Create(kNULL), + QuicFramer framer(kQuicVersion1, + QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *chlo)); } scoped_ptr<QuicEncryptedPacket> ConstructShlo() { scoped_ptr<QuicPacket> shlo(ConstructHandshakePacket(0xDEADBEEF, kSHLO)); - QuicFramer framer(QuicDecrypter::Create(kNULL), + QuicFramer framer(kQuicVersion1, + QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *shlo)); } @@ -139,7 +141,8 @@ class QuicNetworkTransactionTest : public PlatformTest { feedback.tcp.accumulated_number_of_lost_packets = 0; feedback.tcp.receive_window = 256000; - QuicFramer framer(QuicDecrypter::Create(kNULL), + QuicFramer framer(kQuicVersion1, + QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); QuicFrames frames; frames.push_back(QuicFrame(&ack)); @@ -192,7 +195,8 @@ class QuicNetworkTransactionTest : public PlatformTest { scoped_ptr<QuicEncryptedPacket> ConstructPacket( const QuicPacketHeader& header, const QuicFrame& frame) { - QuicFramer framer(QuicDecrypter::Create(kNULL), + QuicFramer framer(kQuicVersion1, + QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); QuicFrames frames; frames.push_back(frame); diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc index bc80bd3..ea1e90a 100644 --- a/net/quic/quic_packet_creator.cc +++ b/net/quic/quic_packet_creator.cc @@ -26,7 +26,8 @@ QuicPacketCreator::QuicPacketCreator(QuicGuid guid, random_generator_(random_generator), sequence_number_(0), fec_group_number_(0), - packet_size_(kPacketHeaderSize) { + // TODO(satyashekhar): Fix this when versioning is implemented. + packet_size_(GetPacketHeaderSize(!kIncludeVersion)) { framer_->set_fec_builder(this); } @@ -55,7 +56,14 @@ void QuicPacketCreator::MaybeStartFEC() { } bool QuicPacketCreator::HasRoomForStreamFrame() const { - return (BytesFree() > kFrameTypeSize + kMinStreamFrameLength); + return BytesFree() > QuicFramer::GetMinStreamFrameSize(); +} + +// static +size_t QuicPacketCreator::StreamFramePacketOverhead(int num_frames, + bool include_version) { + return GetPacketHeaderSize(include_version) + + QuicFramer::GetMinStreamFrameSize() * num_frames; } size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id, @@ -64,14 +72,14 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id, bool fin, QuicFrame* frame) { DCHECK_GT(options_.max_packet_length, - QuicUtils::StreamFramePacketOverhead(1)); + StreamFramePacketOverhead(1, kIncludeVersion)); DCHECK(HasRoomForStreamFrame()); const size_t free_bytes = BytesFree(); size_t bytes_consumed = 0; if (data.size() != 0) { - size_t max_data_len = free_bytes - kFrameTypeSize - kMinStreamFrameLength; + size_t max_data_len = free_bytes - QuicFramer::GetMinStreamFrameSize(); bytes_consumed = min<size_t>(max_data_len, data.size()); bool set_fin = fin && bytes_consumed == data.size(); // Last frame. @@ -126,7 +134,8 @@ SerializedPacket QuicPacketCreator::SerializePacket() { SerializedPacket serialized = framer_->ConstructFrameDataPacket( header, queued_frames_, packet_size_); queued_frames_.clear(); - packet_size_ = kPacketHeaderSize; + // TODO(satyamshekhar) Fix this versioning is implemented. + packet_size_ = GetPacketHeaderSize(false); serialized.retransmittable_frames = queued_retransmittable_frames_.release(); return serialized; } @@ -195,10 +204,10 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, } if (frame.type == STREAM_FRAME) { queued_frames_.push_back( - queued_retransmittable_frames_->AddStreamFrame(frame.stream_frame)); + queued_retransmittable_frames_->AddStreamFrame(frame.stream_frame)); } else { queued_frames_.push_back( - queued_retransmittable_frames_->AddNonStreamFrame(frame)); + queued_retransmittable_frames_->AddNonStreamFrame(frame)); } } else { queued_frames_.push_back(frame); diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h index 23301ec..e3fdc2b 100644 --- a/net/quic/quic_packet_creator.h +++ b/net/quic/quic_packet_creator.h @@ -57,6 +57,9 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { // and there is not already an FEC group open. void MaybeStartFEC(); + // The overhead the framing will add for a packet with num_frames frames. + static size_t StreamFramePacketOverhead(int num_frames, bool include_version); + bool HasRoomForStreamFrame() const; // Converts a raw payload to a frame which fits into the currently open @@ -72,7 +75,7 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { // Serializes all frames into a single packet. All frames must fit into a // single packet. Also, sets the entropy hash of the serialized packet to a // random bool and returns that value as a member of SerializedPacket. - // Never returns an RetransmittableFrames in SerializedPacket + // Never returns a RetransmittableFrames in SerializedPacket. SerializedPacket SerializeAllFrames(const QuicFrames& frames); // Returns true if there are frames pending to be serialized. @@ -139,6 +142,8 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface { size_t packet_size_; QuicFrames queued_frames_; scoped_ptr<RetransmittableFrames> queued_retransmittable_frames_; + + DISALLOW_COPY_AND_ASSIGN(QuicPacketCreator); }; } // namespace net diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc index c060da7..752da91 100644 --- a/net/quic/quic_packet_creator_test.cc +++ b/net/quic/quic_packet_creator_test.cc @@ -26,7 +26,9 @@ namespace { class QuicPacketCreatorTest : public ::testing::Test { protected: QuicPacketCreatorTest() - : framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)), + : framer_(kQuicVersion1, + QuicDecrypter::Create(kNULL), + QuicEncrypter::Create(kNULL)), id_(1), sequence_number_(0), guid_(2), @@ -189,8 +191,8 @@ TEST_F(QuicPacketCreatorTest, CreateStreamFrameFinOnly) { TEST_F(QuicPacketCreatorTest, CreateStreamFrameTooLarge) { // A string larger than fits into a frame. size_t ciphertext_size = NullEncrypter().GetCiphertextSize(1); - creator_.options()->max_packet_length = - ciphertext_size + QuicUtils::StreamFramePacketOverhead(1); + creator_.options()->max_packet_length = ciphertext_size + + QuicPacketCreator::StreamFramePacketOverhead(1, !kIncludeVersion); QuicFrame frame; size_t consumed = creator_.CreateStreamFrame(1u, "test", 0u, true, &frame); EXPECT_EQ(1u, consumed); @@ -202,7 +204,8 @@ TEST_F(QuicPacketCreatorTest, AddFrameAndSerialize) { const size_t max_plaintext_size = framer_.GetMaxPlaintextSize(creator_.options()->max_packet_length); EXPECT_FALSE(creator_.HasPendingFrames()); - EXPECT_EQ(max_plaintext_size - kPacketHeaderSize, creator_.BytesFree()); + EXPECT_EQ(max_plaintext_size - GetPacketHeaderSize(!kIncludeVersion), + creator_.BytesFree()); // Add a variety of frame types and then a padding frame. QuicAckFrame ack_frame; @@ -240,7 +243,8 @@ TEST_F(QuicPacketCreatorTest, AddFrameAndSerialize) { delete serialized.retransmittable_frames; EXPECT_FALSE(creator_.HasPendingFrames()); - EXPECT_EQ(max_plaintext_size - kPacketHeaderSize, creator_.BytesFree()); + EXPECT_EQ(max_plaintext_size - GetPacketHeaderSize(!kIncludeVersion), + creator_.BytesFree()); } } // namespace diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc index fb4bcf2..d3de9b55 100644 --- a/net/quic/quic_packet_generator.cc +++ b/net/quic/quic_packet_generator.cc @@ -73,9 +73,6 @@ QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id, size_t total_bytes_consumed = 0; bool fin_consumed = false; - // Make sure any queued data gets sent before new data. - // SendQueuedData(); - while (delegate_->CanWrite(false)) { // TODO(rch) figure out FEC. // packet_creator_.MaybeStartFEC(); diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h index 32becc1..254a4fe 100644 --- a/net/quic/quic_packet_generator.h +++ b/net/quic/quic_packet_generator.h @@ -3,10 +3,10 @@ // found in the LICENSE file. // // Responsible for generating packets on behalf of a QuicConnection. -// Packets are serialized just-in-time. Control frame are queued. -// Ack and Feedback frames will requested from the Connection +// Packets are serialized just-in-time. Control frames are queued. +// Ack and Feedback frames will be requested from the Connection // just-in-time. When a packet needs to be sent, the Generator -// wills serialized a packet pass it to QuicConnection::SendOrQueuePacket() +// will serialized a packet and pass it to QuicConnection::SendOrQueuePacket() // // The Generator's mode of operation is controlled by two conditions: // @@ -14,7 +14,7 @@ // // If the Delegate is not writable, then no operations will cause // a packet to be serialized. In particular: -// * SetShouldSendAck will simply record that an ack is to be send. +// * SetShouldSendAck will simply record that an ack is to be sent. // * AddControlFram will enqueue the control frame. // * ConsumeData will do nothing. // @@ -43,10 +43,10 @@ // an FEC packet will be sent after each write call completes. // // TODO(rch): This behavior should probably be tuned. When not in batch -// mode we, should probably set a timer so that several independent +// mode, we should probably set a timer so that several independent // operations can be grouped into the same FEC group. // -// When an FEC packet is generate, it will be send to the Delegate, +// When an FEC packet is generated, it will be send to the Delegate, // even if the Delegate has become unwritable after handling the // data packet immediately proceeding the FEC packet. @@ -89,8 +89,6 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator { bool HasQueuedData() const; private: - // Must be called when the connection is writable - // and not blocked by the congestion manager. void SendQueuedData(); bool HasPendingData() const; @@ -106,6 +104,8 @@ class NET_EXPORT_PRIVATE QuicPacketGenerator { scoped_ptr<QuicAckFrame> pending_ack_frame_; scoped_ptr<QuicCongestionFeedbackFrame> pending_feedback_frame_; bool should_send_feedback_; + + DISALLOW_COPY_AND_ASSIGN(QuicPacketGenerator); }; } // namespace net diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc index 85a16e8..3b97472 100644 --- a/net/quic/quic_packet_generator_test.cc +++ b/net/quic/quic_packet_generator_test.cc @@ -74,7 +74,9 @@ struct PacketContents { class QuicPacketGeneratorTest : public ::testing::Test { protected: QuicPacketGeneratorTest() - : framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)), + : framer_(kQuicVersion1, + QuicDecrypter::Create(kNULL), + QuicEncrypter::Create(kNULL)), creator_(42, &framer_, &random_), generator_(&delegate_, &creator_), packet_(0, NULL, 0, NULL), diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index 42ee620..0a7239a 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc @@ -13,6 +13,26 @@ using std::string; namespace net { +size_t GetPacketHeaderSize(bool include_version) { + return kQuicGuidSize + kPublicFlagsSize + + (include_version ? kQuicVersionSize : 0) + kPrivateFlagsSize + + kSequenceNumberSize + kFecGroupSize; +} + +size_t GetPublicResetPacketSize() { + return kQuicGuidSize + kPublicFlagsSize + kPublicResetNonceSize + + kSequenceNumberSize; +} + +size_t GetStartOfFecProtectedData(bool include_version) { + return GetPacketHeaderSize(include_version); +} + +size_t GetStartOfEncryptedData(bool include_version) { + return GetPacketHeaderSize(include_version) - kPrivateFlagsSize - + kFecGroupSize; +} + QuicStreamFrame::QuicStreamFrame() {} QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id, @@ -72,8 +92,8 @@ QuicAckFrame::QuicAckFrame(QuicPacketSequenceNumber largest_observed, } ostream& operator<<(ostream& os, const SentPacketInfo& sent_info) { - os << "entropy_hash: " << static_cast<int>(sent_info.entropy_hash); - os << " least_unacked: " << sent_info.least_unacked; + os << "entropy_hash: " << static_cast<int>(sent_info.entropy_hash) + << " least_unacked: " << sent_info.least_unacked; return os; } @@ -149,9 +169,9 @@ CongestionFeedbackMessageInterArrival:: QuicGoAwayFrame::QuicGoAwayFrame(QuicErrorCode error_code, QuicStreamId last_good_stream_id, const string& reason) - : error_code(error_code), - last_good_stream_id(last_good_stream_id), - reason_phrase(reason) { + : error_code(error_code), + last_good_stream_id(last_good_stream_id), + reason_phrase(reason) { DCHECK_LE(error_code, numeric_limits<uint8>::max()); } @@ -173,6 +193,28 @@ QuicData::~QuicData() { } } +StringPiece QuicPacket::FecProtectedData() const { + const size_t start_of_fec = GetStartOfFecProtectedData(includes_version_); + return StringPiece(data() + start_of_fec, length() - start_of_fec); +} + +StringPiece QuicPacket::AssociatedData() const { + return StringPiece(data() + kStartOfHashData, + GetStartOfEncryptedData(includes_version_) - + kStartOfHashData); +} + +StringPiece QuicPacket::BeforePlaintext() const { + return StringPiece(data(), GetStartOfEncryptedData(includes_version_)); +} + +StringPiece QuicPacket::Plaintext() const { + const size_t start_of_encrypted_data = + GetStartOfEncryptedData(includes_version_); + return StringPiece(data() + start_of_encrypted_data, + length() - start_of_encrypted_data); +} + RetransmittableFrames::RetransmittableFrames() {} RetransmittableFrames::~RetransmittableFrames() { diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index 689167c..ce11a90 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -36,6 +36,7 @@ typedef uint64 QuicPacketSequenceNumber; typedef QuicPacketSequenceNumber QuicFecGroupNumber; typedef uint64 QuicPublicResetNonceProof; typedef uint8 QuicPacketEntropyHash; +typedef uint32 QuicVersionTag; // TODO(rch): Consider Quic specific names for these constants. // Maximum size in bytes of a QUIC packet. @@ -48,6 +49,8 @@ const size_t kDefaultMaxStreamsPerConnection = 100; const size_t kQuicGuidSize = 8; // Number of bytes reserved for public flags in the packet header. const size_t kPublicFlagsSize = 1; +// Number of bytes reserved for version number in the packet header. +const size_t kQuicVersionSize = 4; // Number of bytes reserved for sequence number in the packet header. const size_t kSequenceNumberSize = 6; // Number of bytes reserved for private flags in the packet header. @@ -56,45 +59,22 @@ const size_t kPrivateFlagsSize = 1; const size_t kFecGroupSize = 1; // Number of bytes reserved for the nonce proof in public reset packet. const size_t kPublicResetNonceSize = 8; -// Number of bytes reserved for the frame type preceding each frame. -const size_t kFrameTypeSize = 1; + +// Signifies that the QuicPacket will contain version of the protocol. +const bool kIncludeVersion = true; // Size in bytes of the data or fec packet header. -const size_t kPacketHeaderSize = kQuicGuidSize + kPublicFlagsSize + - kPrivateFlagsSize + kSequenceNumberSize + kFecGroupSize; +NET_EXPORT_PRIVATE size_t GetPacketHeaderSize(bool include_version); // Size in bytes of the public reset packet. -const size_t kPublicResetPacketSize = kQuicGuidSize + kPublicFlagsSize + - kPublicResetNonceSize + kSequenceNumberSize; - -// Index into the guid offset in the header. -const size_t kGuidOffset = 0; -// Index into the flags offset in the header. -const size_t kPublicFlagsOffset = kQuicGuidSize; - -// Index into the sequence number offset in the header. -const size_t kSequenceNumberOffset = kPublicFlagsOffset + kPublicFlagsSize; -// Index into the private flags offset in the data packet header. -const size_t kPrivateFlagsOffset = kSequenceNumberOffset + kSequenceNumberSize; -// Index into the fec group offset in the header. -const size_t kFecGroupOffset = kPrivateFlagsOffset + kPrivateFlagsSize; - -// Index into the nonce proof of the public reset packet. -const size_t kPublicResetPacketNonceProofOffset = kPublicFlagsOffset + - kPublicFlagsSize; -// Index into the rejected sequence number of the public reset packet. -const size_t kPublicResetPacketRejectedSequenceNumberOffset = - kPublicResetPacketNonceProofOffset + kPublicResetNonceSize; +NET_EXPORT_PRIVATE size_t GetPublicResetPacketSize(); // Index of the first byte in a QUIC packet of FEC protected data. -const size_t kStartOfFecProtectedData = kPacketHeaderSize; +NET_EXPORT_PRIVATE size_t GetStartOfFecProtectedData(bool include_version); // Index of the first byte in a QUIC packet of encrypted data. -const size_t kStartOfEncryptedData = kPacketHeaderSize - kPrivateFlagsSize - - kFecGroupSize; -// Index of the first byte in a QUIC packet which is hashed. -const size_t kStartOfHashData = 0; +NET_EXPORT_PRIVATE size_t GetStartOfEncryptedData(bool include_version); -// Size in bytes of all stream frame fields. -const size_t kMinStreamFrameLength = 15; +// Index of the first byte in a QUIC packet which is used in hash calculation. +const size_t kStartOfHashData = 0; // Limit on the delta between stream IDs. const QuicStreamId kMaxStreamIdDelta = 100; @@ -121,7 +101,7 @@ enum QuicFrameType { enum QuicPacketPublicFlags { PACKET_PUBLIC_FLAGS_NONE = 0, - PACKET_PUBLIC_FLAGS_VERSION = 1 << 0, + PACKET_PUBLIC_FLAGS_VERSION = 1 << 0, // Packet header contains version info. PACKET_PUBLIC_FLAGS_RST = 1 << 1, // Packet is a public reset packet. PACKET_PUBLIC_FLAGS_MAX = (1 << 2) - 1 // All bits set. }; @@ -134,10 +114,6 @@ enum QuicPacketPrivateFlags { PACKET_PRIVATE_FLAGS_MAX = (1 << 3) - 1 // All bits set. }; -enum QuicVersion { - QUIC_VERSION_1 = 0 -}; - enum QuicErrorCode { // Stream errors. QUIC_NO_ERROR = 0, @@ -208,12 +184,22 @@ enum QuicErrorCode { QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP, }; +// Version and Crypto tags are written to the wire with a big-endian +// representation of the name of the tag. For example +// the client hello tag (CHLO) will be written as the +// following 4 bytes: 'C' 'H' 'L' 'O'. Since it is +// stored in memory as a little endian uint32, we need +// to reverse the order of the bytes. +#define MAKE_TAG(a, b, c, d) ((d << 24) + (c << 16) + (b << 8) + a) + +const QuicVersionTag kQuicVersion1 = MAKE_TAG('Q', '1', '.', '0'); + struct NET_EXPORT_PRIVATE QuicPacketPublicHeader { // Universal header. All QuicPacket headers will have a guid and public flags. - // TODO(satyamshekhar): Support versioning as per Protocol Negotiation Doc. QuicGuid guid; bool reset_flag; bool version_flag; + QuicVersionTag version; }; // Header for Data or FEC packets. @@ -458,8 +444,6 @@ struct NET_EXPORT_PRIVATE QuicFecData { // FEC protected packet. The last protected packet's sequence number will // be one less than the sequence number of the FEC packet. QuicFecGroupNumber fec_group; - // The last protected packet's sequence number will be one - // less than the sequence number of the FEC packet. base::StringPiece redundancy; }; @@ -472,12 +456,12 @@ class NET_EXPORT_PRIVATE QuicData { QuicData(const char* buffer, size_t length) : buffer_(buffer), length_(length), - owns_buffer_(false) { } + owns_buffer_(false) {} QuicData(char* buffer, size_t length, bool owns_buffer) : buffer_(buffer), length_(length), - owns_buffer_(owns_buffer) { } + owns_buffer_(owns_buffer) {} virtual ~QuicData(); @@ -500,43 +484,43 @@ class NET_EXPORT_PRIVATE QuicPacket : public QuicData { public: static QuicPacket* NewDataPacket(char* buffer, size_t length, - bool owns_buffer) { - return new QuicPacket(buffer, length, owns_buffer, false); + bool owns_buffer, + bool includes_version) { + return new QuicPacket(buffer, length, owns_buffer, includes_version, false); } static QuicPacket* NewFecPacket(char* buffer, size_t length, - bool owns_buffer) { - return new QuicPacket(buffer, length, owns_buffer, true); - } - - base::StringPiece FecProtectedData() const { - return base::StringPiece(data() + kStartOfFecProtectedData, - length() - kStartOfFecProtectedData); - } - - base::StringPiece AssociatedData() const { - return base::StringPiece(data() + kStartOfHashData, - kStartOfEncryptedData - kStartOfHashData); + bool owns_buffer, + bool includes_version) { + return new QuicPacket(buffer, length, owns_buffer, includes_version, true); } - base::StringPiece Plaintext() const { - return base::StringPiece(data() + kStartOfEncryptedData, - length() - kStartOfEncryptedData); - } + base::StringPiece FecProtectedData() const; + base::StringPiece AssociatedData() const; + base::StringPiece BeforePlaintext() const; + base::StringPiece Plaintext() const; bool is_fec_packet() const { return is_fec_packet_; } + bool includes_version() const { return includes_version_; } + char* mutable_data() { return buffer_; } private: - QuicPacket(char* buffer, size_t length, bool owns_buffer, bool is_fec_packet) + QuicPacket(char* buffer, + size_t length, + bool owns_buffer, + bool includes_version, + bool is_fec_packet) : QuicData(buffer, length, owns_buffer), buffer_(buffer), - is_fec_packet_(is_fec_packet) { } + is_fec_packet_(is_fec_packet), + includes_version_(includes_version) {} char* buffer_; const bool is_fec_packet_; + const bool includes_version_; DISALLOW_COPY_AND_ASSIGN(QuicPacket); }; @@ -544,10 +528,10 @@ class NET_EXPORT_PRIVATE QuicPacket : public QuicData { class NET_EXPORT_PRIVATE QuicEncryptedPacket : public QuicData { public: QuicEncryptedPacket(const char* buffer, size_t length) - : QuicData(buffer, length) { } + : QuicData(buffer, length) {} QuicEncryptedPacket(char* buffer, size_t length, bool owns_buffer) - : QuicData(buffer, length, owns_buffer) { } + : QuicData(buffer, length, owns_buffer) {} // By default, gtest prints the raw bytes of an object. The bool data // member (in the base class QuicData) causes this object to have padding @@ -556,11 +540,6 @@ class NET_EXPORT_PRIVATE QuicEncryptedPacket : public QuicData { NET_EXPORT_PRIVATE friend std::ostream& operator<<( std::ostream& os, const QuicEncryptedPacket& s); - base::StringPiece AssociatedData() const { - return base::StringPiece(data() + kStartOfHashData, - kStartOfEncryptedData - kStartOfHashData); - } - private: DISALLOW_COPY_AND_ASSIGN(QuicEncryptedPacket); }; @@ -594,7 +573,7 @@ struct NET_EXPORT_PRIVATE SerializedPacket { : sequence_number(sequence_number), packet(packet), entropy_hash(entropy_hash), - retransmittable_frames(retransmittable_frames) { } + retransmittable_frames(retransmittable_frames) {} QuicPacketSequenceNumber sequence_number; QuicPacket* packet; @@ -608,8 +587,7 @@ struct NET_EXPORT_PRIVATE SerializedPacket { struct QuicConsumedData { QuicConsumedData(size_t bytes_consumed, bool fin_consumed) : bytes_consumed(bytes_consumed), - fin_consumed(fin_consumed) { - } + fin_consumed(fin_consumed) {} // By default, gtest prints the raw bytes of an object. The bool data // member causes this object to have padding bytes, which causes the diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index dfcea32..39abb68 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc @@ -140,13 +140,13 @@ void QuicSession::ConnectionClose(QuicErrorCode error, bool from_peer) { bool QuicSession::OnCanWrite() { // We latch this here rather than doing a traditional loop, because streams // may be modifying the list as we loop. - int remaining_writes = write_blocked_streams_.size(); + int remaining_writes = write_blocked_streams_.NumObjects(); while (!connection_->HasQueuedData() && remaining_writes > 0) { - DCHECK(!write_blocked_streams_.empty()); - ReliableQuicStream* stream = GetStream(write_blocked_streams_.front()); - write_blocked_streams_.pop_front(); + DCHECK(!write_blocked_streams_.IsEmpty()); + ReliableQuicStream* stream = + GetStream(write_blocked_streams_.GetNextBlockedObject()); if (stream != NULL) { // If the stream can't write all bytes, it'll re-add itself to the blocked // list. @@ -155,7 +155,7 @@ bool QuicSession::OnCanWrite() { --remaining_writes; } - return write_blocked_streams_.empty(); + return write_blocked_streams_.IsEmpty(); } QuicConsumedData QuicSession::WriteData(QuicStreamId id, @@ -295,7 +295,7 @@ size_t QuicSession::GetNumOpenStreams() const { } void QuicSession::MarkWriteBlocked(QuicStreamId id) { - write_blocked_streams_.push_back(id); + write_blocked_streams_.AddBlockedObject(id); } void QuicSession::PostProcessAfterData() { diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index 6f07b9a..7152aa0 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h @@ -12,6 +12,7 @@ #include "base/compiler_specific.h" #include "base/hash_tables.h" #include "net/base/ip_endpoint.h" +#include "net/quic/blocked_list.h" #include "net/quic/quic_connection.h" #include "net/quic/quic_crypto_stream.h" #include "net/quic/quic_packet_creator.h" @@ -168,7 +169,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { base::hash_set<QuicStreamId> implicitly_created_streams_; // A list of streams which need to write more data. - std::list<QuicStreamId> write_blocked_streams_; + BlockedList<QuicStreamId> write_blocked_streams_; QuicStreamId largest_peer_created_stream_id_; @@ -176,6 +177,8 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { bool goaway_received_; // Whether a GoAway has been sent. bool goaway_sent_; + + DISALLOW_COPY_AND_ASSIGN(QuicSession); }; } // namespace net diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index ca29264..1216f56 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc @@ -38,14 +38,16 @@ class QuicStreamFactoryTest : public ::testing::Test { clock_, &random_generator_, host)); - QuicFramer framer(QuicDecrypter::Create(kNULL), + QuicFramer framer(kQuicVersion1, + QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *chlo)); } scoped_ptr<QuicEncryptedPacket> ConstructShlo() { scoped_ptr<QuicPacket> shlo(ConstructHandshakePacket(0xDEADBEEF, kSHLO)); - QuicFramer framer(QuicDecrypter::Create(kNULL), + QuicFramer framer(kQuicVersion1, + QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(1, *shlo)); } @@ -87,7 +89,8 @@ class QuicStreamFactoryTest : public ::testing::Test { feedback.tcp.accumulated_number_of_lost_packets = 0; feedback.tcp.receive_window = 16000; - QuicFramer framer(QuicDecrypter::Create(kNULL), + QuicFramer framer(kQuicVersion1, + QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); QuicFrames frames; frames.push_back(QuicFrame(&ack)); @@ -123,7 +126,8 @@ class QuicStreamFactoryTest : public ::testing::Test { scoped_ptr<QuicEncryptedPacket> ConstructPacket( const QuicPacketHeader& header, const QuicFrame& frame) { - QuicFramer framer(QuicDecrypter::Create(kNULL), + QuicFramer framer(kQuicVersion1, + QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); QuicFrames frames; frames.push_back(frame); diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc index ec2a410..07c2045 100644 --- a/net/quic/quic_stream_sequencer.cc +++ b/net/quic/quic_stream_sequencer.cc @@ -158,8 +158,8 @@ bool QuicStreamSequencer::IsDuplicate(const QuicStreamFrame& frame) const { // or we have stored the frame in our map. // TODO(pwestin): Is it possible that a new frame contain more data even if // the offset is the same? - return (frame.offset < num_bytes_consumed_ || - frames_.find(frame.offset) != frames_.end()); + return frame.offset < num_bytes_consumed_ || + frames_.find(frame.offset) != frames_.end(); } void QuicStreamSequencer::FlushBufferedFrames() { diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc index ae52876..414e0f4 100644 --- a/net/quic/quic_utils.cc +++ b/net/quic/quic_utils.cc @@ -10,14 +10,6 @@ namespace net { // static -size_t QuicUtils::StreamFramePacketOverhead(int num_frames) { - // TODO(jar): Use sizeof(some name). - return kPacketHeaderSize + - (kFrameTypeSize + - kMinStreamFrameLength) * num_frames; -} - -// static uint128 QuicUtils::FNV1a_128_Hash(const char* data, int len) { // The following two constants are defined as part of the hash algorithm. // see http://www.isthe.com/chongo/tech/comp/fnv/ diff --git a/net/quic/quic_utils.h b/net/quic/quic_utils.h index bddd87f..34f749e 100644 --- a/net/quic/quic_utils.h +++ b/net/quic/quic_utils.h @@ -15,10 +15,6 @@ namespace net { class NET_EXPORT_PRIVATE QuicUtils { public: - // The overhead the quic framing will add for a packet with num_frames - // frames. - static size_t StreamFramePacketOverhead(int num_frames); - // returns the 128 bit FNV1a hash of the data. See // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param static uint128 FNV1a_128_Hash(const char* data, int len); diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc index 014f6de..0800dc8 100644 --- a/net/quic/reliable_quic_stream_test.cc +++ b/net/quic/reliable_quic_stream_test.cc @@ -49,7 +49,7 @@ class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> { TEST_F(ReliableQuicStreamTest, WriteAllData) { connection_->options()->max_packet_length = - 1 + QuicUtils::StreamFramePacketOverhead(1); + 1 + QuicPacketCreator::StreamFramePacketOverhead(1, !kIncludeVersion); // TODO(rch): figure out how to get StrEq working here. //EXPECT_CALL(session_, WriteData(_, StrEq(kData1), _, _)).WillOnce( EXPECT_CALL(session_, WriteData(1, _, _, _)).WillOnce( @@ -59,7 +59,8 @@ TEST_F(ReliableQuicStreamTest, WriteAllData) { TEST_F(ReliableQuicStreamTest, WriteData) { connection_->options()->max_packet_length = - 1 + QuicUtils::StreamFramePacketOverhead(1); + 1 + QuicPacketCreator::StreamFramePacketOverhead(1, !kIncludeVersion); + // TODO(rch): figure out how to get StrEq working here. //EXPECT_CALL(session_, WriteData(_, StrEq(kData1), _, _)).WillOnce( EXPECT_CALL(session_, WriteData(_, _, _, _)).WillOnce( Return(QuicConsumedData(kDataLen - 1, false))); diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index 0f265a5..9faec9a 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc @@ -8,8 +8,10 @@ #include "net/quic/crypto/crypto_framer.h" #include "net/quic/crypto/crypto_handshake.h" #include "net/quic/crypto/crypto_utils.h" +#include "net/quic/crypto/null_encrypter.h" #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" +#include "net/quic/quic_packet_creator.h" using std::max; using std::min; @@ -245,7 +247,8 @@ static QuicPacket* ConstructPacketFromHandshakeMessage( const CryptoHandshakeMessage& message) { CryptoFramer crypto_framer; scoped_ptr<QuicData> data(crypto_framer.ConstructHandshakeMessage(message)); - QuicFramer quic_framer(QuicDecrypter::Create(kNULL), + QuicFramer quic_framer(kQuicVersion1, + QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)); QuicPacketHeader header; @@ -301,6 +304,11 @@ QuicPacket* ConstructServerHelloPacket(QuicGuid guid, return ConstructPacketFromHandshakeMessage(guid, server_hello); } +size_t GetPacketLengthForOneStream(bool include_version, size_t payload) { + return NullEncrypter().GetCiphertextSize(payload) + + QuicPacketCreator::StreamFramePacketOverhead(1, include_version); +} + QuicPacketEntropyHash TestEntropyCalculator::ReceivedEntropyHash( QuicPacketSequenceNumber sequence_number) const { return 1u; diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 7724d16..199ea02 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h @@ -45,6 +45,10 @@ QuicPacket* ConstructServerHelloPacket(QuicGuid guid, const QuicClock* clock, QuicRandom* random_generator); +// Returns the length of the QuicPacket that will be created if it contains +// a stream frame that has |payload| bytes. +size_t GetPacketLengthForOneStream(bool include_version, size_t payload); + class MockFramerVisitor : public QuicFramerVisitorInterface { public: MockFramerVisitor(); @@ -131,9 +135,9 @@ class FramerVisitorCapturingFrames : public NoOpFramerVisitor { const QuicConnectionCloseFrame& frame) OVERRIDE; virtual void OnGoAwayFrame(const QuicGoAwayFrame& frame) OVERRIDE; - size_t frame_count() { return frame_count_; } + size_t frame_count() const { return frame_count_; } QuicPacketHeader* header() { return &header_; } - const std::vector<QuicStreamFrame>* stream_frames() { + const std::vector<QuicStreamFrame>* stream_frames() const { return &stream_frames_; } QuicAckFrame* ack() { return ack_.get(); } diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc index dc69642..e477a93 100644 --- a/net/quic/test_tools/simple_quic_framer.cc +++ b/net/quic/test_tools/simple_quic_framer.cc @@ -113,7 +113,9 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { }; SimpleQuicFramer::SimpleQuicFramer() - : framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)) { + : framer_(kQuicVersion1, + QuicDecrypter::Create(kNULL), + QuicEncrypter::Create(kNULL)) { } SimpleQuicFramer::~SimpleQuicFramer() { |