summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-03 07:22:41 +0000
committerrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-03 07:22:41 +0000
commit5351cc4b92a85cd508cf6944386141945a913f5e (patch)
tree4f91215a3fb703da4e17f3663f430d02d8f65592 /net
parent20ba262d5122abe134b6e78ddb574c1a419505ab (diff)
downloadchromium_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')
-rw-r--r--net/net.gyp2
-rw-r--r--net/quic/blocked_list.h91
-rw-r--r--net/quic/blocked_list_test.cc83
-rw-r--r--net/quic/crypto/crypto_protocol.h8
-rw-r--r--net/quic/quic_client_session_test.cc4
-rw-r--r--net/quic/quic_connection.cc23
-rw-r--r--net/quic/quic_connection_helper_test.cc4
-rw-r--r--net/quic/quic_connection_test.cc35
-rw-r--r--net/quic/quic_crypto_client_stream_test.cc3
-rw-r--r--net/quic/quic_fec_group.h2
-rw-r--r--net/quic/quic_framer.cc160
-rw-r--r--net/quic/quic_framer.h53
-rw-r--r--net/quic/quic_framer_test.cc459
-rw-r--r--net/quic/quic_http_stream_test.cc4
-rw-r--r--net/quic/quic_network_transaction_unittest.cc12
-rw-r--r--net/quic/quic_packet_creator.cc23
-rw-r--r--net/quic/quic_packet_creator.h7
-rw-r--r--net/quic/quic_packet_creator_test.cc14
-rw-r--r--net/quic/quic_packet_generator.cc3
-rw-r--r--net/quic/quic_packet_generator.h16
-rw-r--r--net/quic/quic_packet_generator_test.cc4
-rw-r--r--net/quic/quic_protocol.cc52
-rw-r--r--net/quic/quic_protocol.h122
-rw-r--r--net/quic/quic_session.cc12
-rw-r--r--net/quic/quic_session.h5
-rw-r--r--net/quic/quic_stream_factory_test.cc12
-rw-r--r--net/quic/quic_stream_sequencer.cc4
-rw-r--r--net/quic/quic_utils.cc8
-rw-r--r--net/quic/quic_utils.h4
-rw-r--r--net/quic/reliable_quic_stream_test.cc5
-rw-r--r--net/quic/test_tools/quic_test_utils.cc10
-rw-r--r--net/quic/test_tools/quic_test_utils.h8
-rw-r--r--net/quic/test_tools/simple_quic_framer.cc4
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() {