diff options
author | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-05 20:57:30 +0000 |
---|---|---|
committer | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-05 20:57:30 +0000 |
commit | f62262b8eb43c6a4ff8298bbf685924ba3292eab (patch) | |
tree | 44b99c48e9f51746890ba6fb46d0051adb16e3f5 /net/quic | |
parent | f666276a1c9df0bab723c76bb25288df87c46f06 (diff) | |
download | chromium_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.cc | 2 | ||||
-rw-r--r-- | net/quic/crypto/crypto_server_test.cc | 103 | ||||
-rw-r--r-- | net/quic/crypto/proof_source.h | 5 | ||||
-rw-r--r-- | net/quic/crypto/proof_source_chromium.cc | 22 | ||||
-rw-r--r-- | net/quic/crypto/proof_source_chromium.h | 37 | ||||
-rw-r--r-- | net/quic/quic_connection.cc | 19 | ||||
-rw-r--r-- | net/quic/quic_connection.h | 6 | ||||
-rw-r--r-- | net/quic/quic_connection_test.cc | 38 | ||||
-rw-r--r-- | net/quic/quic_framer.cc | 34 | ||||
-rw-r--r-- | net/quic/quic_framer.h | 10 | ||||
-rw-r--r-- | net/quic/quic_packet_creator.cc | 21 | ||||
-rw-r--r-- | net/quic/quic_packet_creator.h | 3 | ||||
-rw-r--r-- | net/quic/quic_packet_creator_test.cc | 13 | ||||
-rw-r--r-- | net/quic/quic_packet_entropy_manager.cc | 52 | ||||
-rw-r--r-- | net/quic/quic_packet_entropy_manager.h | 29 | ||||
-rw-r--r-- | net/quic/quic_packet_entropy_manager_test.cc | 11 | ||||
-rw-r--r-- | net/quic/quic_protocol.h | 44 | ||||
-rw-r--r-- | net/quic/reliable_quic_stream_test.cc | 4 | ||||
-rw-r--r-- | net/quic/test_tools/crypto_test_utils.cc | 6 | ||||
-rw-r--r-- | net/quic/test_tools/quic_test_utils.cc | 24 | ||||
-rw-r--r-- | net/quic/test_tools/quic_test_utils.h | 7 |
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); |