summaryrefslogtreecommitdiffstats
path: root/net/quic
diff options
context:
space:
mode:
authorrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-05 20:57:30 +0000
committerrtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-05 20:57:30 +0000
commitf62262b8eb43c6a4ff8298bbf685924ba3292eab (patch)
tree44b99c48e9f51746890ba6fb46d0051adb16e3f5 /net/quic
parentf666276a1c9df0bab723c76bb25288df87c46f06 (diff)
downloadchromium_src-f62262b8eb43c6a4ff8298bbf685924ba3292eab.zip
chromium_src-f62262b8eb43c6a4ff8298bbf685924ba3292eab.tar.gz
chromium_src-f62262b8eb43c6a4ff8298bbf685924ba3292eab.tar.bz2
Land Recent QUIC changes.
Implement the variable length changes necessary to easily accommodate both the new STREAM framing format, as well as the existing format. Merge internal change: 48567379 Stop storing two copies of the version (one in Connection, one in Framer), instead only the Framer stores the version. Merge internal change: 48452109 Cleaning up QuicPacketEntropyManager as part of an effort reduce EndToEndTest::LargePostFEC flakiness, and avoid sending incorrect entropy. Merge internal change: 48443412 Enabling a handful of cert selection tests for secure QUIC Merge internal change: 48306046 QUIC: support default certificates. In the event that the client doesn't supply an SNI value but does request a certificate, the server will use its default certificate. Merge internal change: 48305575 Added more comments to QuicPacket{Public,Private}Flags enums. Merge internal change: 48304472 R=rch@chromium.org Review URL: https://chromiumcodereview.appspot.com/18497011 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@210324 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/quic')
-rw-r--r--net/quic/crypto/crypto_server_config.cc2
-rw-r--r--net/quic/crypto/crypto_server_test.cc103
-rw-r--r--net/quic/crypto/proof_source.h5
-rw-r--r--net/quic/crypto/proof_source_chromium.cc22
-rw-r--r--net/quic/crypto/proof_source_chromium.h37
-rw-r--r--net/quic/quic_connection.cc19
-rw-r--r--net/quic/quic_connection.h6
-rw-r--r--net/quic/quic_connection_test.cc38
-rw-r--r--net/quic/quic_framer.cc34
-rw-r--r--net/quic/quic_framer.h10
-rw-r--r--net/quic/quic_packet_creator.cc21
-rw-r--r--net/quic/quic_packet_creator.h3
-rw-r--r--net/quic/quic_packet_creator_test.cc13
-rw-r--r--net/quic/quic_packet_entropy_manager.cc52
-rw-r--r--net/quic/quic_packet_entropy_manager.h29
-rw-r--r--net/quic/quic_packet_entropy_manager_test.cc11
-rw-r--r--net/quic/quic_protocol.h44
-rw-r--r--net/quic/reliable_quic_stream_test.cc4
-rw-r--r--net/quic/test_tools/crypto_test_utils.cc6
-rw-r--r--net/quic/test_tools/quic_test_utils.cc24
-rw-r--r--net/quic/test_tools/quic_test_utils.h7
21 files changed, 348 insertions, 142 deletions
diff --git a/net/quic/crypto/crypto_server_config.cc b/net/quic/crypto/crypto_server_config.cc
index 9c2f67b..b28207f 100644
--- a/net/quic/crypto/crypto_server_config.cc
+++ b/net/quic/crypto/crypto_server_config.cc
@@ -674,7 +674,7 @@ void QuicCryptoServerConfig::BuildRejection(
const QuicTag* their_proof_demands;
size_t num_their_proof_demands;
- if (proof_source_.get() != NULL && !info.sni.empty() &&
+ if (proof_source_.get() != NULL &&
client_hello.GetTaglist(kPDMD, &their_proof_demands,
&num_their_proof_demands) ==
QUIC_NO_ERROR) {
diff --git a/net/quic/crypto/crypto_server_test.cc b/net/quic/crypto/crypto_server_test.cc
index 0a5a603..b2cdf82 100644
--- a/net/quic/crypto/crypto_server_test.cc
+++ b/net/quic/crypto/crypto_server_test.cc
@@ -23,6 +23,7 @@ class CryptoServerTest : public ::testing::Test {
config_(QuicCryptoServerConfig::TESTING, rand_),
addr_(ParseIPLiteralToNumber("192.0.2.33", &ip_) ?
ip_ : IPAddressNumber(), 1) {
+ config_.SetProofSource(CryptoTestUtils::ProofSourceForTesting());
}
virtual void SetUp() {
@@ -34,6 +35,38 @@ class CryptoServerTest : public ::testing::Test {
CHECK(msg->GetStringPiece(kORBT, &orbit));
CHECK_EQ(sizeof(orbit_), orbit.size());
memcpy(orbit_, orbit.data(), orbit.size());
+
+ char public_value[32];
+ memset(public_value, 42, sizeof(public_value));
+
+ const string nonce_str = GenerateNonce();
+ nonce_hex_ = "#" + base::HexEncode(nonce_str.data(), nonce_str.size());
+ pub_hex_ = "#" + base::HexEncode(public_value, sizeof(public_value));
+
+ CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
+ "CHLO",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ NULL);
+ ShouldSucceed(client_hello);
+ // The message should be rejected because the source-address token is
+ // missing.
+ ASSERT_EQ(kREJ, out_.tag());
+
+ StringPiece srct;
+ ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct));
+ srct_hex_ = "#" + base::HexEncode(srct.data(), srct.size());
+
+ StringPiece scfg;
+ ASSERT_TRUE(out_.GetStringPiece(kSCFG, &scfg));
+ server_config_.reset(CryptoFramer::ParseMessage(scfg));
+
+ StringPiece scid;
+ ASSERT_TRUE(server_config_->GetStringPiece(kSCID, &scid));
+ scid_hex_ = "#" + base::HexEncode(scid.data(), scid.size());
}
void ShouldSucceed(const CryptoHandshakeMessage& message) {
@@ -91,6 +124,11 @@ class CryptoServerTest : public ::testing::Test {
IPAddressNumber ip_;
IPEndPoint addr_;
uint8 orbit_[kOrbitSize];
+
+ // These strings contain hex escaped values from the server suitable for
+ // passing to |InchoateClientHello| when constructing client hello messages.
+ string nonce_hex_, pub_hex_, srct_hex_, scid_hex_;
+ scoped_ptr<CryptoHandshakeMessage> server_config_;
};
TEST_F(CryptoServerTest, BadSNI) {
@@ -111,6 +149,29 @@ TEST_F(CryptoServerTest, BadSNI) {
}
}
+// TODO(rtenneti): Enable the DefaultCert test after implementing ProofSource.
+TEST_F(CryptoServerTest, DISABLED_DefaultCert) {
+ // Check that the server replies with a default certificate when no SNI is
+ // specified.
+ ShouldSucceed(InchoateClientHello(
+ "CHLO",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ "PDMD", "X509",
+ NULL));
+
+ StringPiece cert, proof;
+ EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert));
+ EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof));
+ EXPECT_NE(0u, cert.size());
+ EXPECT_NE(0u, proof.size());
+}
+
TEST_F(CryptoServerTest, TooSmall) {
ShouldFailMentioning("too small", CryptoTestUtils::Message(
"CHLO",
@@ -152,48 +213,14 @@ TEST_F(CryptoServerTest, BadClientNonce) {
TEST_F(CryptoServerTest, ReplayProtection) {
// This tests that disabling replay protection works.
-
- char public_value[32];
- memset(public_value, 42, sizeof(public_value));
-
- const string nonce_str = GenerateNonce();
- const string nonce("#" + base::HexEncode(nonce_str.data(),
- nonce_str.size()));
- const string pub("#" + base::HexEncode(public_value, sizeof(public_value)));
-
CryptoHandshakeMessage msg = CryptoTestUtils::Message(
"CHLO",
"AEAD", "AESG",
"KEXS", "C255",
- "PUBS", pub.c_str(),
- "NONC", nonce.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- NULL);
- ShouldSucceed(msg);
- // The message should be rejected because the source-address token is missing.
- ASSERT_EQ(kREJ, out_.tag());
-
- StringPiece srct;
- ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct));
- const string srct_hex = "#" + base::HexEncode(srct.data(), srct.size());
-
- StringPiece scfg;
- ASSERT_TRUE(out_.GetStringPiece(kSCFG, &scfg));
- scoped_ptr<CryptoHandshakeMessage> server_config(
- CryptoFramer::ParseMessage(scfg));
-
- StringPiece scid;
- ASSERT_TRUE(server_config->GetStringPiece(kSCID, &scid));
- const string scid_hex("#" + base::HexEncode(scid.data(), scid.size()));
-
- msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex.c_str(),
- "#004b5453", srct_hex.c_str(),
- "PUBS", pub.c_str(),
- "NONC", nonce.c_str(),
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
"$padding", static_cast<int>(kClientHelloMinimumSize),
NULL);
ShouldSucceed(msg);
diff --git a/net/quic/crypto/proof_source.h b/net/quic/crypto/proof_source.h
index 75b2ba0..b788a79 100644
--- a/net/quic/crypto/proof_source.h
+++ b/net/quic/crypto/proof_source.h
@@ -25,6 +25,8 @@ class NET_EXPORT_PRIVATE ProofSource {
// The signature uses SHA-256 as the hash function and PSS padding when the
// key is RSA.
//
+ // The signature uses SHA-256 as the hash function when the key is ECDSA.
+ //
// |out_certs| is a pointer to a pointer, not a pointer to an array.
//
// The number of certificate chains is expected to be small and fixed thus
@@ -36,6 +38,9 @@ class NET_EXPORT_PRIVATE ProofSource {
// wish to evicit entries from that cache, thus the caller takes ownership of
// |*out_signature|.
//
+ // |hostname| may be empty to signify that a default certificate should be
+ // used.
+ //
// This function may be called concurrently.
virtual bool GetProof(const std::string& hostname,
const std::string& server_config,
diff --git a/net/quic/crypto/proof_source_chromium.cc b/net/quic/crypto/proof_source_chromium.cc
new file mode 100644
index 0000000..48c2b77
--- /dev/null
+++ b/net/quic/crypto/proof_source_chromium.cc
@@ -0,0 +1,22 @@
+// Copyright 2013 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/crypto/proof_source_chromium.h"
+
+using std::string;
+using std::vector;
+
+namespace net {
+
+ProofSourceChromium::ProofSourceChromium() {
+}
+
+bool ProofSourceChromium::GetProof(const string& hostname,
+ const string& server_config,
+ const vector<string>** out_certs,
+ string* out_signature) {
+ return false;
+}
+
+} // namespace net
diff --git a/net/quic/crypto/proof_source_chromium.h b/net/quic/crypto/proof_source_chromium.h
new file mode 100644
index 0000000..fb0b6a6
--- /dev/null
+++ b/net/quic/crypto/proof_source_chromium.h
@@ -0,0 +1,37 @@
+// Copyright 2013 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.
+
+#ifndef NET_QUIC_CRYPTO_PROOF_SOURCE_CHROMIUM_H_
+#define NET_QUIC_CRYPTO_PROOF_SOURCE_CHROMIUM_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "net/base/net_export.h"
+#include "net/quic/crypto/proof_source.h"
+
+namespace net {
+
+// ProofSourceChromium implements the QUIC ProofSource interface.
+// TODO(rtenneti): implement details of this class.
+class NET_EXPORT_PRIVATE ProofSourceChromium : public ProofSource {
+ public:
+ ProofSourceChromium();
+ virtual ~ProofSourceChromium() {}
+
+ // ProofSource interface
+ virtual bool GetProof(const std::string& hostname,
+ const std::string& server_config,
+ const std::vector<std::string>** out_certs,
+ std::string* out_signature) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProofSourceChromium);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_PROOF_SOURCE_CHROMIUM_H_
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 65f80b3..f8a821a 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -97,7 +97,6 @@ QuicConnection::QuicConnection(QuicGuid guid,
time_largest_observed_(QuicTime::Zero()),
congestion_manager_(clock_, kTCP),
version_negotiation_state_(START_NEGOTIATION),
- quic_version_(kQuicVersion1),
max_packets_per_retransmission_alarm_(kMaxPacketsPerRetransmissionAlarm),
is_server_(is_server),
connected_(true),
@@ -142,8 +141,8 @@ bool QuicConnection::SelectMutualVersion(
}
// Right now we only support kQuicVersion1 so it's okay not to
- // update the framer and quic_version_. When start supporting more
- // versions please update both.
+ // update the framer version. When we start supporting more
+ // versions please update.
return true;
}
@@ -175,7 +174,7 @@ bool QuicConnection::OnProtocolVersionMismatch(QuicTag received_version) {
CloseConnection(QUIC_INTERNAL_ERROR, false);
return false;
}
- DCHECK_NE(quic_version_, received_version);
+ DCHECK_NE(version(), received_version);
if (debug_visitor_) {
debug_visitor_->OnProtocolVersionMismatch(received_version);
@@ -207,8 +206,8 @@ bool QuicConnection::OnProtocolVersionMismatch(QuicTag received_version) {
}
// Right now we only support kQuicVersion1 so it's okay not to
- // update the framer and quic_version_. When start supporting more
- // versions please update both.
+ // update the framer version. When we start supporting more
+ // versions please update.
version_negotiation_state_ = NEGOTIATED_VERSION;
// TODO(satyamshekhar): Store the sequence number of this packet and close the
// connection if we ever received a packet with incorrect version and whose
@@ -235,7 +234,7 @@ void QuicConnection::OnVersionNegotiationPacket(
}
if (std::find(packet.versions.begin(),
- packet.versions.end(), quic_version_) !=
+ packet.versions.end(), version()) !=
packet.versions.end()) {
DLOG(WARNING) << ENDPOINT << "The server already supports our version. "
<< "It should have accepted our connection.";
@@ -302,7 +301,7 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
return false;
} else {
DCHECK_EQ(1u, header.public_header.versions.size());
- DCHECK_EQ(header.public_header.versions[0], quic_version_);
+ DCHECK_EQ(header.public_header.versions[0], version());
version_negotiation_state_ = NEGOTIATED_VERSION;
}
} else {
@@ -585,10 +584,6 @@ void QuicConnection::UpdatePacketInformationSentByPeer(
incoming_ack.sent_info.entropy_hash);
}
peer_least_packet_awaiting_ack_ = incoming_ack.sent_info.least_unacked;
- // TODO(satyamshekhar): We get this iterator O(logN) in
- // RecalculateReceivedEntropyHash also.
- entropy_manager_.ClearReceivedEntropyBefore(
- peer_least_packet_awaiting_ack_);
}
DCHECK(outgoing_ack_.received_info.missing_packets.empty() ||
*outgoing_ack_.received_info.missing_packets.begin() >=
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index fabcc9c..d869937 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -275,7 +275,8 @@ class NET_EXPORT_PRIVATE QuicConnection
// can be handled, false otherwise.
bool ProcessValidatedPacket();
- QuicTag version() const { return quic_version_; }
+ // The version of the protocol this connection is using.
+ QuicTag version() const { return framer_.version(); }
// From QuicFramerVisitorInterface
virtual void OnError(QuicFramer* framer) OVERRIDE;
@@ -684,9 +685,6 @@ class NET_EXPORT_PRIVATE QuicConnection
// The state of connection in version negotiation finite state machine.
QuicVersionNegotiationState version_negotiation_state_;
- // The version of the protocol this connection is using.
- QuicTag quic_version_;
-
size_t max_packets_per_retransmission_alarm_;
// Tracks if the connection was created by the server.
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 8fb1868..b170d0d 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -969,31 +969,36 @@ TEST_F(QuicConnectionTest, BasicSending) {
}
TEST_F(QuicConnectionTest, FECSending) {
- // Limit to one byte per packet.
// All packets carry version info till version is negotiated.
+ size_t payload_length;
connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(kIncludeVersion, IN_FEC_GROUP, 4);
+ GetPacketLengthForOneStream(
+ kIncludeVersion, IN_FEC_GROUP, &payload_length);
// And send FEC every two packets.
connection_.options()->max_packets_per_fec_group = 2;
// Send 4 data packets and 2 FEC packets.
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(6);
- connection_.SendStreamData(1, "foodfoodfoodfood", 0, !kFin);
+ // TODO(ianswett): The first stream frame will consume 2 fewer bytes.
+ const string payload(payload_length * 4, 'a');
+ connection_.SendStreamData(1, payload, 0, !kFin);
// Expect the FEC group to be closed after SendStreamData.
EXPECT_FALSE(creator_.ShouldSendFec(true));
}
TEST_F(QuicConnectionTest, FECQueueing) {
- // Limit to one byte per packet.
// All packets carry version info till version is negotiated.
+ size_t payload_length;
connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(kIncludeVersion, IN_FEC_GROUP, 4);
+ GetPacketLengthForOneStream(
+ kIncludeVersion, IN_FEC_GROUP, &payload_length);
// And send FEC every two packets.
connection_.options()->max_packets_per_fec_group = 2;
EXPECT_EQ(0u, connection_.NumQueuedPackets());
helper_->set_blocked(true);
- connection_.SendStreamData(1, "food", 0, !kFin);
+ const string payload(payload_length, 'a');
+ connection_.SendStreamData(1, payload, 0, !kFin);
EXPECT_FALSE(creator_.ShouldSendFec(true));
// Expect the first data packet and the fec packet to be queued.
EXPECT_EQ(2u, connection_.NumQueuedPackets());
@@ -1905,30 +1910,35 @@ TEST_F(QuicConnectionTest, SendSchedulerDelayThenOnCanWrite) {
}
TEST_F(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
- // Limit to one byte per packet.
// All packets carry version info till version is negotiated.
+ size_t payload_length;
connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(kIncludeVersion, NOT_IN_FEC_GROUP, 4);
+ GetPacketLengthForOneStream(
+ kIncludeVersion, NOT_IN_FEC_GROUP, &payload_length);
// Queue the first packet.
EXPECT_CALL(*send_algorithm_,
TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce(
testing::Return(QuicTime::Delta::FromMicroseconds(10)));
- EXPECT_EQ(0u, connection_.SendStreamData(
- 1, "EnoughDataToQueue", 0, !kFin).bytes_consumed);
+ const string payload(payload_length, 'a');
+ EXPECT_EQ(0u,
+ connection_.SendStreamData(1, payload, 0, !kFin).bytes_consumed);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
}
TEST_F(QuicConnectionTest, LoopThroughSendingPackets) {
- // Limit to 4 bytes per packet.
// All packets carry version info till version is negotiated.
+ size_t payload_length;
connection_.options()->max_packet_length =
- GetPacketLengthForOneStream(kIncludeVersion, NOT_IN_FEC_GROUP, 4);
+ GetPacketLengthForOneStream(
+ kIncludeVersion, NOT_IN_FEC_GROUP, &payload_length);
// Queue the first packet.
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(7);
- EXPECT_EQ(27u, connection_.SendStreamData(
- 1, "EnoughDataToQueueStreamData", 0, !kFin).bytes_consumed);
+ // TODO(ianswett): The first stream frame will consume 2 fewer bytes.
+ const string payload(payload_length * 7, 'a');
+ EXPECT_EQ(payload.size(),
+ connection_.SendStreamData(1, payload, 0, !kFin).bytes_consumed);
}
TEST_F(QuicConnectionTest, NoAckForClose) {
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 5099838..1df3590 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -87,6 +87,16 @@ size_t QuicFramer::GetMinStreamFrameSize() {
}
// static
+size_t QuicFramer::GetMinStreamFrameSize(QuicStreamId stream_id,
+ QuicStreamOffset offset,
+ bool last_frame) {
+ // TODO(ianswett): Remove kQuicStreamFinSize for the next STREAM framing.
+ return kQuicFrameTypeSize + GetStreamIdSize(stream_id) +
+ GetStreamOffsetSize(offset) + kQuicStreamFinSize +
+ kQuicStreamPayloadLengthSize;
+}
+
+// static
size_t QuicFramer::GetMinAckFrameSize() {
return kQuicFrameTypeSize + kQuicEntropyHashSize +
PACKET_6BYTE_SEQUENCE_NUMBER + kQuicEntropyHashSize +
@@ -122,6 +132,16 @@ size_t QuicFramer::GetMaxUnackedPackets(QuicPacketHeader header) {
GetMinAckFrameSize() - 16) / PACKET_6BYTE_SEQUENCE_NUMBER;
}
+// static
+size_t QuicFramer::GetStreamIdSize(QuicStreamId stream_id) {
+ return 4;
+}
+
+// static
+size_t QuicFramer::GetStreamOffsetSize(QuicStreamOffset offset) {
+ return 8;
+}
+
bool QuicFramer::IsSupportedVersion(QuicTag version) {
return version == kQuicVersion1;
}
@@ -137,7 +157,8 @@ size_t QuicFramer::GetSerializedFrameLength(
// PADDING implies end of packet.
return free_bytes;
}
- size_t frame_len = ComputeFrameLength(frame);
+ // See if it fits as the non-last frame.
+ size_t frame_len = ComputeFrameLength(frame, false);
if (frame_len > free_bytes) {
// Only truncate the first frame in a packet, so if subsequent ones go
// over, stop including more frames.
@@ -194,6 +215,7 @@ SerializedPacket QuicFramer::ConstructFrameDataPacket(
for (size_t i = 0; i < frames.size(); ++i) {
const QuicFrame& frame = frames[i];
+
if (!writer.WriteUInt8(frame.type)) {
return kNoPacket;
}
@@ -203,7 +225,8 @@ SerializedPacket QuicFramer::ConstructFrameDataPacket(
writer.WritePadding();
break;
case STREAM_FRAME:
- if (!AppendStreamFramePayload(*frame.stream_frame, &writer)) {
+ if (!AppendStreamFramePayload(
+ *frame.stream_frame, &writer)) {
return kNoPacket;
}
break;
@@ -1328,10 +1351,13 @@ bool QuicFramer::DecryptPayload(const QuicPacketHeader& header,
return true;
}
-size_t QuicFramer::ComputeFrameLength(const QuicFrame& frame) {
+size_t QuicFramer::ComputeFrameLength(const QuicFrame& frame, bool last_frame) {
switch (frame.type) {
case STREAM_FRAME:
- return GetMinStreamFrameSize() + frame.stream_frame->data.size();
+ return GetMinStreamFrameSize(frame.stream_frame->stream_id,
+ frame.stream_frame->offset,
+ last_frame) +
+ frame.stream_frame->data.size();
case ACK_FRAME: {
const QuicAckFrame& ack = *frame.ack_frame;
return GetMinAckFrameSize() + PACKET_6BYTE_SEQUENCE_NUMBER *
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index 76410db..dd3eaef 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -222,6 +222,10 @@ class NET_EXPORT_PRIVATE QuicFramer {
// Size in bytes of all stream frame fields without the payload.
static size_t GetMinStreamFrameSize();
+ // Size in bytes of all stream frame fields without the payload.
+ static size_t GetMinStreamFrameSize(QuicStreamId stream_id,
+ QuicStreamOffset offset,
+ bool last_frame);
// 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.
@@ -234,6 +238,10 @@ class NET_EXPORT_PRIVATE QuicFramer {
// The maximum number of nacks which can be transmitted in a single ack packet
// without exceeding kMaxPacketSize.
static size_t GetMaxUnackedPackets(QuicPacketHeader header);
+ // Size in bytes required to serialize the stream id.
+ static size_t GetStreamIdSize(QuicStreamId stream_id);
+ // Size in bytes required to serialize the stream offset.
+ static size_t GetStreamOffsetSize(QuicStreamOffset offset);
// Size in bytes required for a serialized version negotiation packet
size_t GetVersionNegotiationPacketSize(size_t number_versions);
@@ -367,7 +375,7 @@ class NET_EXPORT_PRIVATE QuicFramer {
QuicPacketSequenceNumber packet_sequence_number) const;
// Computes the wire size in bytes of the payload of |frame|.
- size_t ComputeFrameLength(const QuicFrame& frame);
+ size_t ComputeFrameLength(const QuicFrame& frame, bool last_frame);
static bool AppendPacketSequenceNumber(
QuicSequenceNumberLength sequence_number_length,
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index d1c3ca1..139ed41 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -83,14 +83,14 @@ bool QuicPacketCreator::HasRoomForStreamFrame() const {
// static
size_t QuicPacketCreator::StreamFramePacketOverhead(
- int num_frames,
QuicGuidLength guid_length,
bool include_version,
QuicSequenceNumberLength sequence_number_length,
InFecGroup is_in_fec_group) {
return GetPacketHeaderSize(guid_length, include_version,
sequence_number_length, is_in_fec_group) +
- QuicFramer::GetMinStreamFrameSize() * num_frames;
+ // Assumes this is a stream with a single lone packet.
+ QuicFramer::GetMinStreamFrameSize(1, 0, true);
}
size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
@@ -100,7 +100,7 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
QuicFrame* frame) {
DCHECK_GT(options_.max_packet_length,
StreamFramePacketOverhead(
- 1, PACKET_8BYTE_GUID, kIncludeVersion,
+ PACKET_8BYTE_GUID, kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, IN_FEC_GROUP));
DCHECK(HasRoomForStreamFrame());
@@ -108,8 +108,19 @@ size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
size_t bytes_consumed = 0;
if (data.size() != 0) {
- size_t max_data_len = free_bytes - QuicFramer::GetMinStreamFrameSize();
- bytes_consumed = min<size_t>(max_data_len, data.size());
+ size_t min_last_stream_frame_size =
+ QuicFramer::GetMinStreamFrameSize(id, offset, true);
+ // Comparing against the last stream frame size including the length
+ // guarantees that all the bytes will fit. Otherwise there is a
+ // discontinuity where the packet goes one byte over due to the length data.
+ if (data.size() > free_bytes - min_last_stream_frame_size -
+ kQuicStreamPayloadLengthSize) {
+ // Its the last frame, put as much data as possible in.
+ bytes_consumed =
+ min<size_t>(free_bytes - min_last_stream_frame_size, data.size());
+ } else {
+ bytes_consumed = data.size();
+ }
bool set_fin = fin && bytes_consumed == data.size(); // Last frame.
StringPiece data_frame(data.data(), bytes_consumed);
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index 86a5c0e..8abd49c 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -69,9 +69,8 @@ class NET_EXPORT_PRIVATE QuicPacketCreator : public QuicFecBuilderInterface {
// Makes the framer not serialize the protocol version in sent packets.
void StopSendingVersion();
- // The overhead the framing will add for a packet with num_frames frames.
+ // The overhead the framing will add for a packet with one frame.
static size_t StreamFramePacketOverhead(
- int num_frames,
QuicGuidLength guid_length,
bool include_version,
QuicSequenceNumberLength sequence_number_length,
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index f972182..7a8daa4c 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -224,14 +224,17 @@ TEST_P(QuicPacketCreatorTest, CreateStreamFrameTooLarge) {
creator_.StopSendingVersion();
}
// A string larger than fits into a frame.
+ size_t payload_length;
creator_.options()->max_packet_length = GetPacketLengthForOneStream(
QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
- NOT_IN_FEC_GROUP, 4);
+ NOT_IN_FEC_GROUP, &payload_length);
QuicFrame frame;
- size_t consumed = creator_.CreateStreamFrame(1u, "testTooLong", 0u, true,
- &frame);
- EXPECT_EQ(4u, consumed);
- CheckStreamFrame(frame, 1u, "test", 0u, false);
+ const string too_long_payload(payload_length * 2, 'a');
+ size_t consumed = creator_.CreateStreamFrame(
+ 1u, too_long_payload, 0u, true, &frame);
+ EXPECT_EQ(payload_length, consumed);
+ const string payload(payload_length, 'a');
+ CheckStreamFrame(frame, 1u, payload, 0u, false);
delete frame.stream_frame;
}
diff --git a/net/quic/quic_packet_entropy_manager.cc b/net/quic/quic_packet_entropy_manager.cc
index 35fb198..5f152c0 100644
--- a/net/quic/quic_packet_entropy_manager.cc
+++ b/net/quic/quic_packet_entropy_manager.cc
@@ -9,6 +9,7 @@
using std::make_pair;
using std::max;
+using std::min;
namespace net {
@@ -19,12 +20,23 @@ QuicPacketEntropyManager::QuicPacketEntropyManager()
QuicPacketEntropyManager::~QuicPacketEntropyManager() {}
+QuicPacketSequenceNumber
+QuicPacketEntropyManager::LargestReceivedSequenceNumber() const {
+ if (received_packets_entropy_.empty()) {
+ return 0;
+ }
+ return received_packets_entropy_.rbegin()->first;
+}
+
void QuicPacketEntropyManager::RecordReceivedPacketEntropyHash(
QuicPacketSequenceNumber sequence_number,
QuicPacketEntropyHash entropy_hash) {
- largest_received_sequence_number_ =
- max<QuicPacketSequenceNumber>(largest_received_sequence_number_,
- sequence_number);
+ if (sequence_number < largest_received_sequence_number_) {
+ DLOG(INFO) << "Ignoring received packet entropy for sequence_number:"
+ << sequence_number << " less than largest_peer_sequence_number:"
+ << largest_received_sequence_number_;
+ return;
+ }
received_packets_entropy_.insert(make_pair(sequence_number, entropy_hash));
received_packets_entropy_hash_ ^= entropy_hash;
DVLOG(2) << "setting cumulative received entropy hash to: "
@@ -50,7 +62,9 @@ void QuicPacketEntropyManager::RecordSentPacketEntropyHash(
QuicPacketEntropyHash QuicPacketEntropyManager::ReceivedEntropyHash(
QuicPacketSequenceNumber sequence_number) const {
- if (sequence_number == largest_received_sequence_number_) {
+ DCHECK_LE(sequence_number, LargestReceivedSequenceNumber());
+ DCHECK_GE(sequence_number, largest_received_sequence_number_);
+ if (sequence_number == LargestReceivedSequenceNumber()) {
return received_packets_entropy_hash_;
}
@@ -59,7 +73,7 @@ QuicPacketEntropyHash QuicPacketEntropyManager::ReceivedEntropyHash(
// When this map is empty we should only query entropy for
// |largest_received_sequence_number_|.
LOG_IF(WARNING, it != received_packets_entropy_.end())
- << "largest_received: " << largest_received_sequence_number_
+ << "largest_received: " << LargestReceivedSequenceNumber()
<< " sequence_number: " << sequence_number;
// TODO(satyamshekhar): Make this O(1).
@@ -83,15 +97,30 @@ QuicPacketEntropyHash QuicPacketEntropyManager::SentEntropyHash(
}
void QuicPacketEntropyManager::RecalculateReceivedEntropyHash(
- QuicPacketSequenceNumber sequence_number,
+ QuicPacketSequenceNumber peer_least_unacked,
QuicPacketEntropyHash entropy_hash) {
+ DLOG_IF(WARNING, peer_least_unacked > LargestReceivedSequenceNumber())
+ << "Prematurely updating the entropy manager before registering the "
+ << "entropy of the containing packet creates a temporary inconsistency.";
+ if (peer_least_unacked < largest_received_sequence_number_) {
+ DLOG(INFO) << "Ignoring received peer_least_unacked:" << peer_least_unacked
+ << " less than largest_peer_sequence_number:"
+ << largest_received_sequence_number_;
+ return;
+ }
+ largest_received_sequence_number_ = peer_least_unacked;
received_packets_entropy_hash_ = entropy_hash;
ReceivedEntropyMap::iterator it =
- received_packets_entropy_.lower_bound(sequence_number);
+ received_packets_entropy_.lower_bound(peer_least_unacked);
// TODO(satyamshekhar): Make this O(1).
for (; it != received_packets_entropy_.end(); ++it) {
received_packets_entropy_hash_ ^= it->second;
}
+ // Discard entropies before least unacked.
+ received_packets_entropy_.erase(
+ received_packets_entropy_.begin(),
+ received_packets_entropy_.lower_bound(
+ min(peer_least_unacked, LargestReceivedSequenceNumber())));
}
bool QuicPacketEntropyManager::IsValidEntropy(
@@ -133,13 +162,4 @@ void QuicPacketEntropyManager::ClearSentEntropyBefore(
<< sent_packets_entropy_.begin()->first;
}
-void QuicPacketEntropyManager::ClearReceivedEntropyBefore(
- QuicPacketSequenceNumber sequence_number) {
- // This might clear the received_packets_entropy_ map if the current packet
- // is peer_least_packet_awaiting_ack_ and it doesn't have entropy flag set.
- received_packets_entropy_.erase(
- received_packets_entropy_.begin(),
- received_packets_entropy_.lower_bound(sequence_number));
-}
-
} // namespace net
diff --git a/net/quic/quic_packet_entropy_manager.h b/net/quic/quic_packet_entropy_manager.h
index 5a6c671..fb205a4 100644
--- a/net/quic/quic_packet_entropy_manager.h
+++ b/net/quic/quic_packet_entropy_manager.h
@@ -43,11 +43,13 @@ class NET_EXPORT_PRIVATE QuicPacketEntropyManager :
QuicPacketEntropyHash SentEntropyHash(
QuicPacketSequenceNumber sequence_number) const;
- // Recalculate the received entropy hash since we had some missing packets
- // which the sender won't retransmit again and has sent us the |entropy_hash|
- // for packets up to, but not including, |sequence_number|.
+ QuicPacketSequenceNumber LargestReceivedSequenceNumber() const;
+
+ // Recalculate the received entropy hash and clears old packet entropies,
+ // now that the sender sent us the |entropy_hash| for packets up to,
+ // but not including, |peer_least_unacked|.
void RecalculateReceivedEntropyHash(
- QuicPacketSequenceNumber sequence_number,
+ QuicPacketSequenceNumber peer_least_unacked,
QuicPacketEntropyHash entropy_hash);
// Returns true if |entropy_hash| matches the expected sent entropy hash
@@ -60,10 +62,6 @@ class NET_EXPORT_PRIVATE QuicPacketEntropyManager :
// |sequence_number|.
void ClearSentEntropyBefore(QuicPacketSequenceNumber sequence_number);
- // Removes not required entries from |received_packets_entropy_| before
- // |sequence_number|.
- void ClearReceivedEntropyBefore(QuicPacketSequenceNumber sequence_number);
-
QuicPacketEntropyHash sent_packets_entropy_hash() const {
return sent_packets_entropy_hash_;
}
@@ -79,11 +77,6 @@ class NET_EXPORT_PRIVATE QuicPacketEntropyManager :
typedef std::map<QuicPacketSequenceNumber,
QuicPacketEntropyHash> ReceivedEntropyMap;
- // TODO(satyamshekhar): Can be optimized using an interval set like data
- // structure.
- // Set of received sequence numbers that had the received entropy flag set.
- ReceivedEntropyMap received_packets_entropy_;
-
// Linked hash map from sequence numbers to the sent entropy hash up to the
// sequence number in the key.
SentEntropyMap sent_packets_entropy_;
@@ -91,9 +84,19 @@ class NET_EXPORT_PRIVATE QuicPacketEntropyManager :
// Cumulative hash of entropy of all sent packets.
QuicPacketEntropyHash sent_packets_entropy_hash_;
+ // TODO(satyamshekhar): Can be optimized using an interval set like data
+ // structure.
+ // Map of received sequence numbers to their corresponding entropy.
+ // Every received packet has an entry, and packets without the entropy bit set
+ // have an entropy value of 0.
+ // TODO(ianswett): When the entropy flag is off, the entropy should not be 0.
+ ReceivedEntropyMap received_packets_entropy_;
+
// Cumulative hash of entropy of all received packets.
QuicPacketEntropyHash received_packets_entropy_hash_;
+ // The largest sequence number cleared by RecalculateReceivedEntropyHash.
+ // Received entropy cannot be calculated for numbers less than it.
QuicPacketSequenceNumber largest_received_sequence_number_;
};
diff --git a/net/quic/quic_packet_entropy_manager_test.cc b/net/quic/quic_packet_entropy_manager_test.cc
index 17f4f1e3..0016211 100644
--- a/net/quic/quic_packet_entropy_manager_test.cc
+++ b/net/quic/quic_packet_entropy_manager_test.cc
@@ -51,14 +51,12 @@ TEST_F(QuicPacketEntropyManagerTest, ReceivedPacketEntropyHash) {
TEST_F(QuicPacketEntropyManagerTest, EntropyHashBelowLeastObserved) {
EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(0));
- EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(9));
entropy_manager_.RecordReceivedPacketEntropyHash(4, 5);
EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(3));
};
-TEST_F(QuicPacketEntropyManagerTest, EntropyHashAboveLargesObserved) {
+TEST_F(QuicPacketEntropyManagerTest, EntropyHashAboveLargestObserved) {
EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(0));
- EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(9));
entropy_manager_.RecordReceivedPacketEntropyHash(4, 5);
EXPECT_EQ(0, entropy_manager_.ReceivedEntropyHash(3));
};
@@ -87,6 +85,13 @@ TEST_F(QuicPacketEntropyManagerTest, RecalculateReceivedEntropyHash) {
}
entropy_manager_.RecalculateReceivedEntropyHash(4, 100);
EXPECT_EQ(entropy_hash, entropy_manager_.ReceivedEntropyHash(6));
+
+ // Ensure it doesn't change with an old received sequence number or entropy.
+ entropy_manager_.RecordReceivedPacketEntropyHash(1, 50);
+ EXPECT_EQ(entropy_hash, entropy_manager_.ReceivedEntropyHash(6));
+
+ entropy_manager_.RecalculateReceivedEntropyHash(1, 50);
+ EXPECT_EQ(entropy_hash, entropy_manager_.ReceivedEntropyHash(6));
}
TEST_F(QuicPacketEntropyManagerTest, SentEntropyHash) {
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 5b113b6..4090f4c 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -124,29 +124,55 @@ enum QuicSequenceNumberLength {
PACKET_6BYTE_SEQUENCE_NUMBER = 6
};
+// The public flags are specified in one byte.
enum QuicPacketPublicFlags {
PACKET_PUBLIC_FLAGS_NONE = 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 header guid length in bytes.
+
+ // Bit 0: Does the packet header contains version info?
+ PACKET_PUBLIC_FLAGS_VERSION = 1 << 0,
+
+ // Bit 1: Is this packet a public reset packet?
+ PACKET_PUBLIC_FLAGS_RST = 1 << 1,
+
+ // Bits 2 and 3 specify the length of the GUID as follows:
+ // ----00--: 0 bytes
+ // ----01--: 1 byte
+ // ----10--: 4 bytes
+ // ----11--: 8 bytes
PACKET_PUBLIC_FLAGS_0BYTE_GUID = 0,
PACKET_PUBLIC_FLAGS_1BYTE_GUID = 1 << 2,
PACKET_PUBLIC_FLAGS_4BYTE_GUID = 1 << 3,
PACKET_PUBLIC_FLAGS_8BYTE_GUID = 1 << 3 | 1 << 2,
- // Packet sequence number length in bytes.
+
+ // Bits 4 and 5 describe the packet sequence number length as follows:
+ // --00----: 1 byte
+ // --01----: 2 bytes
+ // --10----: 4 bytes
+ // --11----: 6 bytes
PACKET_PUBLIC_FLAGS_1BYTE_SEQUENCE = 0,
PACKET_PUBLIC_FLAGS_2BYTE_SEQUENCE = 1 << 4,
PACKET_PUBLIC_FLAGS_4BYTE_SEQUENCE = 1 << 5,
PACKET_PUBLIC_FLAGS_6BYTE_SEQUENCE = 1 << 5 | 1 << 4,
- PACKET_PUBLIC_FLAGS_MAX = (1 << 6) - 1 // All bits set.
+
+ // All bits set (bits 6 and 7 are not currently used): 00111111
+ PACKET_PUBLIC_FLAGS_MAX = (1 << 6) - 1
};
+// The private flags are specified in one byte.
enum QuicPacketPrivateFlags {
PACKET_PRIVATE_FLAGS_NONE = 0,
+
+ // Bit 0: Does this packet contain an entropy bit?
PACKET_PRIVATE_FLAGS_ENTROPY = 1 << 0,
- PACKET_PRIVATE_FLAGS_FEC_GROUP = 1 << 1, // Payload is part of an FEC group.
- PACKET_PRIVATE_FLAGS_FEC = 1 << 2, // Payload is FEC as opposed to frames.
- PACKET_PRIVATE_FLAGS_MAX = (1 << 3) - 1 // All bits set.
+
+ // Bit 1: Payload is part of an FEC group?
+ PACKET_PRIVATE_FLAGS_FEC_GROUP = 1 << 1,
+
+ // Bit 2: Payload is FEC as opposed to frames?
+ PACKET_PRIVATE_FLAGS_FEC = 1 << 2,
+
+ // All bits set (bits 3-7 are not currently used): 00000111
+ PACKET_PRIVATE_FLAGS_MAX = (1 << 3) - 1
};
// Size in bytes of the data or fec packet header.
@@ -463,7 +489,7 @@ struct NET_EXPORT_PRIVATE QuicAckFrame {
};
// Defines for all types of congestion feedback that will be negotiated in QUIC,
-// kTCP MUST be supported by all QUIC implementations to guarentee 100%
+// kTCP MUST be supported by all QUIC implementations to guarantee 100%
// compatibility.
enum CongestionFeedbackType {
kTCP, // Used to mimic TCP.
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index 6027c3c..dc5c160 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -99,7 +99,7 @@ TEST_F(ReliableQuicStreamTest, WriteAllData) {
connection_->options()->max_packet_length =
1 + QuicPacketCreator::StreamFramePacketOverhead(
- 1, PACKET_8BYTE_GUID, !kIncludeVersion,
+ PACKET_8BYTE_GUID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
// TODO(rch): figure out how to get StrEq working here.
//EXPECT_CALL(*session_, WriteData(kStreamId, StrEq(kData1), _, _)).WillOnce(
@@ -167,7 +167,7 @@ TEST_F(ReliableQuicStreamTest, WriteData) {
EXPECT_TRUE(write_blocked_list_->IsEmpty());
connection_->options()->max_packet_length =
1 + QuicPacketCreator::StreamFramePacketOverhead(
- 1, PACKET_8BYTE_GUID, !kIncludeVersion,
+ PACKET_8BYTE_GUID, !kIncludeVersion,
PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP);
// TODO(rch): figure out how to get StrEq working here.
//EXPECT_CALL(*session_, WriteData(_, StrEq(kData1), _, _)).WillOnce(
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index 73b5bab..08ced13 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -8,6 +8,7 @@
#include "net/quic/crypto/common_cert_set.h"
#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/crypto_server_config.h"
+#include "net/quic/crypto/proof_source_chromium.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/crypto/quic_random.h"
@@ -501,5 +502,10 @@ CryptoHandshakeMessage CryptoTestUtils::BuildMessage(const char* message_tag,
return *parsed;
}
+// static
+ProofSource* CryptoTestUtils::ProofSourceForTesting() {
+ return new ProofSourceChromium();
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index a8c67f7..809f28a 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -382,21 +382,25 @@ QuicPacket* ConstructHandshakePacket(QuicGuid guid, QuicTag tag) {
}
size_t GetPacketLengthForOneStream(
- bool include_version, InFecGroup is_in_fec_group, size_t payload) {
- // TODO(wtc): the hardcoded use of NullEncrypter here seems wrong.
- size_t packet_length = NullEncrypter().GetCiphertextSize(payload) +
+ bool include_version, InFecGroup is_in_fec_group, size_t* payload_length) {
+ *payload_length = 1;
+ const size_t stream_length =
+ NullEncrypter().GetCiphertextSize(*payload_length) +
QuicPacketCreator::StreamFramePacketOverhead(
- 1, PACKET_8BYTE_GUID, include_version,
+ PACKET_8BYTE_GUID, include_version,
PACKET_6BYTE_SEQUENCE_NUMBER, is_in_fec_group);
-
- size_t ack_length = NullEncrypter().GetCiphertextSize(
+ const size_t ack_length = NullEncrypter().GetCiphertextSize(
QuicFramer::GetMinAckFrameSize()) +
GetPacketHeaderSize(PACKET_8BYTE_GUID, include_version,
PACKET_6BYTE_SEQUENCE_NUMBER, is_in_fec_group);
- // Make sure that if we change the size of the packet length for one stream
- // or the ack frame; that all our test are configured correctly.
- DCHECK_GE(packet_length, ack_length);
- return packet_length;
+ if (stream_length < ack_length) {
+ *payload_length = 1 + ack_length - stream_length;
+ }
+
+ return NullEncrypter().GetCiphertextSize(*payload_length) +
+ QuicPacketCreator::StreamFramePacketOverhead(
+ PACKET_8BYTE_GUID, include_version,
+ PACKET_6BYTE_SEQUENCE_NUMBER, is_in_fec_group);
}
QuicPacketEntropyHash TestEntropyCalculator::ReceivedEntropyHash(
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index e694982..d67fb9c 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -35,10 +35,11 @@ void CompareQuicDataWithHexError(const std::string& description,
QuicData* actual,
QuicData* expected);
-// Returns the length of the QuicPacket that will be created if it contains
-// a stream frame that has |payload| bytes.
+// Returns the length of a QuicPacket that is capable of holding either a
+// stream frame or a minimal ack frame. Sets |*payload_length| to the number
+// of bytes of stream data that will fit in such a packet.
size_t GetPacketLengthForOneStream(
- bool include_version, InFecGroup is_in_fec_group, size_t payload);
+ bool include_version, InFecGroup is_in_fec_group, size_t* payload_length);
string SerializeUncompressedHeaders(const SpdyHeaderBlock& headers);