diff options
author | jokulik <jokulik@chromium.org> | 2016-03-24 15:35:30 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-24 22:37:10 +0000 |
commit | f2bd55c5ab99300b7df0a97b3d0ef16c9a2e584a (patch) | |
tree | a075e02a5d98fce698e53b975674271b17673b3b /net | |
parent | ef26d8f77ba056704780199893f1ebaf518136de (diff) | |
download | chromium_src-f2bd55c5ab99300b7df0a97b3d0ef16c9a2e584a.zip chromium_src-f2bd55c5ab99300b7df0a97b3d0ef16c9a2e584a.tar.gz chromium_src-f2bd55c5ab99300b7df0a97b3d0ef16c9a2e584a.tar.bz2 |
Landing Recent QUIC changes until 3/18/2016 23:30 UTC
relnote: Add a QUIC end to end test of huge post.
The test code has been added but is currently disabled, due to
net_unittest timeout issues.
Merge internal change: 117596033
https://codereview.chromium.org/1830253002/
relnote: Do not read rejected packet number in PUBLIC RESET packet.
Merge internal change: 117595846
https://codereview.chromium.org/1834683002/
relnote: Trailers are now parsed and stored in QuicSpdyStream.
Moved the TrailersWithoutOffset test to the parent QuicSpdyStreamTest.
Deleted the ReceiveTrailersBeforeHeaders test entirely as it doesn't test useful behavior: it calls OnTrailingHeadersComplete directly but this is only ever called from within QuicSpdyStream (and subclasses).
Switch to the new WriteOrBufferBody method.
Merge internal change: 117582133
https://codereview.chromium.org/1832513004/
relnote: Move QuicSpdyClientStream::SendBody to QuicSpdyStream::WriteBody.
Merge internal change: 117577200
https://codereview.chromium.org/1830043004/
relnote: Make ShouldCreate{Incoming,Outgoing}DynamicStream abstract methods in QuicSpdySession. No behavior change.
Merge internal change: 117574127
https://codereview.chromium.org/1828123003/
relnote: Correctly set cmsg space for timestamping. Additionally, guard against future cmsg overflows. Not flag protected.
The previous calculation for the cmsg space was too small by 8B.
Merge internal change: 117568981
https://codereview.chromium.org/1828953002/
relnote: Creating a basic QUIC packet dumper
Adding newlines to any logged quic frames
Merge internal change: 117543172
https://codereview.chromium.org/1834593002/
relnote: Rename StreamSequencerBuffer to QuicStreamSequencerBuffer to bring it in line with other classes in //gfe/quic. No behavior change.
Merge internal change: 117487896
https://codereview.chromium.org/1831723002/
relnote: Rename QuicSpdyStream::response_trailers_ to received_trailers_. No behavior change.
QuicSpdyStream is used by servers and clients, received
trailers could be request trailers.
Merge internal change: 117483696
https://codereview.chromium.org/1822763002/
relnote: Introduces a QUIC_OVERLAPPING_STREAM_DATA error code, sent when receiving a stream frame containing data that overlaps with buffered data.
Renames QUIC_INVALID_STREAM_FRAME to QUIC_EMPTY_STREAM_FRAME_NO_FIN
Dan pointed out that QUIC_INVALID_STREAM_DATA is also used in the framer, making debugging the sequencer specific errors harder. Also the description of QUIC_INVALID_STREAM_DATA is that "STREAM frame data is malformed." which I don't think is true here: it's not malformed, it's just overlapping.
Merge internal change: 117452324
https://codereview.chromium.org/1830063002/
relnote: Close QUIC connection if any error occurs in QuicStreamSequencerBuffer::OnStreamData. Flag protected behind default enabled --flag_quic_consolidate_onstreamframe_errors
Flag protecting out of paranoia: new behavior is that if ever hit the QUIC_INTERNAL_ERROR branch in OnStreamData then we will now close the connection, whereas we did not before. Additionally a stream frame containing data which overlaps with existing data will now result in QUIC_INVALID_STREAM_DATA being sent on close, instead of QUIC_INVALID_STREAM_FRAME.
Merge internal change: 117446575
https://codereview.chromium.org/1830773002/
relnote: Use SO_TIMESTAMPING for received packet timestamps. Guarded by flag_quic_use_socket_timestamp.
This corrects the RTT for extremely low RTT connections (i.e. RTT < EpollServer
iteration duration). This manifests as a ~1.5Gbps improvement in egress at 100%
GFE CPU in the ustreamer load test, which while not indicative of reality, does
bring it closer to the TCP+SSL load test behavior. In practice, this really
just manages to reduce the number of calls to EpollServer::Now().
This is part of a broader set of changes to enable PACKET_RX_RING and all of
the capabilities it provides, notably PACKET_TIMESTAMPING.
Additionally, in QuicPacketReader's plain recvmsg path, ensure the returned
server IP is valid as is done in the recvmmsg path.
Merge internal change: 117434383
https://codereview.chromium.org/1828863002/
relnote: Remove QuicStreamSequencerBufferInterface that only has a single implementation. No behavior change.
Merge internal change: 117397110
https://codereview.chromium.org/1823803003/
relnote: Report no client nonce as INCHOATE_HELLO_FAILURE.
Merge internal change: 117371001
https://codereview.chromium.org/1820383002/
relnote: Add and plumb QuicReceivedPacket in the packet reception path. Optionally use its timestamp, guarded by gfe2_restart_flag_quic_use_socket_timestamp.
This is part of a broader set of changes to enable socket-level timestamping
and to enable PACKET_RX_RING with all of the capabilities it provides.
Merge internal change: 117362867
https://codereview.chromium.org/1821843003/
relnote: Add QUIC 32 in which FEC related fields are removed from private flags and revived packet list are removed from ACK frame.
Merge internal change: 117278937
https://codereview.chromium.org/1817223002/
relnote: rename QuicSpdyClientStream::headers to response_headers
Merge internal change: 117272106
https://codereview.chromium.org/1822763002/
R=rch@chromium.org
BUG=
Review URL: https://codereview.chromium.org/1832953002
Cr-Commit-Position: refs/heads/master@{#383171}
Diffstat (limited to 'net')
73 files changed, 1610 insertions, 535 deletions
diff --git a/net/net.gypi b/net/net.gypi index 5b48ac9..a224d4b 100644 --- a/net/net.gypi +++ b/net/net.gypi @@ -398,6 +398,8 @@ 'quic/quic_socket_address_coder.h', 'quic/quic_stream_sequencer.cc', 'quic/quic_stream_sequencer.h', + 'quic/quic_stream_sequencer_buffer.cc', + 'quic/quic_stream_sequencer_buffer.h', 'quic/quic_stream_sequencer_buffer_interface.h', 'quic/quic_sustained_bandwidth_recorder.cc', 'quic/quic_sustained_bandwidth_recorder.h', @@ -414,8 +416,6 @@ 'quic/quic_write_blocked_list.h', 'quic/reliable_quic_stream.cc', 'quic/reliable_quic_stream.h', - 'quic/stream_sequencer_buffer.cc', - 'quic/stream_sequencer_buffer.h', ], 'net_non_nacl_sources': [ 'android/cert_verify_result_android.cc', @@ -1659,7 +1659,7 @@ 'quic/quic_write_blocked_list_test.cc', 'quic/reliable_quic_stream_test.cc', 'quic/spdy_utils_test.cc', - 'quic/stream_sequencer_buffer_test.cc', + 'quic/quic_stream_sequencer_buffer_test.cc', 'quic/test_tools/crypto_test_utils.cc', 'quic/test_tools/crypto_test_utils.h', 'quic/test_tools/crypto_test_utils_chromium.cc', diff --git a/net/quic/bidirectional_stream_quic_impl_unittest.cc b/net/quic/bidirectional_stream_quic_impl_unittest.cc index b394ed8..3b8847c 100644 --- a/net/quic/bidirectional_stream_quic_impl_unittest.cc +++ b/net/quic/bidirectional_stream_quic_impl_unittest.cc @@ -265,11 +265,11 @@ class BidirectionalStreamQuicImplTest // Holds a packet to be written to the wire, and the IO mode that should // be used by the mock socket when performing the write. struct PacketToWrite { - PacketToWrite(IoMode mode, QuicEncryptedPacket* packet) + PacketToWrite(IoMode mode, QuicReceivedPacket* packet) : mode(mode), packet(packet) {} PacketToWrite(IoMode mode, int rv) : mode(mode), packet(nullptr), rv(rv) {} IoMode mode; - QuicEncryptedPacket* packet; + QuicReceivedPacket* packet; int rv; }; @@ -300,11 +300,11 @@ class BidirectionalStreamQuicImplTest } // Adds a packet to the list of expected writes. - void AddWrite(scoped_ptr<QuicEncryptedPacket> packet) { + void AddWrite(scoped_ptr<QuicReceivedPacket> packet) { writes_.push_back(PacketToWrite(SYNCHRONOUS, packet.release())); } - void ProcessPacket(scoped_ptr<QuicEncryptedPacket> packet) { + void ProcessPacket(scoped_ptr<QuicReceivedPacket> packet) { connection_->ProcessUdpPacket(self_addr_, peer_addr_, *packet); } @@ -361,20 +361,20 @@ class BidirectionalStreamQuicImplTest return maker_.GetResponseHeaders(response_code); } - scoped_ptr<QuicEncryptedPacket> ConstructDataPacket( + scoped_ptr<QuicReceivedPacket> ConstructDataPacket( QuicPacketNumber packet_number, bool should_include_version, bool fin, QuicStreamOffset offset, base::StringPiece data) { - scoped_ptr<QuicEncryptedPacket> packet(maker_.MakeDataPacket( + scoped_ptr<QuicReceivedPacket> packet(maker_.MakeDataPacket( packet_number, stream_id_, should_include_version, fin, offset, data)); DVLOG(2) << "packet(" << packet_number << "): " << std::endl << QuicUtils::StringToHexASCIIDump(packet->AsStringPiece()); return packet; } - scoped_ptr<QuicEncryptedPacket> ConstructRequestHeadersPacket( + scoped_ptr<QuicReceivedPacket> ConstructRequestHeadersPacket( QuicPacketNumber packet_number, bool fin, RequestPriority request_priority, @@ -386,7 +386,7 @@ class BidirectionalStreamQuicImplTest request_headers_, spdy_headers_frame_length); } - scoped_ptr<QuicEncryptedPacket> ConstructResponseHeadersPacket( + scoped_ptr<QuicReceivedPacket> ConstructResponseHeadersPacket( QuicPacketNumber packet_number, bool fin, const SpdyHeaderBlock& response_headers, @@ -397,7 +397,7 @@ class BidirectionalStreamQuicImplTest spdy_headers_frame_length, offset); } - scoped_ptr<QuicEncryptedPacket> ConstructResponseTrailersPacket( + scoped_ptr<QuicReceivedPacket> ConstructResponseTrailersPacket( QuicPacketNumber packet_number, bool fin, const SpdyHeaderBlock& trailers, @@ -408,15 +408,15 @@ class BidirectionalStreamQuicImplTest spdy_headers_frame_length, offset); } - scoped_ptr<QuicEncryptedPacket> ConstructRstStreamPacket( + scoped_ptr<QuicReceivedPacket> ConstructRstStreamPacket( QuicPacketNumber packet_number) { return ConstructRstStreamCancelledPacket(packet_number, 0); } - scoped_ptr<QuicEncryptedPacket> ConstructRstStreamCancelledPacket( + scoped_ptr<QuicReceivedPacket> ConstructRstStreamCancelledPacket( QuicPacketNumber packet_number, size_t bytes_written) { - scoped_ptr<QuicEncryptedPacket> packet( + scoped_ptr<QuicReceivedPacket> packet( maker_.MakeRstPacket(packet_number, !kIncludeVersion, stream_id_, QUIC_STREAM_CANCELLED, bytes_written)); DVLOG(2) << "packet(" << packet_number << "): " << std::endl @@ -424,7 +424,7 @@ class BidirectionalStreamQuicImplTest return packet; } - scoped_ptr<QuicEncryptedPacket> ConstructAckAndRstStreamPacket( + scoped_ptr<QuicReceivedPacket> ConstructAckAndRstStreamPacket( QuicPacketNumber packet_number, QuicPacketNumber largest_received, QuicPacketNumber ack_least_unacked, @@ -435,7 +435,7 @@ class BidirectionalStreamQuicImplTest !kIncludeCongestionFeedback); } - scoped_ptr<QuicEncryptedPacket> ConstructAckAndDataPacket( + scoped_ptr<QuicReceivedPacket> ConstructAckAndDataPacket( QuicPacketNumber packet_number, bool should_include_version, QuicPacketNumber largest_received, @@ -443,7 +443,7 @@ class BidirectionalStreamQuicImplTest bool fin, QuicStreamOffset offset, base::StringPiece data) { - scoped_ptr<QuicEncryptedPacket> packet(maker_.MakeAckAndDataPacket( + scoped_ptr<QuicReceivedPacket> packet(maker_.MakeAckAndDataPacket( packet_number, should_include_version, stream_id_, largest_received, least_unacked, fin, offset, data)); DVLOG(2) << "packet(" << packet_number << "): " << std::endl @@ -451,7 +451,7 @@ class BidirectionalStreamQuicImplTest return packet; } - scoped_ptr<QuicEncryptedPacket> ConstructAckPacket( + scoped_ptr<QuicReceivedPacket> ConstructAckPacket( QuicPacketNumber packet_number, QuicPacketNumber largest_received, QuicPacketNumber least_unacked) { diff --git a/net/quic/crypto/crypto_server_test.cc b/net/quic/crypto/crypto_server_test.cc index c65927a..8fc3689 100644 --- a/net/quic/crypto/crypto_server_test.cc +++ b/net/quic/crypto/crypto_server_test.cc @@ -633,6 +633,42 @@ TEST_P(CryptoServerTest, BadClientNonce) { } } +TEST_P(CryptoServerTest, NoClientNonce) { + // No client nonces should result in INCHOATE_HELLO_FAILURE. + // clang-format off + CryptoHandshakeMessage msg = CryptoTestUtils::Message( + "CHLO", + "VER\0", client_version_string_.c_str(), + "$padding", static_cast<int>(kClientHelloMinimumSize), + nullptr); + // clang-format on + + ShouldSucceed(msg); + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); + + // clang-format off + CryptoHandshakeMessage msg1 = CryptoTestUtils::Message( + "CHLO", + "AEAD", "AESG", + "KEXS", "C255", + "SCID", scid_hex_.c_str(), + "#004b5453", srct_hex_.c_str(), + "PUBS", pub_hex_.c_str(), + "XLCT", XlctHexString().c_str(), + "VER\0", client_version_string_.c_str(), + "$padding", static_cast<int>(kClientHelloMinimumSize), + nullptr); + // clang-format on + + ShouldSucceed(msg1); + CheckRejectTag(); + const HandshakeFailureReason kRejectReasons1[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons1, arraysize(kRejectReasons1)); +} + TEST_P(CryptoServerTest, DowngradeAttack) { if (supported_versions_.size() == 1) { // No downgrade attack is possible if the server only supports one version. @@ -745,7 +781,7 @@ TEST_P(CryptoServerTest, CorruptMultipleTags) { ShouldSucceed(msg); CheckRejectTag(); - if (client_version_ <= QUIC_VERSION_31) { + if (client_version_ <= QUIC_VERSION_32) { const HandshakeFailureReason kRejectReasons[] = { SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE, SERVER_NONCE_DECRYPTION_FAILURE}; diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc index c6d32e5..6378de9 100644 --- a/net/quic/crypto/quic_crypto_server_config.cc +++ b/net/quic/crypto/quic_crypto_server_config.cc @@ -1031,6 +1031,13 @@ void QuicCryptoServerConfig::EvaluateClientHello( return; } + if (!client_hello.GetStringPiece(kNONC, &info->client_nonce)) { + info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE); + // Report no client nonce as INCHOATE_HELLO_FAILURE. + helper.ValidationComplete(QUIC_NO_ERROR, ""); + return; + } + bool found_error = false; if (source_address_token_error != HANDSHAKE_OK) { info->reject_reasons.push_back(source_address_token_error); @@ -1063,8 +1070,7 @@ void QuicCryptoServerConfig::EvaluateClientHello( } } - if (!client_hello.GetStringPiece(kNONC, &info->client_nonce) || - info->client_nonce.size() != kNonceSize) { + if (info->client_nonce.size() != kNonceSize) { info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE); // Invalid client nonce. LOG(ERROR) << "Invalid client nonce: " << client_hello.DebugString(); @@ -1079,8 +1085,8 @@ void QuicCryptoServerConfig::EvaluateClientHello( // Server nonce is optional, and used for key derivation if present. client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce); - if (version > QUIC_VERSION_31) { - DVLOG(1) << "No 0-RTT replay protection in QUIC_VERSION_32 and higher."; + if (version > QUIC_VERSION_32) { + DVLOG(1) << "No 0-RTT replay protection in QUIC_VERSION_33 and higher."; // If the server nonce is empty and we're requiring handshake confirmation // for DoS reasons then we must reject the CHLO. if (FLAGS_quic_require_handshake_confirmation && diff --git a/net/quic/p2p/quic_p2p_session.cc b/net/quic/p2p/quic_p2p_session.cc index 6bd17d6..f165bf7 100644 --- a/net/quic/p2p/quic_p2p_session.cc +++ b/net/quic/p2p/quic_p2p_session.cc @@ -124,7 +124,7 @@ int QuicP2PSession::DoReadComplete(int result) { return result; } - QuicEncryptedPacket packet(read_buffer_->data(), result); + QuicReceivedPacket packet(read_buffer_->data(), result, clock_.Now()); connection()->ProcessUdpPacket(connection()->self_address(), connection()->peer_address(), packet); return OK; diff --git a/net/quic/p2p/quic_p2p_session.h b/net/quic/p2p/quic_p2p_session.h index 734b6e59..1f821d3 100644 --- a/net/quic/p2p/quic_p2p_session.h +++ b/net/quic/p2p/quic_p2p_session.h @@ -10,6 +10,7 @@ #include "base/strings/string_piece.h" #include "net/quic/p2p/quic_p2p_stream.h" #include "net/quic/quic_client_session_base.h" +#include "net/quic/quic_clock.h" #include "net/quic/quic_protocol.h" namespace net { @@ -82,6 +83,9 @@ class NET_EXPORT QuicP2PSession : public QuicSession { ReadState read_state_ = READ_STATE_DO_READ; scoped_refptr<IOBuffer> read_buffer_; + // For recording receipt time + QuicClock clock_; + DISALLOW_COPY_AND_ASSIGN(QuicP2PSession); }; diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc index 08145fc..0f018bb 100644 --- a/net/quic/quic_chromium_client_session.cc +++ b/net/quic/quic_chromium_client_session.cc @@ -655,24 +655,32 @@ bool QuicChromiumClientSession::CanPool(const std::string& hostname, server_id_.host(), hostname); } -QuicChromiumClientStream* -QuicChromiumClientSession::CreateIncomingDynamicStream(QuicStreamId id) { +bool QuicChromiumClientSession::ShouldCreateIncomingDynamicStream( + QuicStreamId id) { if (!connection()->connected()) { LOG(DFATAL) << "ShouldCreateIncomingDynamicStream called when disconnected"; - return nullptr; + return false; } if (goaway_received()) { - DVLOG(1) << "Failed to create a new outgoing stream. " + DVLOG(1) << "Cannot create a new outgoing stream. " << "Already received goaway."; - return nullptr; + return false; } if (going_away_) { - return nullptr; + return false; } if (id % 2 != 0) { LOG(WARNING) << "Received invalid push stream id " << id; connection()->SendConnectionCloseWithDetails( QUIC_INVALID_STREAM_ID, "Server created odd numbered stream"); + return false; + } + return true; +} + +QuicChromiumClientStream* +QuicChromiumClientSession::CreateIncomingDynamicStream(QuicStreamId id) { + if (!ShouldCreateIncomingDynamicStream(id)) { return nullptr; } return CreateIncomingReliableStreamImpl(id); @@ -1056,7 +1064,7 @@ void QuicChromiumClientSession::OnReadError( NotifyFactoryOfSessionClosedLater(); } -bool QuicChromiumClientSession::OnPacket(const QuicEncryptedPacket& packet, +bool QuicChromiumClientSession::OnPacket(const QuicReceivedPacket& packet, IPEndPoint local_address, IPEndPoint peer_address) { ProcessUdpPacket(local_address, peer_address, packet); diff --git a/net/quic/quic_chromium_client_session.h b/net/quic/quic_chromium_client_session.h index 4f100c9..1d587e1 100644 --- a/net/quic/quic_chromium_client_session.h +++ b/net/quic/quic_chromium_client_session.h @@ -158,7 +158,6 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession // QuicSession methods: void OnStreamFrame(const QuicStreamFrame& frame) override; - bool ShouldCreateOutgoingDynamicStream(); QuicChromiumClientStream* CreateOutgoingDynamicStream( SpdyPriority priority) override; QuicCryptoClientStream* GetCryptoStream() override; @@ -187,7 +186,7 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession // QuicChromiumPacketReader::Visitor methods: void OnReadError(int result, const DatagramClientSocket* socket) override; - bool OnPacket(const QuicEncryptedPacket& packet, + bool OnPacket(const QuicReceivedPacket& packet, IPEndPoint local_address, IPEndPoint peer_address) override; @@ -270,6 +269,9 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession protected: // QuicSession methods: + bool ShouldCreateIncomingDynamicStream(QuicStreamId id) override; + bool ShouldCreateOutgoingDynamicStream() override; + QuicChromiumClientStream* CreateIncomingDynamicStream( QuicStreamId id) override; diff --git a/net/quic/quic_chromium_client_stream.cc b/net/quic/quic_chromium_client_stream.cc index 5d9946c..06ec942 100644 --- a/net/quic/quic_chromium_client_stream.cc +++ b/net/quic/quic_chromium_client_stream.cc @@ -40,7 +40,7 @@ void QuicChromiumClientStream::OnStreamHeadersComplete(bool fin, if (decompressed_headers().empty() && !decompressed_trailers().empty()) { DCHECK(trailers_decompressed()); // The delegate will read the trailers via a posted task. - NotifyDelegateOfHeadersCompleteLater(response_trailers(), frame_len); + NotifyDelegateOfHeadersCompleteLater(received_trailers(), frame_len); } else { DCHECK(!headers_delivered_); SpdyHeaderBlock headers; diff --git a/net/quic/quic_chromium_client_stream_test.cc b/net/quic/quic_chromium_client_stream_test.cc index 4e9e2bc..275ed48 100644 --- a/net/quic/quic_chromium_client_stream_test.cc +++ b/net/quic/quic_chromium_client_stream_test.cc @@ -112,6 +112,10 @@ class MockQuicClientSessionBase : public QuicClientSessionBase { const ProofVerifyDetails& verify_details) override {} bool IsAuthorized(const std::string& hostname) override { return true; } + protected: + MOCK_METHOD1(ShouldCreateIncomingDynamicStream, bool(QuicStreamId id)); + MOCK_METHOD0(ShouldCreateOutgoingDynamicStream, bool()); + private: scoped_ptr<QuicCryptoStream> crypto_stream_; diff --git a/net/quic/quic_chromium_packet_reader.cc b/net/quic/quic_chromium_packet_reader.cc index ac45510..4a57ecb 100644 --- a/net/quic/quic_chromium_packet_reader.cc +++ b/net/quic/quic_chromium_packet_reader.cc @@ -77,7 +77,7 @@ void QuicChromiumPacketReader::OnReadComplete(int result) { return; } - QuicEncryptedPacket packet(read_buffer_->data(), result); + QuicReceivedPacket packet(read_buffer_->data(), result, clock_->Now()); IPEndPoint local_address; IPEndPoint peer_address; socket_->GetLocalAddress(&local_address); diff --git a/net/quic/quic_chromium_packet_reader.h b/net/quic/quic_chromium_packet_reader.h index e3e708c..1f0aaed 100644 --- a/net/quic/quic_chromium_packet_reader.h +++ b/net/quic/quic_chromium_packet_reader.h @@ -32,7 +32,7 @@ class NET_EXPORT_PRIVATE QuicChromiumPacketReader { virtual ~Visitor(){}; virtual void OnReadError(int result, const DatagramClientSocket* socket) = 0; - virtual bool OnPacket(const QuicEncryptedPacket& packet, + virtual bool OnPacket(const QuicReceivedPacket& packet, IPEndPoint local_address, IPEndPoint peer_address) = 0; }; diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 7dea3ee..f2d5607 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc @@ -1202,7 +1202,7 @@ const QuicConnectionStats& QuicConnection::GetStats() { void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address, const IPEndPoint& peer_address, - const QuicEncryptedPacket& packet) { + const QuicReceivedPacket& packet) { if (!connected_) { return; } @@ -1224,6 +1224,12 @@ void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address, stats_.bytes_received += packet.length(); ++stats_.packets_received; + if (FLAGS_quic_use_socket_timestamp) { + time_of_last_received_packet_ = packet.receipt_time(); + DVLOG(1) << ENDPOINT << "time of last received packet: " + << time_of_last_received_packet_.ToDebuggingValue(); + } + ScopedRetransmissionScheduler alarm_delayer(this); if (!framer_.ProcessPacket(packet)) { // If we are unable to decrypt this packet, it might be @@ -1353,9 +1359,11 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { DCHECK_EQ(NEGOTIATED_VERSION, version_negotiation_state_); - time_of_last_received_packet_ = clock_->Now(); - DVLOG(1) << ENDPOINT << "time of last received packet: " - << time_of_last_received_packet_.ToDebuggingValue(); + if (!FLAGS_quic_use_socket_timestamp) { + time_of_last_received_packet_ = clock_->Now(); + DVLOG(1) << ENDPOINT << "time of last received packet: " + << time_of_last_received_packet_.ToDebuggingValue(); + } if (last_size_ > largest_received_packet_size_) { largest_received_packet_size_ = last_size_; diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index 169145e..0127c49 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h @@ -392,7 +392,7 @@ class NET_EXPORT_PRIVATE QuicConnection // than that of this connection. virtual void ProcessUdpPacket(const IPEndPoint& self_address, const IPEndPoint& peer_address, - const QuicEncryptedPacket& packet); + const QuicReceivedPacket& packet); // QuicBlockedWriterInterface // Called when the underlying connection becomes writable to allow queued diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index 95cbeb3..329da5b 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc @@ -750,8 +750,8 @@ class QuicConnectionTest : public ::testing::TestWithParam<TestParams> { buffer, kMaxPacketSize); connection_.ProcessUdpPacket( self_address, peer_address, - QuicEncryptedPacket(serialized_packet.encrypted_buffer, - serialized_packet.encrypted_length)); + QuicReceivedPacket(serialized_packet.encrypted_buffer, + serialized_packet.encrypted_length, clock_.Now())); if (connection_.GetSendAlarm()->IsSet()) { connection_.GetSendAlarm()->Fire(); } @@ -778,7 +778,7 @@ class QuicConnectionTest : public ::testing::TestWithParam<TestParams> { level, path_id, number, *packet, buffer, kMaxPacketSize); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, - QuicEncryptedPacket(buffer, encrypted_length, false)); + QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); return base::checked_cast<QuicPacketEntropyHash>(encrypted_length); } @@ -801,7 +801,7 @@ class QuicConnectionTest : public ::testing::TestWithParam<TestParams> { level, path_id, number, *packet, buffer, kMaxPacketSize); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, - QuicEncryptedPacket(buffer, encrypted_length, false)); + QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); if (connection_.GetSendAlarm()->IsSet()) { connection_.GetSendAlarm()->Fire(); } @@ -815,7 +815,7 @@ class QuicConnectionTest : public ::testing::TestWithParam<TestParams> { ENCRYPTION_NONE, path_id, number, *packet, buffer, kMaxPacketSize); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, - QuicEncryptedPacket(buffer, encrypted_length, false)); + QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); } QuicByteCount SendStreamDataToPeer(QuicStreamId id, @@ -1102,7 +1102,7 @@ TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSize) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, - QuicEncryptedPacket(buffer, encrypted_length, false)); + QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); EXPECT_EQ(kMaxPacketSize, connection_.max_packet_length()); } @@ -1136,7 +1136,7 @@ TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSizeWhileWriterLimited) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, - QuicEncryptedPacket(buffer, encrypted_length, false)); + QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); // Here, the limit imposed by the writer is lower than the size of the packet // received, so the writer max packet size is used. @@ -3916,9 +3916,11 @@ TEST_P(QuicConnectionTest, PublicReset) { header.rejected_packet_number = 10101; scoped_ptr<QuicEncryptedPacket> packet( framer_.BuildPublicResetPacket(header)); + scoped_ptr<QuicReceivedPacket> received( + ConstructReceivedPacket(*packet, QuicTime::Zero())); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PUBLIC_RESET, ConnectionCloseSource::FROM_PEER)); - connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *packet); + connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received); } TEST_P(QuicConnectionTest, GoAway) { @@ -3963,7 +3965,7 @@ TEST_P(QuicConnectionTest, PathClose) { TEST_P(QuicConnectionTest, ZeroBytePacket) { // Don't close the connection for zero byte packets. EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0); - QuicEncryptedPacket encrypted(nullptr, 0); + QuicReceivedPacket encrypted(nullptr, 0, QuicTime::Zero()); connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, encrypted); } @@ -4074,7 +4076,7 @@ TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacket) { connection_.set_perspective(Perspective::IS_SERVER); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, - QuicEncryptedPacket(buffer, encrypted_length, false)); + QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); EXPECT_TRUE(writer_->version_negotiation_packet() != nullptr); size_t num_versions = arraysize(kSupportedQuicVersions); @@ -4110,7 +4112,7 @@ TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) { BlockOnNextWrite(); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, - QuicEncryptedPacket(buffer, encrypted_length, false)); + QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); EXPECT_EQ(0u, writer_->last_packet_size()); EXPECT_TRUE(connection_.HasQueuedData()); @@ -4153,7 +4155,7 @@ TEST_P(QuicConnectionTest, writer_->set_is_write_blocked_data_buffered(true); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, - QuicEncryptedPacket(buffer, encryped_length, false)); + QuicReceivedPacket(buffer, encryped_length, QuicTime::Zero(), false)); EXPECT_EQ(0u, writer_->last_packet_size()); EXPECT_FALSE(connection_.HasQueuedData()); } @@ -4167,7 +4169,9 @@ TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) { scoped_ptr<QuicEncryptedPacket> encrypted( framer_.BuildVersionNegotiationPacket(connection_id_, QuicSupportedVersions())); - connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *encrypted); + scoped_ptr<QuicReceivedPacket> received( + ConstructReceivedPacket(*encrypted, QuicTime::Zero())); + connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received); // Now force another packet. The connection should transition into // NEGOTIATED_VERSION state and tell the packet creator to StopSendingVersion. @@ -4187,7 +4191,7 @@ TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, - QuicEncryptedPacket(buffer, encrypted_length, false)); + QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); ASSERT_FALSE(QuicPacketCreatorPeer::SendVersionInPacket(creator_)); } @@ -4201,7 +4205,9 @@ TEST_P(QuicConnectionTest, BadVersionNegotiation) { scoped_ptr<QuicEncryptedPacket> encrypted( framer_.BuildVersionNegotiationPacket(connection_id_, QuicSupportedVersions())); - connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *encrypted); + scoped_ptr<QuicReceivedPacket> received( + ConstructReceivedPacket(*encrypted, QuicTime::Zero())); + connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received); } TEST_P(QuicConnectionTest, CheckSendStats) { @@ -4277,7 +4283,7 @@ TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) { connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, - QuicEncryptedPacket(buffer, encrypted_length, false)); + QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); } TEST_P(QuicConnectionTest, SelectMutualVersion) { diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc index 8d1ff31..d87d14d 100644 --- a/net/quic/quic_crypto_server_stream_test.cc +++ b/net/quic/quic_crypto_server_stream_test.cc @@ -146,7 +146,7 @@ class QuicCryptoServerStreamTest : public ::testing::TestWithParam<bool> { } bool AsyncStrikeRegisterVerification() { - if (server_connection_->version() > QUIC_VERSION_31) { + if (server_connection_->version() > QUIC_VERSION_32) { return false; } return GetParam(); diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc index 67f3a0c..e86474b 100644 --- a/net/quic/quic_flags.cc +++ b/net/quic/quic_flags.cc @@ -138,3 +138,11 @@ bool FLAGS_quic_dont_copy_acks = true; // Use a byte conservation approach instead of packet conservation in the // Slow Start Large Reduction experiment. bool FLAGS_quic_sslr_byte_conservation = true; + +// Try to use the socket timestamp to determine the time a packet was +// received instead of Now(). +bool FLAGS_quic_use_socket_timestamp = true; + +// If true, handling of errors from invalid stream frames is done in +// one place in QuicStreamSequencer::OnStreamFrame. +bool FLAGS_quic_consolidate_onstreamframe_errors = true; diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h index 5936e8b..0e70632 100644 --- a/net/quic/quic_flags.h +++ b/net/quic/quic_flags.h @@ -46,5 +46,7 @@ NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_rto_timeout; NET_EXPORT_PRIVATE extern bool FLAGS_quic_dont_limit_max_cwnd; NET_EXPORT_PRIVATE extern bool FLAGS_quic_dont_copy_acks; NET_EXPORT_PRIVATE extern bool FLAGS_quic_sslr_byte_conservation; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_socket_timestamp; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_consolidate_onstreamframe_errors; #endif // NET_QUIC_QUIC_FLAGS_H_ diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index fa667f2..3d3e36f 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc @@ -621,12 +621,6 @@ bool QuicFramer::ProcessPublicResetPacket( } // TODO(satyamshekhar): validate nonce to protect against DoS. - if (reset->GetUint64(kRSEQ, &packet.rejected_packet_number) != - QUIC_NO_ERROR) { - set_detailed_error("Unable to read rejected packet number."); - return RaiseError(QUIC_INVALID_PUBLIC_RST_PACKET); - } - StringPiece address; if (reset->GetStringPiece(kCADR, &address)) { QuicSocketAddressCoder address_coder; @@ -1009,9 +1003,16 @@ bool QuicFramer::ProcessAuthenticatedHeader(QuicDataReader* reader, return RaiseError(QUIC_INVALID_PACKET_HEADER); } - if (private_flags > PACKET_PRIVATE_FLAGS_MAX) { - set_detailed_error("Illegal private flags value."); - return RaiseError(QUIC_INVALID_PACKET_HEADER); + if (quic_version_ > QUIC_VERSION_31) { + if (private_flags > PACKET_PRIVATE_FLAGS_MAX_VERSION_32) { + set_detailed_error("Illegal private flags value."); + return RaiseError(QUIC_INVALID_PACKET_HEADER); + } + } else { + if (private_flags > PACKET_PRIVATE_FLAGS_MAX) { + set_detailed_error("Illegal private flags value."); + return RaiseError(QUIC_INVALID_PACKET_HEADER); + } } header->entropy_flag = (private_flags & PACKET_PRIVATE_FLAGS_ENTROPY) != 0; @@ -1369,6 +1370,10 @@ bool QuicFramer::ProcessAckFrame(QuicDataReader* reader, last_packet_number -= (range_length + 1); } + if (quic_version_ > QUIC_VERSION_31) { + return true; + } + // Parse the revived packets list. // TODO(ianswett): Change the ack frame so it only expresses one revived. uint8_t num_revived_packets; @@ -1753,7 +1758,10 @@ size_t QuicFramer::GetAckFrameSize( size_t ack_size = GetMinAckFrameSize(largest_observed_length); if (!ack_info.nack_ranges.empty()) { - ack_size += kNumberOfNackRangesSize + kNumberOfRevivedPacketsSize; + ack_size += kNumberOfNackRangesSize; + if (quic_version_ <= QUIC_VERSION_31) { + ack_size += kNumberOfRevivedPacketsSize; + } ack_size += min(ack_info.nack_ranges.size(), kMaxNackRanges) * (missing_packet_number_length + PACKET_1BYTE_PACKET_NUMBER); } @@ -1935,9 +1943,12 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicPacketHeader& header, QuicPacketNumberLength missing_packet_number_length = GetMinSequenceNumberLength(ack_info.max_delta); // Determine whether we need to truncate ranges. - size_t available_range_bytes = - writer->capacity() - writer->length() - kNumberOfRevivedPacketsSize - - kNumberOfNackRangesSize - GetMinAckFrameSize(largest_observed_length); + size_t available_range_bytes = writer->capacity() - writer->length() - + kNumberOfNackRangesSize - + GetMinAckFrameSize(largest_observed_length); + if (quic_version_ <= QUIC_VERSION_31) { + available_range_bytes -= kNumberOfRevivedPacketsSize; + } size_t max_num_ranges = available_range_bytes / (missing_packet_number_length + PACKET_1BYTE_PACKET_NUMBER); @@ -2043,6 +2054,10 @@ bool QuicFramer::AppendAckFrameAndTypeByte(const QuicPacketHeader& header, } DCHECK_EQ(num_missing_ranges, num_ranges_written); + if (quic_version_ > QUIC_VERSION_31) { + return true; + } + // Append revived packets. // FEC is not supported. uint8_t num_revived_packets = 0; diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index d770db9..80f7683 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc @@ -1381,10 +1381,16 @@ TEST_P(QuicFramerTest, InvalidFECGroupOffset) { 0x10 }; // clang-format on - CheckProcessingFails(packet, arraysize(packet), - "First fec protected packet offset must be less " - "than the packet number.", - QUIC_INVALID_PACKET_HEADER); + if (framer_.version() > QUIC_VERSION_31) { + CheckProcessingFails(packet, arraysize(packet), + "Illegal private flags value.", + QUIC_INVALID_PACKET_HEADER); + } else { + CheckProcessingFails(packet, arraysize(packet), + "First fec protected packet offset must be less " + "than the packet number.", + QUIC_INVALID_PACKET_HEADER); + } }; TEST_P(QuicFramerTest, PaddingFrame) { @@ -1791,6 +1797,10 @@ TEST_P(QuicFramerTest, AckFrameTwoTimestamp) { }; // clang-format on + if (framer_.version() > QUIC_VERSION_31) { + return; + } + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); @@ -1869,6 +1879,119 @@ TEST_P(QuicFramerTest, AckFrameTwoTimestamp) { } } +TEST_P(QuicFramerTest, AckFrameTwoTimestampVersion32) { + // clang-format off + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, not truncated, 6 byte largest observed, 1 byte delta) + 0x6C, + // entropy hash of all received packets. + 0xBA, + // largest observed packet number + 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12, + // Zero delta time. + 0x00, 0x00, + // Number of timestamps. + 0x02, + // Delta from largest observed. + 0x01, + // Delta time. + 0x10, 0x32, 0x54, 0x76, + // Delta from largest observed. + 0x02, + // Delta time. + 0x10, 0x32, + // num missing packets + 0x01, + // missing packet delta + 0x01, + // 0 more missing packets in range. + 0x00, + }; + // clang-format on + + if (framer_.version() <= QUIC_VERSION_31) { + return; + } + + 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, !kIncludePathId)); + + EXPECT_EQ(0u, visitor_.stream_frames_.size()); + ASSERT_EQ(1u, visitor_.ack_frames_.size()); + const QuicAckFrame& frame = *visitor_.ack_frames_[0]; + EXPECT_EQ(0xBA, frame.entropy_hash); + EXPECT_EQ(kLargestObserved, frame.largest_observed); + ASSERT_EQ(1u, frame.missing_packets.NumPacketsSlow()); + ASSERT_EQ(2u, frame.received_packet_times.size()); + EXPECT_EQ(kMissingPacket, frame.missing_packets.Min()); + + const size_t kReceivedEntropyOffset = kQuicFrameTypeSize; + const size_t kLargestObservedOffset = + kReceivedEntropyOffset + kQuicEntropyHashSize; + const size_t kMissingDeltaTimeOffset = + kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER; + const size_t kNumTimestampsOffset = + kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize; + const size_t kTimestampDeltaLargestObserved1 = + kNumTimestampsOffset + kQuicNumTimestampsSize; + const size_t kTimestampTimeDeltaLargestObserved1 = + kTimestampDeltaLargestObserved1 + 1; + const size_t kTimestampDeltaLargestObserved2 = + kTimestampTimeDeltaLargestObserved1 + 4; + const size_t kTimestampTimeDeltaLargestObserved2 = + kTimestampDeltaLargestObserved2 + 1; + const size_t kNumMissingPacketOffset = + kTimestampTimeDeltaLargestObserved2 + 2; + const size_t kMissingPacketsOffset = + kNumMissingPacketOffset + kNumberOfNackRangesSize; + // Now test framing boundaries. + const size_t ack_frame_size = PACKET_1BYTE_PACKET_NUMBER; + for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) { + string expected_error; + if (i < kLargestObservedOffset) { + expected_error = "Unable to read entropy hash for received packets."; + } else if (i < kMissingDeltaTimeOffset) { + expected_error = "Unable to read largest observed."; + } else if (i < kNumTimestampsOffset) { + expected_error = "Unable to read ack delay time."; + } else if (i < kTimestampDeltaLargestObserved1) { + expected_error = "Unable to read num received packets."; + } else if (i < kTimestampTimeDeltaLargestObserved1) { + expected_error = "Unable to read sequence delta in received packets."; + } else if (i < kTimestampDeltaLargestObserved2) { + expected_error = "Unable to read time delta in received packets."; + } else if (i < kTimestampTimeDeltaLargestObserved2) { + expected_error = "Unable to read sequence delta in received packets."; + } else if (i < kNumMissingPacketOffset) { + expected_error = + "Unable to read incremental time delta in received packets."; + } else if (i < kMissingPacketsOffset) { + expected_error = "Unable to read num missing packet ranges."; + } else { + expected_error = "Unable to read missing packet number delta."; + } + CheckProcessingFails( + packet, + i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), + expected_error, QUIC_INVALID_ACK_DATA); + } +} + TEST_P(QuicFramerTest, AckFrameOneTimestamp) { // clang-format off unsigned char packet[] = { @@ -1907,6 +2030,10 @@ TEST_P(QuicFramerTest, AckFrameOneTimestamp) { }; // clang-format on + if (framer_.version() > QUIC_VERSION_31) { + return; + } + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); @@ -1975,6 +2102,105 @@ TEST_P(QuicFramerTest, AckFrameOneTimestamp) { } } +TEST_P(QuicFramerTest, AckFrameOneTimestampVersion32) { + // clang-format off + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, not truncated, 6 byte largest observed, 1 byte delta) + 0x6C, + // entropy hash of all received packets. + 0xBA, + // largest observed packet number + 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12, + // Zero delta time. + 0x00, 0x00, + // Number of timestamps. + 0x01, + // Delta from largest observed. + 0x01, + // Delta time. + 0x10, 0x32, 0x54, 0x76, + // num missing packets + 0x01, + // missing packet delta + 0x01, + // 0 more missing packets in range. + 0x00, + }; + // clang-format on + + if (framer_.version() <= QUIC_VERSION_31) { + return; + } + + 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, !kIncludePathId)); + + EXPECT_EQ(0u, visitor_.stream_frames_.size()); + ASSERT_EQ(1u, visitor_.ack_frames_.size()); + const QuicAckFrame& frame = *visitor_.ack_frames_[0]; + EXPECT_EQ(0xBA, frame.entropy_hash); + EXPECT_EQ(kLargestObserved, frame.largest_observed); + ASSERT_EQ(1u, frame.missing_packets.NumPacketsSlow()); + ASSERT_EQ(1u, frame.received_packet_times.size()); + EXPECT_EQ(kMissingPacket, frame.missing_packets.Min()); + + const size_t kReceivedEntropyOffset = kQuicFrameTypeSize; + const size_t kLargestObservedOffset = + kReceivedEntropyOffset + kQuicEntropyHashSize; + const size_t kMissingDeltaTimeOffset = + kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER; + const size_t kNumTimestampsOffset = + kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize; + const size_t kTimestampDeltaLargestObserved = + kNumTimestampsOffset + kQuicNumTimestampsSize; + const size_t kTimestampTimeDeltaLargestObserved = + kTimestampDeltaLargestObserved + 1; + const size_t kNumMissingPacketOffset = kTimestampTimeDeltaLargestObserved + 4; + const size_t kMissingPacketsOffset = + kNumMissingPacketOffset + kNumberOfNackRangesSize; + // Now test framing boundaries. + const size_t ack_frame_size = PACKET_1BYTE_PACKET_NUMBER; + for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) { + string expected_error; + if (i < kLargestObservedOffset) { + expected_error = "Unable to read entropy hash for received packets."; + } else if (i < kMissingDeltaTimeOffset) { + expected_error = "Unable to read largest observed."; + } else if (i < kNumTimestampsOffset) { + expected_error = "Unable to read ack delay time."; + } else if (i < kTimestampDeltaLargestObserved) { + expected_error = "Unable to read num received packets."; + } else if (i < kTimestampTimeDeltaLargestObserved) { + expected_error = "Unable to read sequence delta in received packets."; + } else if (i < kNumMissingPacketOffset) { + expected_error = "Unable to read time delta in received packets."; + } else if (i < kMissingPacketsOffset) { + expected_error = "Unable to read num missing packet ranges."; + } else { + expected_error = "Unable to read missing packet number delta."; + } + CheckProcessingFails( + packet, + i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), + expected_error, QUIC_INVALID_ACK_DATA); + } +} + TEST_P(QuicFramerTest, AckFrame) { // clang-format off unsigned char packet[] = { @@ -2009,6 +2235,10 @@ TEST_P(QuicFramerTest, AckFrame) { }; // clang-format on + if (framer_.version() > QUIC_VERSION_31) { + return; + } + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); @@ -2069,6 +2299,93 @@ TEST_P(QuicFramerTest, AckFrame) { } } +TEST_P(QuicFramerTest, AckFrameVersion32) { + // clang-format off + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, not truncated, 6 byte largest observed, 1 byte delta) + 0x6C, + // entropy hash of all received packets. + 0xBA, + // largest observed packet number + 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12, + // Zero delta time. + 0x00, 0x00, + // Number of timestamps. + 0x00, + // num missing packets + 0x01, + // missing packet delta + 0x01, + // 0 more missing packets in range. + 0x00, + }; + // clang-format on + + if (framer_.version() <= QUIC_VERSION_31) { + return; + } + + 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, !kIncludePathId)); + + EXPECT_EQ(0u, visitor_.stream_frames_.size()); + ASSERT_EQ(1u, visitor_.ack_frames_.size()); + const QuicAckFrame& frame = *visitor_.ack_frames_[0]; + EXPECT_EQ(0xBA, frame.entropy_hash); + EXPECT_EQ(kLargestObserved, frame.largest_observed); + ASSERT_EQ(1u, frame.missing_packets.NumPacketsSlow()); + EXPECT_EQ(kMissingPacket, frame.missing_packets.Min()); + + const size_t kReceivedEntropyOffset = kQuicFrameTypeSize; + const size_t kLargestObservedOffset = + kReceivedEntropyOffset + kQuicEntropyHashSize; + const size_t kMissingDeltaTimeOffset = + kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER; + const size_t kNumTimestampsOffset = + kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize; + const size_t kNumMissingPacketOffset = + kNumTimestampsOffset + kQuicNumTimestampsSize; + const size_t kMissingPacketsOffset = + kNumMissingPacketOffset + kNumberOfNackRangesSize; + // Now test framing boundaries. + const size_t ack_frame_size = PACKET_1BYTE_PACKET_NUMBER; + for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) { + string expected_error; + if (i < kLargestObservedOffset) { + expected_error = "Unable to read entropy hash for received packets."; + } else if (i < kMissingDeltaTimeOffset) { + expected_error = "Unable to read largest observed."; + } else if (i < kNumTimestampsOffset) { + expected_error = "Unable to read ack delay time."; + } else if (i < kNumMissingPacketOffset) { + expected_error = "Unable to read num received packets."; + } else if (i < kMissingPacketsOffset) { + expected_error = "Unable to read num missing packet ranges."; + } else { + expected_error = "Unable to read missing packet number delta."; + } + CheckProcessingFails( + packet, + i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), + expected_error, QUIC_INVALID_ACK_DATA); + } +} + TEST_P(QuicFramerTest, AckFrameRevivedPackets) { // clang-format off unsigned char packet[] = { @@ -2107,6 +2424,10 @@ TEST_P(QuicFramerTest, AckFrameRevivedPackets) { }; // clang-format on + if (framer_.version() > QUIC_VERSION_31) { + return; + } + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); @@ -2264,6 +2585,79 @@ TEST_P(QuicFramerTest, AckFrame500Nacks) { }; // clang-format on + if (framer_.version() > QUIC_VERSION_31) { + return; + } + + 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, !kIncludePathId)); + + EXPECT_EQ(0u, visitor_.stream_frames_.size()); + ASSERT_EQ(1u, visitor_.ack_frames_.size()); + QuicAckFrame* frame = visitor_.ack_frames_[0]; + EXPECT_EQ(0xBA, frame->entropy_hash); + EXPECT_EQ(kLargestObserved, frame->largest_observed); + ASSERT_EQ(500u, frame->missing_packets.NumPacketsSlow()); + EXPECT_EQ(kMissingPacket - 499, frame->missing_packets.Min()); + EXPECT_EQ(kMissingPacket, frame->missing_packets.Max()); + + // Verify that the packet re-serializes identically. + QuicFrames frames; + frames.push_back(QuicFrame(frame)); + scoped_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames)); + ASSERT_TRUE(data != nullptr); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet), + arraysize(packet)); +} + +TEST_P(QuicFramerTest, AckFrame500NacksVersion32) { + // clang-format off + unsigned char packet[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, not truncated, 6 byte largest observed, 1 byte delta) + 0x6C, + // entropy hash of all received packets. + 0xBA, + // largest observed packet number + 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12, + // Zero delta time. + 0x00, 0x00, + // No received packets. + 0x00, + // num missing packet ranges + 0x02, + // missing packet delta + 0x01, + // 243 more missing packets in range. + // The ranges are listed in this order so the re-constructed packet + // matches. + 0xF3, + // No gap between ranges + 0x00, + // 255 more missing packets in range. + 0xFF, + }; + // clang-format on + + if (framer_.version() <= QUIC_VERSION_31) { + return; + } + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); @@ -2737,8 +3131,7 @@ TEST_P(QuicFramerTest, PublicResetPacket) { EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag); EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag); EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof); - EXPECT_EQ(kPacketNumber, - visitor_.public_reset_packet_->rejected_packet_number); + EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number); EXPECT_EQ(ADDRESS_FAMILY_UNSPECIFIED, visitor_.public_reset_packet_->client_address.GetFamily()); @@ -2844,8 +3237,7 @@ TEST_P(QuicFramerTest, PublicResetPacketWithClientAddress) { EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag); EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag); EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof); - EXPECT_EQ(kPacketNumber, - visitor_.public_reset_packet_->rejected_packet_number); + EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number); EXPECT_EQ("4.31.198.44", visitor_.public_reset_packet_->client_address.address().ToString()); EXPECT_EQ(443, visitor_.public_reset_packet_->client_address.port()); @@ -2933,9 +3325,13 @@ TEST_P(QuicFramerTest, DropFecPacket) { // clang-format on QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); - EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + if (framer_.version() <= QUIC_VERSION_31) { + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + } else { + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + } EXPECT_FALSE(visitor_.header_.get()); } @@ -3412,12 +3808,49 @@ TEST_P(QuicFramerTest, BuildAckFramePacket) { }; // clang-format on + // clang-format off + unsigned char packet_version32[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, not truncated, 6 byte largest observed, 1 byte delta) + 0x6C, + // entropy hash of all received packets. + 0x43, + // largest observed packet number + 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12, + // Zero delta time. + 0x00, 0x00, + // num received packets. + 0x00, + // num missing packet ranges + 0x01, + // missing packet delta + 0x01, + // 0 more missing packets in range. + 0x00, + }; + // clang-format on + scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError("constructed packet", data->data(), - data->length(), AsChars(packet), - arraysize(packet)); + if (framer_.version() <= QUIC_VERSION_31) { + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet), + arraysize(packet)); + } else { + test::CompareCharArraysWithHexError( + "constructed packet", data->data(), data->length(), + AsChars(packet_version32), arraysize(packet_version32)); + } } // TODO(jri): Add test for tuncated packets in which the original ack frame had @@ -3526,12 +3959,94 @@ TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) { }; // clang-format on + // clang-format off + unsigned char packet_version32[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, is truncated, 2 byte largest observed, 1 byte delta) + 0x74, + // entropy hash of all received packets, set to 1 by TestEntropyCalculator + // since ack is truncated. + 0x01, + // 2-byte largest observed packet number. + // Expected to be 510 (0x1FE), since only 255 nack ranges can fit. + 0xFE, 0x01, + // Zero delta time. + 0x00, 0x00, + // num missing packet ranges (limited to 255 by size of this field). + 0xFF, + // {missing packet delta, further missing packets in range} + // 6 nack ranges x 42 + 3 nack ranges + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + }; + // clang-format on + scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError("constructed packet", data->data(), - data->length(), AsChars(packet), - arraysize(packet)); + if (framer_.version() <= QUIC_VERSION_31) { + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet), + arraysize(packet)); + } else { + test::CompareCharArraysWithHexError( + "constructed packet", data->data(), data->length(), + AsChars(packet_version32), arraysize(packet_version32)); + } } TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacket) { @@ -3590,13 +4105,53 @@ TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacket) { }; // clang-format on - scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames, 37u)); - ASSERT_TRUE(data != nullptr); - // Expect 1 byte unused since at least 2 bytes are needed to fit more nacks. - EXPECT_EQ(36u, data->length()); - test::CompareCharArraysWithHexError("constructed packet", data->data(), - data->length(), AsChars(packet), - arraysize(packet)); + // clang-format off + unsigned char packet_version32[] = { + // public flags (8 byte connection_id) + 0x3C, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // packet number + 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + // private flags (entropy) + 0x01, + + // frame type (ack frame) + // (has nacks, is truncated, 2 byte largest observed, 1 byte delta) + 0x74, + // entropy hash of all received packets, set to 1 by TestEntropyCalculator + // since ack is truncated. + 0x01, + // 2-byte largest observed packet number. + // Expected to be 12 (0x0C), since only 6 nack ranges can fit. + 0x0C, 0x00, + // Zero delta time. + 0x00, 0x00, + // num missing packet ranges (limited to 6 by packet size of 37). + 0x06, + // {missing packet delta, further missing packets in range} + // 6 nack ranges + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + }; + // clang-format on + + if (framer_.version() <= QUIC_VERSION_31) { + scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames, 37u)); + ASSERT_TRUE(data != nullptr); + // Expect 1 byte unused since at least 2 bytes are needed to fit more nacks. + EXPECT_EQ(36u, data->length()); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet), + arraysize(packet)); + } else { + scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames, 36u)); + ASSERT_TRUE(data != nullptr); + // Expect 1 byte unused since at least 2 bytes are needed to fit more nacks. + EXPECT_EQ(35u, data->length()); + test::CompareCharArraysWithHexError( + "constructed packet", data->data(), data->length(), + AsChars(packet_version32), arraysize(packet_version32)); + } } TEST_P(QuicFramerTest, BuildStopWaitingPacket) { diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index 3e2c444..569d285 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc @@ -129,11 +129,11 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { // Holds a packet to be written to the wire, and the IO mode that should // be used by the mock socket when performing the write. struct PacketToWrite { - PacketToWrite(IoMode mode, QuicEncryptedPacket* packet) + PacketToWrite(IoMode mode, QuicReceivedPacket* packet) : mode(mode), packet(packet) {} PacketToWrite(IoMode mode, int rv) : mode(mode), packet(nullptr), rv(rv) {} IoMode mode; - QuicEncryptedPacket* packet; + QuicReceivedPacket* packet; int rv; }; @@ -161,7 +161,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { } // Adds a packet to the list of expected writes. - void AddWrite(scoped_ptr<QuicEncryptedPacket> packet) { + void AddWrite(scoped_ptr<QuicReceivedPacket> packet) { writes_.push_back(PacketToWrite(SYNCHRONOUS, packet.release())); } @@ -170,14 +170,14 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { } // Returns the packet to be written at position |pos|. - QuicEncryptedPacket* GetWrite(size_t pos) { return writes_[pos].packet; } + QuicReceivedPacket* GetWrite(size_t pos) { return writes_[pos].packet; } bool AtEof() { return socket_data_->AllReadDataConsumed() && socket_data_->AllWriteDataConsumed(); } - void ProcessPacket(scoped_ptr<QuicEncryptedPacket> packet) { + void ProcessPacket(scoped_ptr<QuicReceivedPacket> packet) { connection_->ProcessUdpPacket(self_addr_, peer_addr_, *packet); } @@ -283,7 +283,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { response_data_ = body; } - scoped_ptr<QuicEncryptedPacket> InnerConstructDataPacket( + scoped_ptr<QuicReceivedPacket> InnerConstructDataPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -294,7 +294,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { should_include_version, fin, offset, data); } - scoped_ptr<QuicEncryptedPacket> ConstructDataPacket( + scoped_ptr<QuicReceivedPacket> ConstructDataPacket( QuicPacketNumber packet_number, bool should_include_version, bool fin, @@ -304,7 +304,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { should_include_version, fin, offset, data); } - scoped_ptr<QuicEncryptedPacket> InnerConstructRequestHeadersPacket( + scoped_ptr<QuicReceivedPacket> InnerConstructRequestHeadersPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -318,7 +318,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { request_headers_, spdy_headers_frame_length); } - scoped_ptr<QuicEncryptedPacket> ConstructRequestHeadersPacket( + scoped_ptr<QuicReceivedPacket> ConstructRequestHeadersPacket( QuicPacketNumber packet_number, bool fin, RequestPriority request_priority, @@ -328,7 +328,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { spdy_headers_frame_length); } - scoped_ptr<QuicEncryptedPacket> InnerConstructResponseHeadersPacket( + scoped_ptr<QuicReceivedPacket> InnerConstructResponseHeadersPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool fin, @@ -338,7 +338,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { spdy_headers_frame_length, &response_offset_); } - scoped_ptr<QuicEncryptedPacket> ConstructResponseHeadersPacket( + scoped_ptr<QuicReceivedPacket> ConstructResponseHeadersPacket( QuicPacketNumber packet_number, bool fin, size_t* spdy_headers_frame_length) { @@ -346,7 +346,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { spdy_headers_frame_length); } - scoped_ptr<QuicEncryptedPacket> ConstructResponseHeadersPacketWithOffset( + scoped_ptr<QuicReceivedPacket> ConstructResponseHeadersPacketWithOffset( QuicPacketNumber packet_number, bool fin, size_t* spdy_headers_frame_length, @@ -356,7 +356,7 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { spdy_headers_frame_length, offset); } - scoped_ptr<QuicEncryptedPacket> ConstructResponseTrailersPacket( + scoped_ptr<QuicReceivedPacket> ConstructResponseTrailersPacket( QuicPacketNumber packet_number, bool fin, const SpdyHeaderBlock& trailers, @@ -367,26 +367,26 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { spdy_headers_frame_length, offset); } - scoped_ptr<QuicEncryptedPacket> ConstructRstStreamPacket( + scoped_ptr<QuicReceivedPacket> ConstructRstStreamPacket( QuicPacketNumber packet_number) { return maker_.MakeRstPacket( packet_number, true, stream_id_, AdjustErrorForVersion(QUIC_RST_ACKNOWLEDGEMENT, GetParam())); } - scoped_ptr<QuicEncryptedPacket> ConstructRstStreamCancelledPacket( + scoped_ptr<QuicReceivedPacket> ConstructRstStreamCancelledPacket( QuicPacketNumber packet_number) { return maker_.MakeRstPacket(packet_number, !kIncludeVersion, stream_id_, QUIC_STREAM_CANCELLED); } - scoped_ptr<QuicEncryptedPacket> ConstructRstStreamVaryMismatchPacket( + scoped_ptr<QuicReceivedPacket> ConstructRstStreamVaryMismatchPacket( QuicPacketNumber packet_number) { return maker_.MakeRstPacket(packet_number, !kIncludeVersion, promise_id_, QUIC_PROMISE_VARY_MISMATCH); } - scoped_ptr<QuicEncryptedPacket> ConstructAckAndRstStreamPacket( + scoped_ptr<QuicReceivedPacket> ConstructAckAndRstStreamPacket( QuicPacketNumber packet_number, QuicPacketNumber largest_received, QuicPacketNumber ack_least_unacked, @@ -397,12 +397,12 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> { !kIncludeCongestionFeedback); } - scoped_ptr<QuicEncryptedPacket> ConstructAckAndRstStreamPacket( + scoped_ptr<QuicReceivedPacket> ConstructAckAndRstStreamPacket( QuicPacketNumber packet_number) { return ConstructAckAndRstStreamPacket(packet_number, 2, 1, 1); } - scoped_ptr<QuicEncryptedPacket> ConstructAckPacket( + scoped_ptr<QuicReceivedPacket> ConstructAckPacket( QuicPacketNumber packet_number, QuicPacketNumber largest_received, QuicPacketNumber least_unacked) { diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index 4ec1012..2da013e 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc @@ -194,6 +194,8 @@ QuicTag QuicVersionToQuicTag(const QuicVersion version) { return MakeQuicTag('Q', '0', '3', '0'); case QUIC_VERSION_31: return MakeQuicTag('Q', '0', '3', '1'); + case QUIC_VERSION_32: + return MakeQuicTag('Q', '0', '3', '2'); default: // This shold be an ERROR because we should never attempt to convert an // invalid QuicVersion to be written to the wire. @@ -227,6 +229,7 @@ string QuicVersionToString(const QuicVersion version) { RETURN_STRING_LITERAL(QUIC_VERSION_29); RETURN_STRING_LITERAL(QUIC_VERSION_30); RETURN_STRING_LITERAL(QUIC_VERSION_31); + RETURN_STRING_LITERAL(QUIC_VERSION_32); default: return "QUIC_VERSION_UNSUPPORTED"; } @@ -354,7 +357,7 @@ QuicFrame::QuicFrame(QuicPathCloseFrame* frame) ostream& operator<<(ostream& os, const QuicStopWaitingFrame& sent_info) { os << "entropy_hash: " << static_cast<int>(sent_info.entropy_hash) - << " least_unacked: " << sent_info.least_unacked; + << " least_unacked: " << sent_info.least_unacked << "\n"; return os; } @@ -532,7 +535,7 @@ ostream& operator<<(ostream& os, const QuicAckFrame& ack_frame) { ack_frame.received_packet_times) { os << p.first << " at " << p.second.ToDebuggingValue() << " "; } - os << " ]"; + os << " ]\n"; return os; } @@ -695,6 +698,40 @@ QuicEncryptedPacket::QuicEncryptedPacket(char* buffer, bool owns_buffer) : QuicData(buffer, length, owns_buffer) {} +QuicEncryptedPacket* QuicEncryptedPacket::Clone() const { + char* buffer = new char[this->length()]; + memcpy(buffer, this->data(), this->length()); + return new QuicEncryptedPacket(buffer, this->length(), true); +} + +ostream& operator<<(ostream& os, const QuicEncryptedPacket& s) { + os << s.length() << "-byte data"; + return os; +} + +QuicReceivedPacket::QuicReceivedPacket(const char* buffer, + size_t length, + QuicTime receipt_time) + : QuicEncryptedPacket(buffer, length), receipt_time_(receipt_time) {} + +QuicReceivedPacket::QuicReceivedPacket(char* buffer, + size_t length, + QuicTime receipt_time, + bool owns_buffer) + : QuicEncryptedPacket(buffer, length, owns_buffer), + receipt_time_(receipt_time) {} + +QuicReceivedPacket* QuicReceivedPacket::Clone() const { + char* buffer = new char[this->length()]; + memcpy(buffer, this->data(), this->length()); + return new QuicReceivedPacket(buffer, this->length(), receipt_time(), true); +} + +ostream& operator<<(ostream& os, const QuicReceivedPacket& s) { + os << s.length() << "-byte data"; + return os; +} + StringPiece QuicPacket::AssociatedData() const { return StringPiece(data(), GetStartOfEncryptedData( connection_id_length_, includes_version_, @@ -746,17 +783,6 @@ SerializedPacket::SerializedPacket(const SerializedPacket& other) = default; SerializedPacket::~SerializedPacket() {} -QuicEncryptedPacket* QuicEncryptedPacket::Clone() const { - char* buffer = new char[this->length()]; - memcpy(buffer, this->data(), this->length()); - return new QuicEncryptedPacket(buffer, this->length(), true); -} - -ostream& operator<<(ostream& os, const QuicEncryptedPacket& s) { - os << s.length() << "-byte data"; - return os; -} - TransmissionInfo::TransmissionInfo() : encryption_level(ENCRYPTION_NONE), packet_number_length(PACKET_1BYTE_PACKET_NUMBER), diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index 7757c23..73ebf3a 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h @@ -337,7 +337,10 @@ enum QuicPacketPrivateFlags { PACKET_PRIVATE_FLAGS_FEC = 1 << 2, // All bits set (bits 3-7 are not currently used): 00000111 - PACKET_PRIVATE_FLAGS_MAX = (1 << 3) - 1 + PACKET_PRIVATE_FLAGS_MAX = (1 << 3) - 1, + + // For version 32 (bits 1-7 are not used): 00000001 + PACKET_PRIVATE_FLAGS_MAX_VERSION_32 = (1 << 1) - 1 }; // The available versions of QUIC. Guaranteed that the integer value of the enum @@ -358,6 +361,7 @@ enum QuicVersion { QUIC_VERSION_29 = 29, // Server and client honor QUIC_STREAM_NO_ERROR. QUIC_VERSION_30 = 30, // Add server side support of cert transparency. QUIC_VERSION_31 = 31, // Adds a hash of the client hello to crypto proof. + QUIC_VERSION_32 = 32, // FEC related fields are removed from wire format. }; // This vector contains QUIC versions which we currently support. @@ -368,8 +372,8 @@ enum QuicVersion { // IMPORTANT: if you are adding to this list, follow the instructions at // http://sites/quic/adding-and-removing-versions static const QuicVersion kSupportedQuicVersions[] = { - QUIC_VERSION_31, QUIC_VERSION_30, QUIC_VERSION_29, QUIC_VERSION_28, - QUIC_VERSION_27, QUIC_VERSION_26, QUIC_VERSION_25}; + QUIC_VERSION_32, QUIC_VERSION_31, QUIC_VERSION_30, QUIC_VERSION_29, + QUIC_VERSION_28, QUIC_VERSION_27, QUIC_VERSION_26, QUIC_VERSION_25}; typedef std::vector<QuicVersion> QuicVersionVector; @@ -494,6 +498,8 @@ enum QuicErrorCode { QUIC_INVALID_FEC_DATA = 5, // STREAM frame data is malformed. QUIC_INVALID_STREAM_DATA = 46, + // STREAM frame data overlaps with buffered data. + QUIC_OVERLAPPING_STREAM_DATA = 87, // STREAM frame data is not encrypted. QUIC_UNENCRYPTED_STREAM_DATA = 61, // FEC frame data is not encrypted. @@ -559,7 +565,7 @@ enum QuicErrorCode { // There was an error while reading from the socket. QUIC_PACKET_READ_ERROR = 51, // We received a STREAM_FRAME with no data and no fin flag set. - QUIC_INVALID_STREAM_FRAME = 50, + QUIC_EMPTY_STREAM_FRAME_NO_FIN = 50, // We received invalid data on the headers stream. QUIC_INVALID_HEADERS_STREAM_DATA = 56, // The peer received too much data, violating flow control. @@ -662,7 +668,7 @@ enum QuicErrorCode { QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM = 84, // No error. Used as bound while iterating. - QUIC_LAST_ERROR = 87, + QUIC_LAST_ERROR = 88, }; // Must be updated any time a QuicErrorCode is deprecated. @@ -1245,6 +1251,35 @@ class NET_EXPORT_PRIVATE QuicEncryptedPacket : public QuicData { DISALLOW_COPY_AND_ASSIGN(QuicEncryptedPacket); }; +// A received encrypted QUIC packet, with a recorded time of receipt. +class NET_EXPORT_PRIVATE QuicReceivedPacket : public QuicEncryptedPacket { + public: + QuicReceivedPacket(const char* buffer, size_t length, QuicTime receipt_time); + QuicReceivedPacket(char* buffer, + size_t length, + QuicTime receipt_time, + bool owns_buffer); + + // Clones the packet into a new packet which owns the buffer. + QuicReceivedPacket* Clone() const; + + // Returns the time at which the packet was received. + QuicTime receipt_time() const { return receipt_time_; } + + // 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 + // bytes, which causes the default gtest object printer to read + // uninitialize memory. So we need to teach gtest how to print this object. + NET_EXPORT_PRIVATE friend std::ostream& operator<<( + std::ostream& os, + const QuicReceivedPacket& s); + + private: + const QuicTime receipt_time_; + + DISALLOW_COPY_AND_ASSIGN(QuicReceivedPacket); +}; + // Pure virtual class to listen for packet acknowledgements. class NET_EXPORT_PRIVATE QuicAckListenerInterface : public base::RefCounted<QuicAckListenerInterface> { diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index 14edd79..9448d98 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc @@ -230,7 +230,7 @@ bool QuicSession::HasOpenDynamicStreams() const { void QuicSession::ProcessUdpPacket(const IPEndPoint& self_address, const IPEndPoint& peer_address, - const QuicEncryptedPacket& packet) { + const QuicReceivedPacket& packet) { connection_->ProcessUdpPacket(self_address, peer_address, packet); } diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index 988c000..a8b610f 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h @@ -88,7 +88,7 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface { // Called on every incoming packet. Passes |packet| through to |connection_|. virtual void ProcessUdpPacket(const IPEndPoint& self_address, const IPEndPoint& peer_address, - const QuicEncryptedPacket& packet); + const QuicReceivedPacket& packet); // Called by streams when they want to write data to the peer. // Returns a pair with the number of bytes consumed from data, and a boolean diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc index 534b6682..65702f8 100644 --- a/net/quic/quic_session_test.cc +++ b/net/quic/quic_session_test.cc @@ -89,10 +89,6 @@ class TestStream : public QuicSpdyStream { void OnDataAvailable() override {} - void SendBody(const string& data, bool fin) { - WriteOrBufferData(data, fin, nullptr); - } - MOCK_METHOD0(OnCanWrite, void()); }; @@ -142,6 +138,12 @@ class TestSession : public QuicSpdySession { } } + bool ShouldCreateIncomingDynamicStream(QuicStreamId /*id*/) override { + return true; + } + + bool ShouldCreateOutgoingDynamicStream() override { return true; } + bool IsClosedStream(QuicStreamId id) { return QuicSession::IsClosedStream(id); } @@ -723,7 +725,7 @@ TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedStream) { EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); EXPECT_CALL(*connection_, SendBlocked(stream2->id())); EXPECT_CALL(*connection_, SendBlocked(0)); - stream2->SendBody(body, false); + stream2->WriteOrBufferBody(body, false, nullptr); EXPECT_TRUE(stream2->flow_controller()->IsBlocked()); EXPECT_TRUE(session_.IsConnectionFlowControlBlocked()); EXPECT_TRUE(session_.IsStreamFlowControlBlocked()); diff --git a/net/quic/quic_spdy_session.h b/net/quic/quic_spdy_session.h index 246a6de..8db7049 100644 --- a/net/quic/quic_spdy_session.h +++ b/net/quic/quic_spdy_session.h @@ -89,6 +89,12 @@ class NET_EXPORT_PRIVATE QuicSpdySession : public QuicSession { QuicSpdyStream* GetSpdyDataStream(const QuicStreamId stream_id); + // If an incoming stream can be created, return true. + virtual bool ShouldCreateIncomingDynamicStream(QuicStreamId id) = 0; + + // If an outgoing stream can be created, return true. + virtual bool ShouldCreateOutgoingDynamicStream() = 0; + private: friend class test::QuicSpdySessionPeer; diff --git a/net/quic/quic_spdy_stream.cc b/net/quic/quic_spdy_stream.cc index 3486593..514d317 100644 --- a/net/quic/quic_spdy_stream.cc +++ b/net/quic/quic_spdy_stream.cc @@ -77,6 +77,13 @@ size_t QuicSpdyStream::WriteHeaders( return bytes_written; } +void QuicSpdyStream::WriteOrBufferBody( + const string& data, + bool fin, + QuicAckListenerInterface* ack_notifier_delegate) { + WriteOrBufferData(data, fin, ack_notifier_delegate); +} + size_t QuicSpdyStream::WriteTrailers( SpdyHeaderBlock trailer_block, QuicAckListenerInterface* ack_notifier_delegate) { @@ -218,7 +225,7 @@ void QuicSpdyStream::OnTrailingHeadersComplete(bool fin, size_t /*frame_len*/) { SpdyHeaderBlock trailers; if (!SpdyUtils::ParseTrailers(decompressed_trailers().data(), decompressed_trailers().length(), - &final_byte_offset, &response_trailers_)) { + &final_byte_offset, &received_trailers_)) { DLOG(ERROR) << "Trailers are malformed: " << id(); session()->connection()->SendConnectionCloseWithDetails( QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers are malformed"); diff --git a/net/quic/quic_spdy_stream.h b/net/quic/quic_spdy_stream.h index a5adfe2..ee3a9a21 100644 --- a/net/quic/quic_spdy_stream.h +++ b/net/quic/quic_spdy_stream.h @@ -105,6 +105,11 @@ class NET_EXPORT_PRIVATE QuicSpdyStream : public ReliableQuicStream { bool fin, QuicAckListenerInterface* ack_notifier_delegate); + // Sends |data| to the peer, or buffers if it can't be sent immediately. + void WriteOrBufferBody(const std::string& data, + bool fin, + QuicAckListenerInterface* ack_notifier_delegate); + // Writes the trailers contained in |trailer_block| to the dedicated // headers stream. Trailers will always have the FIN set. size_t WriteTrailers(SpdyHeaderBlock trailer_block, @@ -142,8 +147,8 @@ class NET_EXPORT_PRIVATE QuicSpdyStream : public ReliableQuicStream { } // Returns whatever trailers have been received for this stream. - const SpdyHeaderBlock& response_trailers() const { - return response_trailers_; + const SpdyHeaderBlock& received_trailers() const { + return received_trailers_; } virtual SpdyPriority priority() const; @@ -188,7 +193,7 @@ class NET_EXPORT_PRIVATE QuicSpdyStream : public ReliableQuicStream { // via ProcessData or Readv. std::string decompressed_trailers_; // The parsed trailers received from the peer. - SpdyHeaderBlock response_trailers_; + SpdyHeaderBlock received_trailers_; DISALLOW_COPY_AND_ASSIGN(QuicSpdyStream); }; diff --git a/net/quic/quic_spdy_stream_test.cc b/net/quic/quic_spdy_stream_test.cc index 1e7abc6..36eda71 100644 --- a/net/quic/quic_spdy_stream_test.cc +++ b/net/quic/quic_spdy_stream_test.cc @@ -646,6 +646,35 @@ TEST_P(QuicSpdyStreamTest, ReceivingTrailers) { EXPECT_EQ("", stream_->decompressed_trailers()); } +TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutOffset) { + // Test that receiving trailers without a final offset field is an error. + Initialize(kShouldProcessData); + + // Receive initial headers. + string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); + stream_->OnStreamHeaders(headers); + stream_->OnStreamHeadersComplete(false, headers.size()); + stream_->MarkHeadersConsumed(stream_->decompressed_headers().size()); + + const string body = "this is the body"; + // Receive trailing headers, without kFinalOffsetHeaderKey. + SpdyHeaderBlock trailers_block; + trailers_block["key1"] = "value1"; + trailers_block["key2"] = "value2"; + trailers_block["key3"] = "value3"; + string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block); + stream_->OnStreamHeaders(trailers); + + // Verify that the trailers block didn't contain a final offset. + EXPECT_EQ("", trailers_block[kFinalOffsetHeaderKey].as_string()); + + // Receipt of the malformed trailers will close the connection. + EXPECT_CALL(*connection_, SendConnectionCloseWithDetails( + QUIC_INVALID_HEADERS_STREAM_DATA, _)) + .Times(1); + stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size()); +} + TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutFin) { // Test that received Trailers must always have the FIN set. Initialize(kShouldProcessData); diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc index 113f4ff..5228a0a 100644 --- a/net/quic/quic_stream_sequencer.cc +++ b/net/quic/quic_stream_sequencer.cc @@ -13,8 +13,9 @@ #include "net/quic/quic_clock.h" #include "net/quic/quic_flags.h" #include "net/quic/quic_protocol.h" +#include "net/quic/quic_stream_sequencer_buffer.h" +#include "net/quic/quic_utils.h" #include "net/quic/reliable_quic_stream.h" -#include "net/quic/stream_sequencer_buffer.h" using std::min; using std::numeric_limits; @@ -40,11 +41,12 @@ void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { ++num_frames_received_; const QuicStreamOffset byte_offset = frame.offset; const size_t data_len = frame.frame_length; - if (data_len == 0 && !frame.fin) { + bool consolidate_errors = FLAGS_quic_consolidate_onstreamframe_errors; + if (!consolidate_errors && data_len == 0 && !frame.fin) { // Stream frames must have data or a fin flag. LOG(WARNING) << "QUIC_INVALID_STREAM_FRAM: Empty stream frame " "without FIN set."; - stream_->CloseConnectionWithDetails(QUIC_INVALID_STREAM_FRAME, + stream_->CloseConnectionWithDetails(QUIC_EMPTY_STREAM_FRAME_NO_FIN, "Empty stream frame without FIN set."); return; } @@ -56,18 +58,28 @@ void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { } } size_t bytes_written; + string error_details; QuicErrorCode result = buffered_frames_.OnStreamData( byte_offset, StringPiece(frame.frame_buffer, frame.frame_length), - clock_->ApproximateNow(), &bytes_written); - - if (result == QUIC_INVALID_STREAM_DATA) { - LOG(WARNING) << "QUIC_INVALID_STREAM_FRAME: Stream frame " - "overlaps with buffered data."; - stream_->CloseConnectionWithDetails( - QUIC_INVALID_STREAM_FRAME, "Stream frame overlaps with buffered data."); - return; + clock_->ApproximateNow(), &bytes_written, &error_details); + if (!consolidate_errors) { + if (result == QUIC_OVERLAPPING_STREAM_DATA) { + LOG(WARNING) << "QUIC_INVALID_STREAM_FRAME: Stream frame " + "overlaps with buffered data."; + stream_->CloseConnectionWithDetails( + QUIC_EMPTY_STREAM_FRAME_NO_FIN, + "Stream frame overlaps with buffered data."); + return; + } + } else { + if (result != QUIC_NO_ERROR) { + LOG(WARNING) << QuicUtils::ErrorToString(result) << ": " << error_details; + stream_->CloseConnectionWithDetails(result, error_details); + return; + } } - if (result == QUIC_NO_ERROR && bytes_written == 0) { + + if ((consolidate_errors || result == QUIC_NO_ERROR) && bytes_written == 0) { ++num_duplicate_frames_received_; // Silently ignore duplicates. return; diff --git a/net/quic/quic_stream_sequencer.h b/net/quic/quic_stream_sequencer.h index 1d06d2f..add7fbc 100644 --- a/net/quic/quic_stream_sequencer.h +++ b/net/quic/quic_stream_sequencer.h @@ -12,7 +12,7 @@ #include "base/macros.h" #include "net/quic/quic_protocol.h" -#include "net/quic/stream_sequencer_buffer.h" +#include "net/quic/quic_stream_sequencer_buffer.h" using std::string; @@ -116,7 +116,7 @@ class NET_EXPORT_PRIVATE QuicStreamSequencer { ReliableQuicStream* stream_; // Stores received data in offset order. - StreamSequencerBuffer buffered_frames_; + QuicStreamSequencerBuffer buffered_frames_; // The offset, if any, we got a stream termination for. When this many bytes // have been processed, the sequencer will be closed. diff --git a/net/quic/stream_sequencer_buffer.cc b/net/quic/quic_stream_sequencer_buffer.cc index 0582fd7..5f94085 100644 --- a/net/quic/stream_sequencer_buffer.cc +++ b/net/quic/quic_stream_sequencer_buffer.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/quic/stream_sequencer_buffer.h" +#include "net/quic/quic_stream_sequencer_buffer.h" #include "base/logging.h" #include "net/quic/quic_bug_tracker.h" @@ -11,17 +11,18 @@ using std::min; namespace net { -StreamSequencerBuffer::Gap::Gap(QuicStreamOffset begin_offset, - QuicStreamOffset end_offset) +QuicStreamSequencerBuffer::Gap::Gap(QuicStreamOffset begin_offset, + QuicStreamOffset end_offset) : begin_offset(begin_offset), end_offset(end_offset) {} -StreamSequencerBuffer::FrameInfo::FrameInfo() +QuicStreamSequencerBuffer::FrameInfo::FrameInfo() : length(1), timestamp(QuicTime::Zero()) {} -StreamSequencerBuffer::FrameInfo::FrameInfo(size_t length, QuicTime timestamp) +QuicStreamSequencerBuffer::FrameInfo::FrameInfo(size_t length, + QuicTime timestamp) : length(length), timestamp(timestamp) {} -StreamSequencerBuffer::StreamSequencerBuffer(size_t max_capacity_bytes) +QuicStreamSequencerBuffer::QuicStreamSequencerBuffer(size_t max_capacity_bytes) : max_buffer_capacity_bytes_(max_capacity_bytes), blocks_count_( ceil(static_cast<double>(max_capacity_bytes) / kBlockSizeBytes)), @@ -30,11 +31,11 @@ StreamSequencerBuffer::StreamSequencerBuffer(size_t max_capacity_bytes) Clear(); } -StreamSequencerBuffer::~StreamSequencerBuffer() { +QuicStreamSequencerBuffer::~QuicStreamSequencerBuffer() { Clear(); } -void StreamSequencerBuffer::Clear() { +void QuicStreamSequencerBuffer::Clear() { for (size_t i = 0; i < blocks_count_; ++i) { if (blocks_[i] != nullptr) { RetireBlock(i); @@ -49,24 +50,25 @@ void StreamSequencerBuffer::Clear() { frame_arrival_time_map_.clear(); } -void StreamSequencerBuffer::RetireBlock(size_t idx) { +void QuicStreamSequencerBuffer::RetireBlock(size_t idx) { DCHECK(blocks_[idx] != nullptr); delete blocks_[idx]; blocks_[idx] = nullptr; DVLOG(1) << "Retired block with index: " << idx; } -QuicErrorCode StreamSequencerBuffer::OnStreamData( +QuicErrorCode QuicStreamSequencerBuffer::OnStreamData( QuicStreamOffset starting_offset, base::StringPiece data, QuicTime timestamp, - size_t* const bytes_buffered) { + size_t* const bytes_buffered, + std::string* error_details) { *bytes_buffered = 0; QuicStreamOffset offset = starting_offset; size_t size = data.size(); if (size == 0) { - QUIC_BUG << "Attempted to write 0 bytes of data."; - return QUIC_INVALID_STREAM_FRAME; + *error_details = "Received empty stream frame without FIN."; + return QUIC_EMPTY_STREAM_FRAME_NO_FIN; } // Find the first gap not ending before |offset|. This gap maybe the gap to @@ -90,15 +92,18 @@ QuicErrorCode StreamSequencerBuffer::OnStreamData( if (offset < current_gap->begin_offset && offset + size > current_gap->begin_offset) { // Beginning of new data overlaps data before current gap. - return QUIC_INVALID_STREAM_DATA; + *error_details = "Beginning of received data overlaps with buffered data."; + return QUIC_OVERLAPPING_STREAM_DATA; } if (offset + size > current_gap->end_offset) { // End of new data overlaps with data after current gap. - return QUIC_INVALID_STREAM_DATA; + *error_details = "End of received data overlaps with buffered data."; + return QUIC_OVERLAPPING_STREAM_DATA; } // Write beyond the current range this buffer is covering. if (offset + size > total_bytes_read_ + max_buffer_capacity_bytes_) { + *error_details = "Received data beyond available range."; return QUIC_INTERNAL_ERROR; } @@ -148,7 +153,7 @@ QuicErrorCode StreamSequencerBuffer::OnStreamData( return QUIC_NO_ERROR; } -inline void StreamSequencerBuffer::UpdateGapList( +inline void QuicStreamSequencerBuffer::UpdateGapList( std::list<Gap>::iterator gap_with_new_data_written, QuicStreamOffset start_offset, size_t bytes_written) { @@ -178,7 +183,8 @@ inline void StreamSequencerBuffer::UpdateGapList( } } -size_t StreamSequencerBuffer::Readv(const iovec* dest_iov, size_t dest_count) { +size_t QuicStreamSequencerBuffer::Readv(const iovec* dest_iov, + size_t dest_count) { size_t bytes_read = 0; for (size_t i = 0; i < dest_count && ReadableBytes() > 0; ++i) { char* dest = reinterpret_cast<char*>(dest_iov[i].iov_base); @@ -215,8 +221,8 @@ size_t StreamSequencerBuffer::Readv(const iovec* dest_iov, size_t dest_count) { return bytes_read; } -int StreamSequencerBuffer::GetReadableRegions(struct iovec* iov, - int iov_count) const { +int QuicStreamSequencerBuffer::GetReadableRegions(struct iovec* iov, + int iov_count) const { DCHECK(iov != nullptr); DCHECK_GT(iov_count, 0); @@ -273,8 +279,8 @@ int StreamSequencerBuffer::GetReadableRegions(struct iovec* iov, return iov_used; } -bool StreamSequencerBuffer::GetReadableRegion(iovec* iov, - QuicTime* timestamp) const { +bool QuicStreamSequencerBuffer::GetReadableRegion(iovec* iov, + QuicTime* timestamp) const { if (ReadableBytes() == 0) { iov[0].iov_base = nullptr; iov[0].iov_len = 0; @@ -312,7 +318,7 @@ bool StreamSequencerBuffer::GetReadableRegion(iovec* iov, return true; } -bool StreamSequencerBuffer::MarkConsumed(size_t bytes_used) { +bool QuicStreamSequencerBuffer::MarkConsumed(size_t bytes_used) { if (bytes_used > ReadableBytes()) { return false; } @@ -338,46 +344,47 @@ bool StreamSequencerBuffer::MarkConsumed(size_t bytes_used) { return true; } -size_t StreamSequencerBuffer::FlushBufferedFrames() { +size_t QuicStreamSequencerBuffer::FlushBufferedFrames() { size_t prev_total_bytes_read = total_bytes_read_; total_bytes_read_ = gaps_.back().begin_offset; Clear(); return total_bytes_read_ - prev_total_bytes_read; } -size_t StreamSequencerBuffer::ReadableBytes() const { +size_t QuicStreamSequencerBuffer::ReadableBytes() const { return gaps_.front().begin_offset - total_bytes_read_; } -bool StreamSequencerBuffer::HasBytesToRead() const { +bool QuicStreamSequencerBuffer::HasBytesToRead() const { return ReadableBytes() > 0; } -QuicStreamOffset StreamSequencerBuffer::BytesConsumed() const { +QuicStreamOffset QuicStreamSequencerBuffer::BytesConsumed() const { return total_bytes_read_; } -size_t StreamSequencerBuffer::BytesBuffered() const { +size_t QuicStreamSequencerBuffer::BytesBuffered() const { return num_bytes_buffered_; } -size_t StreamSequencerBuffer::GetBlockIndex(QuicStreamOffset offset) const { +size_t QuicStreamSequencerBuffer::GetBlockIndex(QuicStreamOffset offset) const { return (offset % max_buffer_capacity_bytes_) / kBlockSizeBytes; } -size_t StreamSequencerBuffer::GetInBlockOffset(QuicStreamOffset offset) const { +size_t QuicStreamSequencerBuffer::GetInBlockOffset( + QuicStreamOffset offset) const { return (offset % max_buffer_capacity_bytes_) % kBlockSizeBytes; } -size_t StreamSequencerBuffer::ReadOffset() const { +size_t QuicStreamSequencerBuffer::ReadOffset() const { return GetInBlockOffset(total_bytes_read_); } -size_t StreamSequencerBuffer::NextBlockToRead() const { +size_t QuicStreamSequencerBuffer::NextBlockToRead() const { return GetBlockIndex(total_bytes_read_); } -void StreamSequencerBuffer::RetireBlockIfEmpty(size_t block_index) { +void QuicStreamSequencerBuffer::RetireBlockIfEmpty(size_t block_index) { DCHECK(ReadableBytes() == 0 || GetInBlockOffset(total_bytes_read_) == 0) << "RetireBlockIfEmpty() should only be called when advancing to next " "block" @@ -411,11 +418,11 @@ void StreamSequencerBuffer::RetireBlockIfEmpty(size_t block_index) { RetireBlock(block_index); } -bool StreamSequencerBuffer::Empty() const { +bool QuicStreamSequencerBuffer::Empty() const { return gaps_.size() == 1 && gaps_.front().begin_offset == total_bytes_read_; } -size_t StreamSequencerBuffer::GetBlockCapacity(size_t block_index) const { +size_t QuicStreamSequencerBuffer::GetBlockCapacity(size_t block_index) const { if ((block_index + 1) == blocks_count_) { size_t result = max_buffer_capacity_bytes_ % kBlockSizeBytes; if (result == 0) { // whole block @@ -427,7 +434,7 @@ size_t StreamSequencerBuffer::GetBlockCapacity(size_t block_index) const { } } -void StreamSequencerBuffer::UpdateFrameArrivalMap(QuicStreamOffset offset) { +void QuicStreamSequencerBuffer::UpdateFrameArrivalMap(QuicStreamOffset offset) { // Get the frame before which all frames should be removed. auto next_frame = frame_arrival_time_map_.upper_bound(offset); DCHECK(next_frame != frame_arrival_time_map_.begin()); diff --git a/net/quic/stream_sequencer_buffer.h b/net/quic/quic_stream_sequencer_buffer.h index 93dd57c..2a59041 100644 --- a/net/quic/stream_sequencer_buffer.h +++ b/net/quic/quic_stream_sequencer_buffer.h @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_QUIC_STREAM_SEQUENCER_BUFFER_H_ -#define NET_QUIC_STREAM_SEQUENCER_BUFFER_H_ +#ifndef NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_H_ +#define NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_H_ -// StreamSequencerBuffer implements QuicStreamSequencerBufferInterface. +// QuicStreamSequencerBuffer implements QuicStreamSequencerBufferInterface. // It is a circular stream buffer with random write and // in-sequence read. It consists of a vector of pointers pointing // to memory blocks created as needed and a list of Gaps to indicate @@ -20,14 +20,14 @@ // // This class is thread-unsafe. // -// StreamSequencerBuffer maintains a concept of the readable region, which +// QuicStreamSequencerBuffer maintains a concept of the readable region, which // contains all written data that has not been read. // It promises stability of the underlying memory addresses in the readable // region, so pointers into it can be maintained, and the offset of a pointer // from the start of the read region can be calculated. // // Expected Use: -// StreamSequencerBuffer buffer(2.5 * 8 * 1024); +// QuicStreamSequencerBuffer buffer(2.5 * 8 * 1024); // std::string source(1024, 'a'); // base::StringPiece std::string_piece(source.data(), source.size()); // size_t written = 0; @@ -68,16 +68,16 @@ #include "base/macros.h" #include "net/quic/quic_protocol.h" -#include "net/quic/quic_stream_sequencer_buffer_interface.h" + +using base::StringPiece; namespace net { namespace test { -class StreamSequencerBufferPeer; +class QuicStreamSequencerBufferPeer; } // namespace test -class NET_EXPORT_PRIVATE StreamSequencerBuffer - : public QuicStreamSequencerBufferInterface { +class NET_EXPORT_PRIVATE QuicStreamSequencerBuffer { public: // A Gap indicates a missing chunk of bytes between // [begin_offset, end_offset) in the stream @@ -106,28 +106,65 @@ class NET_EXPORT_PRIVATE StreamSequencerBuffer char buffer[kBlockSizeBytes]; }; - explicit StreamSequencerBuffer(size_t max_capacity_bytes); + explicit QuicStreamSequencerBuffer(size_t max_capacity_bytes); + ~QuicStreamSequencerBuffer(); + + // Free the space used to buffer data. + void Clear(); - ~StreamSequencerBuffer() override; + // Returns true if there is nothing to read in this buffer. + bool Empty() const; - // QuicStreamSequencerBufferInterface implementation. - void Clear() override; - bool Empty() const override; + // Called to buffer new data received for this stream. If the data was + // successfully buffered, returns QUIC_NO_ERROR and stores the number of + // bytes buffered in |bytes_buffered|. Returns an error otherwise. + // |timestamp| is the time the data arrived. QuicErrorCode OnStreamData(QuicStreamOffset offset, base::StringPiece data, QuicTime timestamp, - size_t* bytes_buffered) override; - size_t Readv(const struct iovec* dest_iov, size_t dest_count) override; - int GetReadableRegions(struct iovec* iov, int iov_len) const override; - bool GetReadableRegion(iovec* iov, QuicTime* timestamp) const override; - bool MarkConsumed(size_t bytes_buffered) override; - size_t FlushBufferedFrames() override; - bool HasBytesToRead() const override; - QuicStreamOffset BytesConsumed() const override; - size_t BytesBuffered() const override; + size_t* bytes_buffered, + std::string* error_details); + + // Reads from this buffer into given iovec array, up to number of iov_len + // iovec objects and returns the number of bytes read. + size_t Readv(const struct iovec* dest_iov, size_t dest_count); + + // Returns the readable region of valid data in iovec format. The readable + // region is the buffer region where there is valid data not yet read by + // client. + // Returns the number of iovec entries in |iov| which were populated. + // If the region is empty, one iovec entry with 0 length + // is returned, and the function returns 0. If there are more readable + // regions than iov_size, the function only processes the first + // iov_size of them. + int GetReadableRegions(struct iovec* iov, int iov_len) const; + + // Fills in one iovec with data which all arrived at the same time from the + // next readable region. + // Populates |timestamp| with the time that this data arrived. + // Returns false if there is no readable region available. + bool GetReadableRegion(iovec* iov, QuicTime* timestamp) const; + + // Called after GetReadableRegions() to free up |bytes_used| space if these + // bytes are processed. + // Pre-requisite: bytes_used <= available bytes to read. + bool MarkConsumed(size_t bytes_buffered); + + // Deletes and records as consumed any buffered data and clear the buffer. + // (To be called only after sequencer's StopReading has been called.) + size_t FlushBufferedFrames(); + + // Whether there are bytes can be read out. + bool HasBytesToRead() const; + + // Count how many bytes have been consumed (read out of buffer). + QuicStreamOffset BytesConsumed() const; + + // Count how many bytes are in buffer at this moment. + size_t BytesBuffered() const; private: - friend class test::StreamSequencerBufferPeer; + friend class test::QuicStreamSequencerBufferPeer; // Dispose the given buffer block. // After calling this method, blocks_[index] is set to nullptr @@ -196,8 +233,8 @@ class NET_EXPORT_PRIVATE StreamSequencerBuffer // Stores all the buffered frames' start offset, length and arrival time. std::map<QuicStreamOffset, FrameInfo> frame_arrival_time_map_; - DISALLOW_COPY_AND_ASSIGN(StreamSequencerBuffer); + DISALLOW_COPY_AND_ASSIGN(QuicStreamSequencerBuffer); }; } // namespace net -#endif // NET_QUIC_STREAM_SEQUENCER_BUFFER_H_ +#endif // NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_H_ diff --git a/net/quic/stream_sequencer_buffer_test.cc b/net/quic/quic_stream_sequencer_buffer_test.cc index 348205f..5d9bda8 100644 --- a/net/quic/stream_sequencer_buffer_test.cc +++ b/net/quic/quic_stream_sequencer_buffer_test.cc @@ -1,8 +1,7 @@ // Copyright (c) 2015 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/stream_sequencer_buffer.h" +#include "net/quic/quic_stream_sequencer_buffer.h" #include "base/logging.h" #include "base/macros.h" @@ -41,14 +40,15 @@ char GetCharFromIOVecs(size_t offset, iovec iov[], size_t count) { return '\0'; } -static const size_t kBlockSizeBytes = StreamSequencerBuffer::kBlockSizeBytes; -typedef StreamSequencerBuffer::BufferBlock BufferBlock; -typedef StreamSequencerBuffer::Gap Gap; -typedef StreamSequencerBuffer::FrameInfo FrameInfo; +static const size_t kBlockSizeBytes = + QuicStreamSequencerBuffer::kBlockSizeBytes; +typedef QuicStreamSequencerBuffer::BufferBlock BufferBlock; +typedef QuicStreamSequencerBuffer::Gap Gap; +typedef QuicStreamSequencerBuffer::FrameInfo FrameInfo; -class StreamSequencerBufferPeer { +class QuicStreamSequencerBufferPeer { public: - explicit StreamSequencerBufferPeer(StreamSequencerBuffer* buffer) + explicit QuicStreamSequencerBufferPeer(QuicStreamSequencerBuffer* buffer) : buffer_(buffer) {} // Read from this buffer_->into the given destination buffer_-> up to the @@ -142,12 +142,12 @@ class StreamSequencerBufferPeer { void set_gaps(const std::list<Gap>& gaps) { buffer_->gaps_ = gaps; } private: - StreamSequencerBuffer* buffer_; + QuicStreamSequencerBuffer* buffer_; }; namespace { -class StreamSequencerBufferTest : public testing::Test { +class QuicStreamSequencerBufferTest : public testing::Test { public: void SetUp() override { Initialize(); } @@ -158,8 +158,8 @@ class StreamSequencerBufferTest : public testing::Test { protected: void Initialize() { - buffer_.reset(new StreamSequencerBuffer(max_capacity_bytes_)); - helper_.reset(new StreamSequencerBufferPeer(buffer_.get())); + buffer_.reset(new QuicStreamSequencerBuffer(max_capacity_bytes_)); + helper_.reset(new QuicStreamSequencerBufferPeer(buffer_.get())); } // Use 2.5 here to make sure the buffer has more than one block and its end @@ -168,42 +168,43 @@ class StreamSequencerBufferTest : public testing::Test { size_t max_capacity_bytes_ = 2.5 * kBlockSizeBytes; MockClock clock_; - std::unique_ptr<StreamSequencerBuffer> buffer_; - std::unique_ptr<StreamSequencerBufferPeer> helper_; + std::unique_ptr<QuicStreamSequencerBuffer> buffer_; + std::unique_ptr<QuicStreamSequencerBufferPeer> helper_; + string error_details_; }; -TEST_F(StreamSequencerBufferTest, InitializationWithDifferentSizes) { - const size_t kCapacity = 2 * StreamSequencerBuffer::kBlockSizeBytes; +TEST_F(QuicStreamSequencerBufferTest, InitializationWithDifferentSizes) { + const size_t kCapacity = 2 * QuicStreamSequencerBuffer::kBlockSizeBytes; ResetMaxCapacityBytes(kCapacity); EXPECT_EQ(max_capacity_bytes_, helper_->max_buffer_capacity()); EXPECT_TRUE(helper_->CheckInitialState()); - const size_t kCapacity1 = 8 * StreamSequencerBuffer::kBlockSizeBytes; + const size_t kCapacity1 = 8 * QuicStreamSequencerBuffer::kBlockSizeBytes; ResetMaxCapacityBytes(kCapacity1); EXPECT_EQ(kCapacity1, helper_->max_buffer_capacity()); EXPECT_TRUE(helper_->CheckInitialState()); } -TEST_F(StreamSequencerBufferTest, ClearOnEmpty) { +TEST_F(QuicStreamSequencerBufferTest, ClearOnEmpty) { buffer_->Clear(); EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, OnStreamData0length) { - std::string source; +TEST_F(QuicStreamSequencerBufferTest, OnStreamData0length) { size_t written; - EXPECT_DFATAL( - buffer_->OnStreamData(800, source, clock_.ApproximateNow(), &written), - "Attempted to write 0 bytes of data."); + QuicErrorCode error = buffer_->OnStreamData(800, "", clock_.ApproximateNow(), + &written, &error_details_); + EXPECT_EQ(error, QUIC_EMPTY_STREAM_FRAME_NO_FIN); EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, OnStreamDataWithinBlock) { +TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithinBlock) { std::string source(1024, 'a'); size_t written; clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); QuicTime t = clock_.ApproximateNow(); - EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(800, source, t, &written)); + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(800, source, t, &written, &error_details_)); BufferBlock* block_ptr = helper_->GetBlock(0); for (size_t i = 0; i < source.size(); ++i) { ASSERT_EQ('a', block_ptr->buffer[helper_->GetInBlockOffset(800) + i]); @@ -219,71 +220,77 @@ TEST_F(StreamSequencerBufferTest, OnStreamDataWithinBlock) { EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, OnStreamDataWithOverlap) { +TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithOverlap) { std::string source(1024, 'a'); // Write something into [800, 1824) size_t written; clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); QuicTime t1 = clock_.ApproximateNow(); - EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(800, source, t1, &written)); + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(800, source, t1, &written, &error_details_)); // Try to write to [0, 1024) and [1024, 2048). // But no byte will be written since overlap. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); QuicTime t2 = clock_.ApproximateNow(); - EXPECT_EQ(QUIC_INVALID_STREAM_DATA, - buffer_->OnStreamData(0, source, t2, &written)); - EXPECT_EQ(QUIC_INVALID_STREAM_DATA, - buffer_->OnStreamData(1024, source, t2, &written)); + EXPECT_EQ(QUIC_OVERLAPPING_STREAM_DATA, + buffer_->OnStreamData(0, source, t2, &written, &error_details_)); + EXPECT_EQ(QUIC_OVERLAPPING_STREAM_DATA, + buffer_->OnStreamData(1024, source, t2, &written, &error_details_)); auto frame_map = helper_->frame_arrival_time_map(); EXPECT_EQ(1u, frame_map->size()); EXPECT_EQ(t1, (*frame_map)[800].timestamp); } -TEST_F(StreamSequencerBufferTest, OnStreamDataOverlapAndDuplicateCornerCases) { +TEST_F(QuicStreamSequencerBufferTest, + OnStreamDataOverlapAndDuplicateCornerCases) { std::string source(1024, 'a'); // Write something into [800, 1824) size_t written; - buffer_->OnStreamData(800, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(800, source, clock_.ApproximateNow(), &written, + &error_details_); source = std::string(800, 'b'); // Try to write to [1, 801), but should fail due to overlapping - EXPECT_EQ( - QUIC_INVALID_STREAM_DATA, - buffer_->OnStreamData(1, source, clock_.ApproximateNow(), &written)); + EXPECT_EQ(QUIC_OVERLAPPING_STREAM_DATA, + buffer_->OnStreamData(1, source, clock_.ApproximateNow(), &written, + &error_details_)); // write to [0, 800) - EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData( - 0, source, clock_.ApproximateNow(), &written)); + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, + &error_details_)); // Try to write one byte to [1823, 1824), but should count as duplicate std::string one_byte = "c"; - EXPECT_EQ( - QUIC_NO_ERROR, - buffer_->OnStreamData(1823, one_byte, clock_.ApproximateNow(), &written)); + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(1823, one_byte, clock_.ApproximateNow(), + &written, &error_details_)); EXPECT_EQ(0u, written); // write one byte to [1824, 1825) - EXPECT_EQ( - QUIC_NO_ERROR, - buffer_->OnStreamData(1824, one_byte, clock_.ApproximateNow(), &written)); + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(1824, one_byte, clock_.ApproximateNow(), + &written, &error_details_)); auto frame_map = helper_->frame_arrival_time_map(); EXPECT_EQ(3u, frame_map->size()); EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, OnStreamDataWithoutOverlap) { +TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithoutOverlap) { std::string source(1024, 'a'); // Write something into [800, 1824). size_t written; - EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData( - 800, source, clock_.ApproximateNow(), &written)); + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(800, source, clock_.ApproximateNow(), + &written, &error_details_)); source = std::string(100, 'b'); // Write something into [kBlockSizeBytes * 2 - 20, kBlockSizeBytes * 2 + 80). EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(kBlockSizeBytes * 2 - 20, source, - clock_.ApproximateNow(), &written)); + clock_.ApproximateNow(), &written, + &error_details_)); EXPECT_EQ(3, helper_->GapSize()); EXPECT_EQ(1024u + 100u, buffer_->BytesBuffered()); EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, OnStreamDataInLongStreamWithOverlap) { +TEST_F(QuicStreamSequencerBufferTest, OnStreamDataInLongStreamWithOverlap) { // Assume a stream has already buffered almost 4GB. uint64_t total_bytes_read = pow(2, 32) - 1; helper_->set_total_bytes_read(total_bytes_read); @@ -296,84 +303,89 @@ TEST_F(StreamSequencerBufferTest, OnStreamDataInLongStreamWithOverlap) { size_t written; // Frame [2^32 + 500, 2^32 + 600). QuicStreamOffset offset = pow(2, 32) + 500; - EXPECT_EQ( - QUIC_NO_ERROR, - buffer_->OnStreamData(offset, source, clock_.ApproximateNow(), &written)); + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(offset, source, clock_.ApproximateNow(), + &written, &error_details_)); EXPECT_EQ(2, helper_->GapSize()); // Frame [2^32 + 700, 2^32 + 800). offset = pow(2, 32) + 700; - EXPECT_EQ( - QUIC_NO_ERROR, - buffer_->OnStreamData(offset, source, clock_.ApproximateNow(), &written)); + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(offset, source, clock_.ApproximateNow(), + &written, &error_details_)); EXPECT_EQ(3, helper_->GapSize()); // Another frame [2^32 + 300, 2^32 + 400). offset = pow(2, 32) + 300; - EXPECT_EQ( - QUIC_NO_ERROR, - buffer_->OnStreamData(offset, source, clock_.ApproximateNow(), &written)); + EXPECT_EQ(QUIC_NO_ERROR, + buffer_->OnStreamData(offset, source, clock_.ApproximateNow(), + &written, &error_details_)); EXPECT_EQ(4, helper_->GapSize()); } -TEST_F(StreamSequencerBufferTest, OnStreamDataTillEnd) { +TEST_F(QuicStreamSequencerBufferTest, OnStreamDataTillEnd) { // Write 50 bytes to the end. const size_t kBytesToWrite = 50; std::string source(kBytesToWrite, 'a'); size_t written; EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(max_capacity_bytes_ - kBytesToWrite, source, - clock_.ApproximateNow(), &written)); + clock_.ApproximateNow(), &written, + &error_details_)); EXPECT_EQ(50u, buffer_->BytesBuffered()); EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, OnStreamDataTillEndCorner) { +TEST_F(QuicStreamSequencerBufferTest, OnStreamDataTillEndCorner) { // Write 1 byte to the end. const size_t kBytesToWrite = 1; std::string source(kBytesToWrite, 'a'); size_t written; EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(max_capacity_bytes_ - kBytesToWrite, source, - clock_.ApproximateNow(), &written)); + clock_.ApproximateNow(), &written, + &error_details_)); EXPECT_EQ(1u, buffer_->BytesBuffered()); EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, OnStreamDataBeyondCapacity) { +TEST_F(QuicStreamSequencerBufferTest, OnStreamDataBeyondCapacity) { std::string source(60, 'a'); size_t written; EXPECT_EQ(QUIC_INTERNAL_ERROR, buffer_->OnStreamData(max_capacity_bytes_ - 50, source, - clock_.ApproximateNow(), &written)); + clock_.ApproximateNow(), &written, + &error_details_)); EXPECT_TRUE(helper_->CheckBufferInvariants()); source = "b"; EXPECT_EQ(QUIC_INTERNAL_ERROR, buffer_->OnStreamData(max_capacity_bytes_, source, - clock_.ApproximateNow(), &written)); + clock_.ApproximateNow(), &written, + &error_details_)); EXPECT_TRUE(helper_->CheckBufferInvariants()); EXPECT_EQ(QUIC_INTERNAL_ERROR, buffer_->OnStreamData(max_capacity_bytes_ * 1000, source, - clock_.ApproximateNow(), &written)); + clock_.ApproximateNow(), &written, + &error_details_)); EXPECT_TRUE(helper_->CheckBufferInvariants()); EXPECT_EQ(0u, buffer_->BytesBuffered()); } -TEST_F(StreamSequencerBufferTest, Readv100Bytes) { +TEST_F(QuicStreamSequencerBufferTest, Readv100Bytes) { std::string source(1024, 'a'); clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); QuicTime t1 = clock_.ApproximateNow(); // Write something into [kBlockSizeBytes, kBlockSizeBytes + 1024). size_t written; - buffer_->OnStreamData(kBlockSizeBytes, source, t1, &written); + buffer_->OnStreamData(kBlockSizeBytes, source, t1, &written, &error_details_); EXPECT_FALSE(buffer_->HasBytesToRead()); source = std::string(100, 'b'); clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); QuicTime t2 = clock_.ApproximateNow(); // Write something into [0, 100). - buffer_->OnStreamData(0, source, t2, &written); + buffer_->OnStreamData(0, source, t2, &written, &error_details_); EXPECT_TRUE(buffer_->HasBytesToRead()); EXPECT_EQ(2u, helper_->frame_arrival_time_map()->size()); // Read into a iovec array with total capacity of 120 bytes. @@ -387,11 +399,12 @@ TEST_F(StreamSequencerBufferTest, Readv100Bytes) { EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, ReadvAcrossBlocks) { +TEST_F(QuicStreamSequencerBufferTest, ReadvAcrossBlocks) { std::string source(kBlockSizeBytes + 50, 'a'); // Write 1st block to full and extand 50 bytes to next block. size_t written; - buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, + &error_details_); EXPECT_EQ(source.size(), helper_->ReadableBytes()); // Iteratively read 512 bytes from buffer_-> Overwrite dest[] each time. char dest[512]; @@ -408,11 +421,12 @@ TEST_F(StreamSequencerBufferTest, ReadvAcrossBlocks) { EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, ClearAfterRead) { +TEST_F(QuicStreamSequencerBufferTest, ClearAfterRead) { std::string source(kBlockSizeBytes + 50, 'a'); // Write 1st block to full with 'a'. size_t written; - buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, + &error_details_); // Read first 512 bytes from buffer to make space at the beginning. char dest[512]{0}; const iovec iov{dest, 512}; @@ -423,11 +437,13 @@ TEST_F(StreamSequencerBufferTest, ClearAfterRead) { EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, OnStreamDataAcrossLastBlockAndFillCapacity) { +TEST_F(QuicStreamSequencerBufferTest, + OnStreamDataAcrossLastBlockAndFillCapacity) { std::string source(kBlockSizeBytes + 50, 'a'); // Write 1st block to full with 'a'. size_t written; - buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, + &error_details_); // Read first 512 bytes from buffer to make space at the beginning. char dest[512]{0}; const iovec iov{dest, 512}; @@ -437,19 +453,20 @@ TEST_F(StreamSequencerBufferTest, OnStreamDataAcrossLastBlockAndFillCapacity) { // Write more than half block size of bytes in the last block with 'b', which // will wrap to the beginning and reaches the full capacity. source = std::string(0.5 * kBlockSizeBytes + 512, 'b'); - EXPECT_EQ(QUIC_NO_ERROR, - buffer_->OnStreamData(2 * kBlockSizeBytes, source, - clock_.ApproximateNow(), &written)); + EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(2 * kBlockSizeBytes, source, + clock_.ApproximateNow(), + &written, &error_details_)); EXPECT_EQ(source.size(), written); EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, +TEST_F(QuicStreamSequencerBufferTest, OnStreamDataAcrossLastBlockAndExceedCapacity) { std::string source(kBlockSizeBytes + 50, 'a'); // Write 1st block to full. size_t written; - buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, + &error_details_); // Read first 512 bytes from buffer to make space at the beginning. char dest[512]{0}; const iovec iov{dest, 512}; @@ -460,25 +477,27 @@ TEST_F(StreamSequencerBufferTest, source = std::string(0.5 * kBlockSizeBytes + 512 + 1, 'b'); EXPECT_EQ(QUIC_INTERNAL_ERROR, buffer_->OnStreamData(2 * kBlockSizeBytes, source, - clock_.ApproximateNow(), &written)); + clock_.ApproximateNow(), &written, + &error_details_)); EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, ReadvAcrossLastBlock) { +TEST_F(QuicStreamSequencerBufferTest, ReadvAcrossLastBlock) { // Write to full capacity and read out 512 bytes at beginning and continue // appending 256 bytes. std::string source(max_capacity_bytes_, 'a'); clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); QuicTime t = clock_.ApproximateNow(); size_t written; - buffer_->OnStreamData(0, source, t, &written); + buffer_->OnStreamData(0, source, t, &written, &error_details_); char dest[512]{0}; const iovec iov{dest, 512}; buffer_->Readv(&iov, 1); source = std::string(256, 'b'); clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); QuicTime t2 = clock_.ApproximateNow(); - buffer_->OnStreamData(max_capacity_bytes_, source, t2, &written); + buffer_->OnStreamData(max_capacity_bytes_, source, t2, &written, + &error_details_); EXPECT_TRUE(helper_->CheckBufferInvariants()); EXPECT_EQ(2u, helper_->frame_arrival_time_map()->size()); @@ -492,7 +511,7 @@ TEST_F(StreamSequencerBufferTest, ReadvAcrossLastBlock) { EXPECT_EQ(0u, helper_->frame_arrival_time_map()->size()); } -TEST_F(StreamSequencerBufferTest, ReadvEmpty) { +TEST_F(QuicStreamSequencerBufferTest, ReadvEmpty) { char dest[512]{0}; iovec iov{dest, 512}; size_t read = buffer_->Readv(&iov, 1); @@ -500,7 +519,7 @@ TEST_F(StreamSequencerBufferTest, ReadvEmpty) { EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, GetReadableRegionsEmpty) { +TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionsEmpty) { iovec iovs[2]; int iov_count = buffer_->GetReadableRegions(iovs, 2); EXPECT_EQ(0, iov_count); @@ -508,23 +527,25 @@ TEST_F(StreamSequencerBufferTest, GetReadableRegionsEmpty) { EXPECT_EQ(0u, iovs[iov_count].iov_len); } -TEST_F(StreamSequencerBufferTest, GetReadableRegionsBlockedByGap) { +TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionsBlockedByGap) { // Write into [1, 1024). std::string source(1023, 'a'); size_t written; - buffer_->OnStreamData(1, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(1, source, clock_.ApproximateNow(), &written, + &error_details_); // Try to get readable regions, but none is there. iovec iovs[2]; int iov_count = buffer_->GetReadableRegions(iovs, 2); EXPECT_EQ(0, iov_count); } -TEST_F(StreamSequencerBufferTest, GetReadableRegionsTillEndOfBlock) { +TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionsTillEndOfBlock) { // Write first block to full with [0, 256) 'a' and the rest 'b' then read out // [0, 256) std::string source(kBlockSizeBytes, 'a'); size_t written; - buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, + &error_details_); char dest[256]; helper_->Read(dest, 256); // Get readable region from [256, 1024) @@ -536,11 +557,12 @@ TEST_F(StreamSequencerBufferTest, GetReadableRegionsTillEndOfBlock) { iovs[0].iov_len)); } -TEST_F(StreamSequencerBufferTest, GetReadableRegionsWithinOneBlock) { +TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionsWithinOneBlock) { // Write into [0, 1024) and then read out [0, 256) std::string source(1024, 'a'); size_t written; - buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, + &error_details_); char dest[256]; helper_->Read(dest, 256); // Get readable region from [256, 1024) @@ -552,11 +574,13 @@ TEST_F(StreamSequencerBufferTest, GetReadableRegionsWithinOneBlock) { iovs[0].iov_len)); } -TEST_F(StreamSequencerBufferTest, GetReadableRegionsAcrossBlockWithLongIOV) { +TEST_F(QuicStreamSequencerBufferTest, + GetReadableRegionsAcrossBlockWithLongIOV) { // Write into [0, 2 * kBlockSizeBytes + 1024) and then read out [0, 1024) std::string source(2 * kBlockSizeBytes + 1024, 'a'); size_t written; - buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, + &error_details_); char dest[1024]; helper_->Read(dest, 1024); @@ -568,18 +592,20 @@ TEST_F(StreamSequencerBufferTest, GetReadableRegionsAcrossBlockWithLongIOV) { EXPECT_EQ(1024u, iovs[2].iov_len); } -TEST_F(StreamSequencerBufferTest, GetReadableRegionsWithMultipleIOVsAcrossEnd) { +TEST_F(QuicStreamSequencerBufferTest, + GetReadableRegionsWithMultipleIOVsAcrossEnd) { // Write into [0, 2 * kBlockSizeBytes + 1024) and then read out [0, 1024) // and then append 1024 + 512 bytes. std::string source(2.5 * kBlockSizeBytes - 1024, 'a'); size_t written; - buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, + &error_details_); char dest[1024]; helper_->Read(dest, 1024); // Write across the end. source = std::string(1024 + 512, 'b'); buffer_->OnStreamData(2.5 * kBlockSizeBytes - 1024, source, - clock_.ApproximateNow(), &written); + clock_.ApproximateNow(), &written, &error_details_); // Use short iovec's. iovec iovs[2]; int iov_count = buffer_->GetReadableRegions(iovs, 2); @@ -596,7 +622,7 @@ TEST_F(StreamSequencerBufferTest, GetReadableRegionsWithMultipleIOVsAcrossEnd) { iovs1[3].iov_len)); } -TEST_F(StreamSequencerBufferTest, GetReadableRegionEmpty) { +TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionEmpty) { iovec iov; QuicTime t = QuicTime::Zero(); EXPECT_FALSE(buffer_->GetReadableRegion(&iov, &t)); @@ -604,11 +630,12 @@ TEST_F(StreamSequencerBufferTest, GetReadableRegionEmpty) { EXPECT_EQ(0u, iov.iov_len); } -TEST_F(StreamSequencerBufferTest, GetReadableRegionBeforeGap) { +TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionBeforeGap) { // Write into [1, 1024). std::string source(1023, 'a'); size_t written; - buffer_->OnStreamData(1, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(1, source, clock_.ApproximateNow(), &written, + &error_details_); // GetReadableRegion should return false because range [0,1) hasn't been // filled yet. iovec iov; @@ -616,13 +643,13 @@ TEST_F(StreamSequencerBufferTest, GetReadableRegionBeforeGap) { EXPECT_FALSE(buffer_->GetReadableRegion(&iov, &t)); } -TEST_F(StreamSequencerBufferTest, GetReadableRegionTillEndOfBlock) { +TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionTillEndOfBlock) { // Write into [0, kBlockSizeBytes + 1) and then read out [0, 256) std::string source(kBlockSizeBytes + 1, 'a'); size_t written; clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); QuicTime t = clock_.ApproximateNow(); - buffer_->OnStreamData(0, source, t, &written); + buffer_->OnStreamData(0, source, t, &written, &error_details_); char dest[256]; helper_->Read(dest, 256); // Get readable region from [256, 1024) @@ -635,13 +662,13 @@ TEST_F(StreamSequencerBufferTest, GetReadableRegionTillEndOfBlock) { std::string(reinterpret_cast<const char*>(iov.iov_base), iov.iov_len)); } -TEST_F(StreamSequencerBufferTest, GetReadableRegionTillGap) { +TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionTillGap) { // Write into [0, kBlockSizeBytes - 1) and then read out [0, 256) std::string source(kBlockSizeBytes - 1, 'a'); size_t written; clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); QuicTime t = clock_.ApproximateNow(); - buffer_->OnStreamData(0, source, t, &written); + buffer_->OnStreamData(0, source, t, &written, &error_details_); char dest[256]; helper_->Read(dest, 256); // Get readable region from [256, 1023) @@ -654,25 +681,27 @@ TEST_F(StreamSequencerBufferTest, GetReadableRegionTillGap) { std::string(reinterpret_cast<const char*>(iov.iov_base), iov.iov_len)); } -TEST_F(StreamSequencerBufferTest, GetReadableRegionByArrivalTime) { +TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionByArrivalTime) { // Write into [0, kBlockSizeBytes - 100) and then read out [0, 256) std::string source(kBlockSizeBytes - 100, 'a'); size_t written; clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); QuicTime t = clock_.ApproximateNow(); - buffer_->OnStreamData(0, source, t, &written); + buffer_->OnStreamData(0, source, t, &written, &error_details_); char dest[256]; helper_->Read(dest, 256); // Write into [kBlockSizeBytes - 100, kBlockSizeBytes - 50)] in same time std::string source2(50, 'b'); clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); - buffer_->OnStreamData(kBlockSizeBytes - 100, source2, t, &written); + buffer_->OnStreamData(kBlockSizeBytes - 100, source2, t, &written, + &error_details_); // Write into [kBlockSizeBytes - 50, kBlockSizeBytes)] in another time std::string source3(50, 'c'); clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); QuicTime t3 = clock_.ApproximateNow(); - buffer_->OnStreamData(kBlockSizeBytes - 50, source3, t3, &written); + buffer_->OnStreamData(kBlockSizeBytes - 50, source3, t3, &written, + &error_details_); // Get readable region from [256, 1024 - 50) iovec iov; @@ -684,11 +713,12 @@ TEST_F(StreamSequencerBufferTest, GetReadableRegionByArrivalTime) { std::string(reinterpret_cast<const char*>(iov.iov_base), iov.iov_len)); } -TEST_F(StreamSequencerBufferTest, MarkConsumedInOneBlock) { +TEST_F(QuicStreamSequencerBufferTest, MarkConsumedInOneBlock) { // Write into [0, 1024) and then read out [0, 256) std::string source(1024, 'a'); size_t written; - buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, + &error_details_); char dest[256]; helper_->Read(dest, 256); @@ -702,12 +732,12 @@ TEST_F(StreamSequencerBufferTest, MarkConsumedInOneBlock) { EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, MarkConsumedNotEnoughBytes) { +TEST_F(QuicStreamSequencerBufferTest, MarkConsumedNotEnoughBytes) { // Write into [0, 1024) and then read out [0, 256) std::string source(1024, 'a'); size_t written; QuicTime t = clock_.ApproximateNow(); - buffer_->OnStreamData(0, source, t, &written); + buffer_->OnStreamData(0, source, t, &written, &error_details_); char dest[256]; helper_->Read(dest, 256); @@ -725,11 +755,12 @@ TEST_F(StreamSequencerBufferTest, MarkConsumedNotEnoughBytes) { EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, MarkConsumedAcrossBlock) { +TEST_F(QuicStreamSequencerBufferTest, MarkConsumedAcrossBlock) { // Write into [0, 2 * kBlockSizeBytes + 1024) and then read out [0, 1024) std::string source(2 * kBlockSizeBytes + 1024, 'a'); size_t written; - buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, + &error_details_); char dest[1024]; helper_->Read(dest, 1024); @@ -739,17 +770,18 @@ TEST_F(StreamSequencerBufferTest, MarkConsumedAcrossBlock) { EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, MarkConsumedAcrossEnd) { +TEST_F(QuicStreamSequencerBufferTest, MarkConsumedAcrossEnd) { // Write into [0, 2.5 * kBlockSizeBytes - 1024) and then read out [0, 1024) // and then append 1024 + 512 bytes. std::string source(2.5 * kBlockSizeBytes - 1024, 'a'); size_t written; - buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, + &error_details_); char dest[1024]; helper_->Read(dest, 1024); source = std::string(1024 + 512, 'b'); buffer_->OnStreamData(2.5 * kBlockSizeBytes - 1024, source, - clock_.ApproximateNow(), &written); + clock_.ApproximateNow(), &written, &error_details_); EXPECT_EQ(1024u, buffer_->BytesConsumed()); // Consume to the end of 2nd block. @@ -766,18 +798,19 @@ TEST_F(StreamSequencerBufferTest, MarkConsumedAcrossEnd) { EXPECT_TRUE(helper_->CheckBufferInvariants()); } -TEST_F(StreamSequencerBufferTest, FlushBufferedFrames) { +TEST_F(QuicStreamSequencerBufferTest, FlushBufferedFrames) { // Write into [0, 2.5 * kBlockSizeBytes - 1024) and then read out [0, 1024). std::string source(max_capacity_bytes_ - 1024, 'a'); size_t written; - buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written); + buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written, + &error_details_); char dest[1024]; helper_->Read(dest, 1024); EXPECT_EQ(1024u, buffer_->BytesConsumed()); // Write [1024, 512) to the physical beginning. source = std::string(512, 'b'); buffer_->OnStreamData(max_capacity_bytes_, source, clock_.ApproximateNow(), - &written); + &written, &error_details_); EXPECT_EQ(512u, written); EXPECT_EQ(max_capacity_bytes_ - 1024 + 512, buffer_->FlushBufferedFrames()); EXPECT_EQ(max_capacity_bytes_ + 512, buffer_->BytesConsumed()); @@ -789,7 +822,8 @@ TEST_F(StreamSequencerBufferTest, FlushBufferedFrames) { EXPECT_TRUE(helper_->CheckBufferInvariants()); } -class StreamSequencerBufferRandomIOTest : public StreamSequencerBufferTest { +class QuicStreamSequencerBufferRandomIOTest + : public QuicStreamSequencerBufferTest { public: typedef std::pair<QuicStreamOffset, size_t> OffsetSizePair; @@ -842,7 +876,7 @@ class StreamSequencerBufferRandomIOTest : public StreamSequencerBufferTest { } // Write the currently first chunk of data in the out-of-order stream into - // StreamSequencerBuffer. If current chuck cannot be written into buffer + // QuicStreamSequencerBuffer. If current chuck cannot be written into buffer // because it goes beyond current capacity, move it to the end of // shuffled_buf_ and write it later. void WriteNextChunkToBuffer() { @@ -855,8 +889,9 @@ class StreamSequencerBufferRandomIOTest : public StreamSequencerBufferTest { } base::StringPiece string_piece_w(write_buf.get(), num_to_write); size_t written; - auto result = buffer_->OnStreamData(offset, string_piece_w, - clock_.ApproximateNow(), &written); + auto result = + buffer_->OnStreamData(offset, string_piece_w, clock_.ApproximateNow(), + &written, &error_details_); if (result == QUIC_NO_ERROR) { shuffled_buf_.pop_front(); total_bytes_written_ += num_to_write; @@ -879,7 +914,7 @@ class StreamSequencerBufferRandomIOTest : public StreamSequencerBufferTest { SimpleRandom rng_; }; -TEST_F(StreamSequencerBufferRandomIOTest, RandomWriteAndReadv) { +TEST_F(QuicStreamSequencerBufferRandomIOTest, RandomWriteAndReadv) { // Set kMaxReadSize larger than kBlockSizeBytes to test both small and large // read. const size_t kMaxReadSize = kBlockSizeBytes * 2; @@ -939,7 +974,7 @@ TEST_F(StreamSequencerBufferRandomIOTest, RandomWriteAndReadv) { EXPECT_LE(bytes_to_buffer_, total_bytes_written_); } -TEST_F(StreamSequencerBufferRandomIOTest, RandomWriteAndConsumeInPlace) { +TEST_F(QuicStreamSequencerBufferRandomIOTest, RandomWriteAndConsumeInPlace) { // The value 4 is chosen such that the max write size is no larger than the // maximum buffer capacity. const size_t kMaxNumReads = 4; diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc index ef3b333..b66bf1d 100644 --- a/net/quic/quic_stream_sequencer_test.cc +++ b/net/quic/quic_stream_sequencer_test.cc @@ -240,7 +240,7 @@ TEST_F(QuicStreamSequencerTest, BlockedThenFullFrameAndFinConsumed) { TEST_F(QuicStreamSequencerTest, EmptyFrame) { EXPECT_CALL(stream_, - CloseConnectionWithDetails(QUIC_INVALID_STREAM_FRAME, _)); + CloseConnectionWithDetails(QUIC_EMPTY_STREAM_FRAME_NO_FIN, _)); OnFrame(0, ""); EXPECT_EQ(0u, NumBufferedBytes()); EXPECT_EQ(0u, sequencer_->NumBytesConsumed()); @@ -563,7 +563,11 @@ TEST_F(QuicStreamSequencerTest, DontAcceptOverlappingFrames) { sequencer_->OnStreamFrame(frame1); QuicStreamFrame frame2(kClientDataStreamId1, false, 2, StringPiece("hello")); - EXPECT_CALL(stream_, CloseConnectionWithDetails(QUIC_INVALID_STREAM_FRAME, _)) + EXPECT_CALL(stream_, CloseConnectionWithDetails( + FLAGS_quic_consolidate_onstreamframe_errors + ? QUIC_OVERLAPPING_STREAM_DATA + : QUIC_EMPTY_STREAM_FRAME_NO_FIN, + _)) .Times(1); sequencer_->OnStreamFrame(frame2); } diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc index d16bf72..0bf71c6 100644 --- a/net/quic/quic_utils.cc +++ b/net/quic/quic_utils.cc @@ -221,6 +221,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_MISSING_PAYLOAD); RETURN_STRING_LITERAL(QUIC_INVALID_FEC_DATA); RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_DATA); + RETURN_STRING_LITERAL(QUIC_OVERLAPPING_STREAM_DATA); RETURN_STRING_LITERAL(QUIC_UNENCRYPTED_STREAM_DATA); RETURN_STRING_LITERAL(QUIC_INVALID_RST_STREAM_DATA); RETURN_STRING_LITERAL(QUIC_INVALID_CONNECTION_CLOSE_DATA); @@ -265,7 +266,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_ERROR_MIGRATING_PORT); RETURN_STRING_LITERAL(QUIC_PACKET_WRITE_ERROR); RETURN_STRING_LITERAL(QUIC_PACKET_READ_ERROR); - RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_FRAME); + RETURN_STRING_LITERAL(QUIC_EMPTY_STREAM_FRAME_NO_FIN); RETURN_STRING_LITERAL(QUIC_INVALID_HEADERS_STREAM_DATA); RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA); diff --git a/net/quic/spdy_utils.cc b/net/quic/spdy_utils.cc index 623637d..72f9ae6 100644 --- a/net/quic/spdy_utils.cc +++ b/net/quic/spdy_utils.cc @@ -35,7 +35,7 @@ string SpdyUtils::SerializeUncompressedHeaders(const SpdyHeaderBlock& headers) { // static bool SpdyUtils::ParseHeaders(const char* data, uint32_t data_len, - int* content_length, + int64_t* content_length, SpdyHeaderBlock* headers) { SpdyFramer framer(HTTP2); if (!framer.ParseHeaderBlockInBuffer(data, data_len, headers) || diff --git a/net/quic/spdy_utils.h b/net/quic/spdy_utils.h index cef1368..ba8fecb 100644 --- a/net/quic/spdy_utils.h +++ b/net/quic/spdy_utils.h @@ -30,7 +30,7 @@ class NET_EXPORT_PRIVATE SpdyUtils { // Returns true on success, false if parsing fails, or invalid keys are found. static bool ParseHeaders(const char* data, uint32_t data_len, - int* content_length, + int64_t* content_length, SpdyHeaderBlock* headers); // Parses |data| as a std::string containing serialized HTTP/2 HEADERS frame, diff --git a/net/quic/spdy_utils_test.cc b/net/quic/spdy_utils_test.cc index 191d184..c3ebf70 100644 --- a/net/quic/spdy_utils_test.cc +++ b/net/quic/spdy_utils_test.cc @@ -31,7 +31,7 @@ TEST(SpdyUtilsTest, SerializeAndParseHeaders) { // Take the serialized header block, and parse back into SpdyHeaderBlock. SpdyHeaderBlock output_headers; - int content_length = -1; + int64_t content_length = -1; ASSERT_TRUE(SpdyUtils::ParseHeaders(serialized_headers.data(), serialized_headers.size(), &content_length, &output_headers)); diff --git a/net/quic/test_tools/mock_quic_dispatcher.h b/net/quic/test_tools/mock_quic_dispatcher.h index 3cb69e6..05c9c9b 100644 --- a/net/quic/test_tools/mock_quic_dispatcher.h +++ b/net/quic/test_tools/mock_quic_dispatcher.h @@ -27,7 +27,7 @@ class MockQuicDispatcher : public QuicDispatcher { MOCK_METHOD3(ProcessPacket, void(const IPEndPoint& server_address, const IPEndPoint& client_address, - const QuicEncryptedPacket& packet)); + const QuicReceivedPacket& packet)); private: DISALLOW_COPY_AND_ASSIGN(MockQuicDispatcher); diff --git a/net/quic/test_tools/quic_test_packet_maker.cc b/net/quic/test_tools/quic_test_packet_maker.cc index 9600d3e..58e06c9 100644 --- a/net/quic/test_tools/quic_test_packet_maker.cc +++ b/net/quic/test_tools/quic_test_packet_maker.cc @@ -33,7 +33,7 @@ void QuicTestPacketMaker::set_hostname(const std::string& host) { host_.assign(host); } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakePingPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakePingPacket( QuicPacketNumber num, bool include_version) { QuicPacketHeader header; @@ -47,10 +47,10 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakePingPacket( header.fec_group = 0; QuicPingFrame ping; - return scoped_ptr<QuicEncryptedPacket>(MakePacket(header, QuicFrame(ping))); + return scoped_ptr<QuicReceivedPacket>(MakePacket(header, QuicFrame(ping))); } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRstPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeRstPacket( QuicPacketNumber num, bool include_version, QuicStreamId stream_id, @@ -58,7 +58,7 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRstPacket( return MakeRstPacket(num, include_version, stream_id, error_code, 0); } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRstPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeRstPacket( QuicPacketNumber num, bool include_version, QuicStreamId stream_id, @@ -76,10 +76,10 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRstPacket( QuicRstStreamFrame rst(stream_id, error_code, bytes_written); DVLOG(1) << "Adding frame: " << QuicFrame(&rst); - return scoped_ptr<QuicEncryptedPacket>(MakePacket(header, QuicFrame(&rst))); + return scoped_ptr<QuicReceivedPacket>(MakePacket(header, QuicFrame(&rst))); } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckAndRstPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeAckAndRstPacket( QuicPacketNumber num, bool include_version, QuicStreamId stream_id, @@ -125,11 +125,11 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckAndRstPacket( header.packet_number, *packet, buffer, kMaxPacketSize); EXPECT_NE(0u, encrypted_size); - QuicEncryptedPacket encrypted(buffer, encrypted_size, false); - return scoped_ptr<QuicEncryptedPacket>(encrypted.Clone()); + QuicReceivedPacket encrypted(buffer, encrypted_size, QuicTime::Zero(), false); + return scoped_ptr<QuicReceivedPacket>(encrypted.Clone()); } -scoped_ptr<QuicEncryptedPacket> +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeAckAndConnectionClosePacket( QuicPacketNumber num, bool include_version, @@ -178,11 +178,11 @@ QuicTestPacketMaker::MakeAckAndConnectionClosePacket( header.packet_number, *packet, buffer, kMaxPacketSize); EXPECT_NE(0u, encrypted_size); - QuicEncryptedPacket encrypted(buffer, encrypted_size, false); - return scoped_ptr<QuicEncryptedPacket>(encrypted.Clone()); + QuicReceivedPacket encrypted(buffer, encrypted_size, clock_->Now(), false); + return scoped_ptr<QuicReceivedPacket>(encrypted.Clone()); } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeConnectionClosePacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeConnectionClosePacket( QuicPacketNumber num) { QuicPacketHeader header; header.public_header.connection_id = connection_id_; @@ -197,10 +197,10 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeConnectionClosePacket( QuicConnectionCloseFrame close; close.error_code = QUIC_CRYPTO_VERSION_NOT_SUPPORTED; close.error_details = "Time to panic!"; - return scoped_ptr<QuicEncryptedPacket>(MakePacket(header, QuicFrame(&close))); + return scoped_ptr<QuicReceivedPacket>(MakePacket(header, QuicFrame(&close))); } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeGoAwayPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeGoAwayPacket( QuicPacketNumber num, QuicErrorCode error_code, std::string reason_phrase) { @@ -218,13 +218,12 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeGoAwayPacket( goaway.error_code = error_code; goaway.last_good_stream_id = 0; goaway.reason_phrase = reason_phrase; - return scoped_ptr<QuicEncryptedPacket>( - MakePacket(header, QuicFrame(&goaway))); + return scoped_ptr<QuicReceivedPacket>(MakePacket(header, QuicFrame(&goaway))); } // Sets both least_unacked fields in stop waiting frame and ack frame // to be |least_unacked|. -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeAckPacket( QuicPacketNumber packet_number, QuicPacketNumber largest_received, QuicPacketNumber least_unacked, @@ -233,7 +232,7 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckPacket( least_unacked, send_feedback); } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeAckPacket( QuicPacketNumber packet_number, QuicPacketNumber largest_received, QuicPacketNumber ack_least_unacked, @@ -271,12 +270,12 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckPacket( header.packet_number, *packet, buffer, kMaxPacketSize); EXPECT_NE(0u, encrypted_size); - QuicEncryptedPacket encrypted(buffer, encrypted_size, false); - return scoped_ptr<QuicEncryptedPacket>(encrypted.Clone()); + QuicReceivedPacket encrypted(buffer, encrypted_size, clock_->Now(), false); + return scoped_ptr<QuicReceivedPacket>(encrypted.Clone()); } // Returns a newly created packet to send kData on stream 1. -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeDataPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeDataPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -288,7 +287,7 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeDataPacket( return MakePacket(header_, QuicFrame(&frame)); } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckAndDataPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeAckAndDataPacket( QuicPacketNumber packet_number, bool include_version, QuicStreamId stream_id, @@ -317,7 +316,7 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckAndDataPacket( return MakeMultipleFramesPacket(header_, frames); } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRequestHeadersPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeRequestHeadersPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -332,7 +331,7 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRequestHeadersPacket( // If |offset| is provided, will use the value when creating the packet. // Will also update the value after packet creation. -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRequestHeadersPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeRequestHeadersPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -377,7 +376,7 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRequestHeadersPacket( // Convenience method for calling MakeRequestHeadersPacket with nullptr for // |spdy_headers_frame_length|. -scoped_ptr<QuicEncryptedPacket> +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeRequestHeadersPacketWithOffsetTracking( QuicPacketNumber packet_number, QuicStreamId stream_id, @@ -393,7 +392,7 @@ QuicTestPacketMaker::MakeRequestHeadersPacketWithOffsetTracking( // If |offset| is provided, will use the value when creating the packet. // Will also update the value after packet creation. -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeResponseHeadersPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeResponseHeadersPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -431,7 +430,7 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeResponseHeadersPacket( } } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeResponseHeadersPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeResponseHeadersPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -445,7 +444,7 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeResponseHeadersPacket( // Convenience method for calling MakeResponseHeadersPacket with nullptr for // |spdy_headers_frame_length|. -scoped_ptr<QuicEncryptedPacket> +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeResponseHeadersPacketWithOffsetTracking( QuicPacketNumber packet_number, QuicStreamId stream_id, @@ -488,7 +487,7 @@ SpdyHeaderBlock QuicTestPacketMaker::GetResponseHeaders( return headers; } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakePacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakePacket( const QuicPacketHeader& header, const QuicFrame& frame) { QuicFrames frames; @@ -496,7 +495,7 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakePacket( return MakeMultipleFramesPacket(header, frames); } -scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeMultipleFramesPacket( +scoped_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeMultipleFramesPacket( const QuicPacketHeader& header, const QuicFrames& frames) { QuicFramer framer(SupportedVersions(version_), clock_->Now(), @@ -508,8 +507,8 @@ scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeMultipleFramesPacket( header.packet_number, *packet, buffer, kMaxPacketSize); EXPECT_NE(0u, encrypted_size); - QuicEncryptedPacket encrypted(buffer, encrypted_size, false); - return scoped_ptr<QuicEncryptedPacket>(encrypted.Clone()); + QuicReceivedPacket encrypted(buffer, encrypted_size, clock_->Now(), false); + return scoped_ptr<QuicReceivedPacket>(encrypted.Clone()); } void QuicTestPacketMaker::InitializeHeader(QuicPacketNumber packet_number, diff --git a/net/quic/test_tools/quic_test_packet_maker.h b/net/quic/test_tools/quic_test_packet_maker.h index 1b66cb8..3574ab7 100644 --- a/net/quic/test_tools/quic_test_packet_maker.h +++ b/net/quic/test_tools/quic_test_packet_maker.h @@ -30,22 +30,22 @@ class QuicTestPacketMaker { ~QuicTestPacketMaker(); void set_hostname(const std::string& host); - scoped_ptr<QuicEncryptedPacket> MakePingPacket(QuicPacketNumber num, - bool include_version); - scoped_ptr<QuicEncryptedPacket> MakeRstPacket( + scoped_ptr<QuicReceivedPacket> MakePingPacket(QuicPacketNumber num, + bool include_version); + scoped_ptr<QuicReceivedPacket> MakeRstPacket( QuicPacketNumber num, bool include_version, QuicStreamId stream_id, QuicRstStreamErrorCode error_code); - scoped_ptr<QuicEncryptedPacket> MakeRstPacket( + scoped_ptr<QuicReceivedPacket> MakeRstPacket( QuicPacketNumber num, bool include_version, QuicStreamId stream_id, QuicRstStreamErrorCode error_code, size_t bytes_written); - scoped_ptr<QuicEncryptedPacket> MakeAckAndRstPacket( + scoped_ptr<QuicReceivedPacket> MakeAckAndRstPacket( QuicPacketNumber num, bool include_version, QuicStreamId stream_id, @@ -54,7 +54,7 @@ class QuicTestPacketMaker { QuicPacketNumber ack_least_unacked, QuicPacketNumber stop_least_unacked, bool send_feedback); - scoped_ptr<QuicEncryptedPacket> MakeAckAndConnectionClosePacket( + scoped_ptr<QuicReceivedPacket> MakeAckAndConnectionClosePacket( QuicPacketNumber num, bool include_version, QuicTime::Delta delta_time_largest_observed, @@ -62,29 +62,29 @@ class QuicTestPacketMaker { QuicPacketNumber least_unacked, QuicErrorCode quic_error, std::string& quic_error_details); - scoped_ptr<QuicEncryptedPacket> MakeConnectionClosePacket( + scoped_ptr<QuicReceivedPacket> MakeConnectionClosePacket( QuicPacketNumber num); - scoped_ptr<QuicEncryptedPacket> MakeGoAwayPacket(QuicPacketNumber num, - QuicErrorCode error_code, - std::string reason_phrase); - scoped_ptr<QuicEncryptedPacket> MakeAckPacket( + scoped_ptr<QuicReceivedPacket> MakeGoAwayPacket(QuicPacketNumber num, + QuicErrorCode error_code, + std::string reason_phrase); + scoped_ptr<QuicReceivedPacket> MakeAckPacket( QuicPacketNumber packet_number, QuicPacketNumber largest_received, QuicPacketNumber least_unacked, bool send_feedback); - scoped_ptr<QuicEncryptedPacket> MakeAckPacket( + scoped_ptr<QuicReceivedPacket> MakeAckPacket( QuicPacketNumber packet_number, QuicPacketNumber largest_received, QuicPacketNumber ack_least_unacked, QuicPacketNumber stop_least_unacked, bool send_feedback); - scoped_ptr<QuicEncryptedPacket> MakeDataPacket(QuicPacketNumber packet_number, - QuicStreamId stream_id, - bool should_include_version, - bool fin, - QuicStreamOffset offset, - base::StringPiece data); - scoped_ptr<QuicEncryptedPacket> MakeAckAndDataPacket( + scoped_ptr<QuicReceivedPacket> MakeDataPacket(QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + QuicStreamOffset offset, + base::StringPiece data); + scoped_ptr<QuicReceivedPacket> MakeAckAndDataPacket( QuicPacketNumber packet_number, bool include_version, QuicStreamId stream_id, @@ -96,7 +96,7 @@ class QuicTestPacketMaker { // If |spdy_headers_frame_length| is non-null, it will be set to the size of // the SPDY headers frame created for this packet. - scoped_ptr<QuicEncryptedPacket> MakeRequestHeadersPacket( + scoped_ptr<QuicReceivedPacket> MakeRequestHeadersPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -105,7 +105,7 @@ class QuicTestPacketMaker { const SpdyHeaderBlock& headers, size_t* spdy_headers_frame_length); - scoped_ptr<QuicEncryptedPacket> MakeRequestHeadersPacket( + scoped_ptr<QuicReceivedPacket> MakeRequestHeadersPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -117,7 +117,7 @@ class QuicTestPacketMaker { // Convenience method for calling MakeRequestHeadersPacket with nullptr for // |spdy_headers_frame_length|. - scoped_ptr<QuicEncryptedPacket> MakeRequestHeadersPacketWithOffsetTracking( + scoped_ptr<QuicReceivedPacket> MakeRequestHeadersPacketWithOffsetTracking( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -128,7 +128,7 @@ class QuicTestPacketMaker { // If |spdy_headers_frame_length| is non-null, it will be set to the size of // the SPDY headers frame created for this packet. - scoped_ptr<QuicEncryptedPacket> MakeResponseHeadersPacket( + scoped_ptr<QuicReceivedPacket> MakeResponseHeadersPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -137,7 +137,7 @@ class QuicTestPacketMaker { size_t* spdy_headers_frame_length, QuicStreamOffset* offset); - scoped_ptr<QuicEncryptedPacket> MakeResponseHeadersPacket( + scoped_ptr<QuicReceivedPacket> MakeResponseHeadersPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -147,7 +147,7 @@ class QuicTestPacketMaker { // Convenience method for calling MakeResponseHeadersPacket with nullptr for // |spdy_headers_frame_length|. - scoped_ptr<QuicEncryptedPacket> MakeResponseHeadersPacketWithOffsetTracking( + scoped_ptr<QuicReceivedPacket> MakeResponseHeadersPacketWithOffsetTracking( QuicPacketNumber packet_number, QuicStreamId stream_id, bool should_include_version, @@ -164,9 +164,9 @@ class QuicTestPacketMaker { const std::string& alt_svc); private: - scoped_ptr<QuicEncryptedPacket> MakePacket(const QuicPacketHeader& header, - const QuicFrame& frame); - scoped_ptr<QuicEncryptedPacket> MakeMultipleFramesPacket( + scoped_ptr<QuicReceivedPacket> MakePacket(const QuicPacketHeader& header, + const QuicFrame& frame); + scoped_ptr<QuicReceivedPacket> MakeMultipleFramesPacket( const QuicPacketHeader& header, const QuicFrames& frames); diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index bc9fbc4..3d9267a 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc @@ -545,6 +545,15 @@ QuicEncryptedPacket* ConstructEncryptedPacket( return new QuicEncryptedPacket(buffer, encrypted_length, true); } +QuicReceivedPacket* ConstructReceivedPacket( + const QuicEncryptedPacket& encrypted_packet, + QuicTime receipt_time) { + char* buffer = new char[encrypted_packet.length()]; + memcpy(buffer, encrypted_packet.data(), encrypted_packet.length()); + return new QuicReceivedPacket(buffer, encrypted_packet.length(), receipt_time, + true); +} + QuicEncryptedPacket* ConstructMisFramedEncryptedPacket( QuicConnectionId connection_id, bool version_flag, diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 1f99831..ea2875d 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h @@ -109,6 +109,12 @@ QuicEncryptedPacket* ConstructEncryptedPacket(QuicConnectionId connection_id, QuicPacketNumber packet_number, const std::string& data); +// Constructs a received packet for testing. The caller must take ownership of +// the returned pointer. +QuicReceivedPacket* ConstructReceivedPacket( + const QuicEncryptedPacket& encrypted_packet, + QuicTime receipt_time); + // Create an encrypted packet for testing whose data portion erroneous. // The specific way the data portion is erroneous is not specified, but // it is an error that QuicFramer detects. @@ -377,7 +383,7 @@ class MockConnection : public QuicConnection { MOCK_METHOD3(ProcessUdpPacket, void(const IPEndPoint& self_address, const IPEndPoint& peer_address, - const QuicEncryptedPacket& packet)); + const QuicReceivedPacket& packet)); MOCK_METHOD1(SendConnectionClose, void(QuicErrorCode error)); MOCK_METHOD2(SendConnectionCloseWithDetails, void(QuicErrorCode error, const std::string& details)); @@ -407,7 +413,7 @@ class MockConnection : public QuicConnection { void ReallyProcessUdpPacket(const IPEndPoint& self_address, const IPEndPoint& peer_address, - const QuicEncryptedPacket& packet) { + const QuicReceivedPacket& packet) { QuicConnection::ProcessUdpPacket(self_address, peer_address, packet); } @@ -454,6 +460,8 @@ class MockQuicSpdySession : public QuicSpdySession { MOCK_METHOD1(CreateIncomingDynamicStream, QuicSpdyStream*(QuicStreamId id)); MOCK_METHOD1(CreateOutgoingDynamicStream, QuicSpdyStream*(SpdyPriority priority)); + MOCK_METHOD1(ShouldCreateIncomingDynamicStream, bool(QuicStreamId id)); + MOCK_METHOD0(ShouldCreateOutgoingDynamicStream, bool()); MOCK_METHOD5(WritevData, QuicConsumedData(QuicStreamId id, QuicIOVector data, @@ -547,6 +555,8 @@ class TestQuicSpdyClientSession : public QuicClientSessionBase { MOCK_METHOD1(CreateIncomingDynamicStream, QuicSpdyStream*(QuicStreamId id)); MOCK_METHOD1(CreateOutgoingDynamicStream, QuicSpdyStream*(SpdyPriority priority)); + MOCK_METHOD1(ShouldCreateIncomingDynamicStream, bool(QuicStreamId id)); + MOCK_METHOD0(ShouldCreateOutgoingDynamicStream, bool()); QuicCryptoClientStream* GetCryptoStream() override; diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index 923808b..38bb4c4 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc @@ -1003,7 +1003,7 @@ TEST_P(EndToEndTest, DoNotSetResumeWriteAlarmIfConnectionFlowControlBlocked) { // Make sure that the stream has data pending so that it will be marked as // write blocked when it receives a stream level WINDOW_UPDATE. - stream->SendBody("hello", false); + stream->WriteOrBufferBody("hello", false, nullptr); // The stream now attempts to write, fails because it is still connection // level flow control blocked, and is added to the write blocked list. @@ -1505,7 +1505,7 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) { // Open a data stream to make sure the stream level flow control is updated. QuicSpdyClientStream* stream = client_->GetOrCreateStream(); - stream->SendBody("hello", false); + stream->WriteOrBufferBody("hello", false, nullptr); // Client should have the right values for server's receive window. EXPECT_EQ(kServerStreamIFCW, @@ -1972,6 +1972,55 @@ class StreamWithErrorFactory : public QuicTestServer::StreamFactory { string response_body_; }; +// A test server stream that drops all received body. +class ServerStreamThatDropsBody : public QuicSimpleServerStream { + public: + ServerStreamThatDropsBody(QuicStreamId id, QuicSpdySession* session) + : QuicSimpleServerStream(id, session) {} + + ~ServerStreamThatDropsBody() override {} + + protected: + void OnDataAvailable() override { + while (HasBytesToRead()) { + struct iovec iov; + if (GetReadableRegions(&iov, 1) == 0) { + // No more data to read. + break; + } + DVLOG(1) << "Processed " << iov.iov_len << " bytes for stream " << id(); + MarkConsumed(iov.iov_len); + } + + if (!sequencer()->IsClosed()) { + sequencer()->SetUnblocked(); + return; + } + + // If the sequencer is closed, then all the body, including the fin, has + // been consumed. + OnFinRead(); + + if (write_side_closed() || fin_buffered()) { + return; + } + + SendResponse(); + } +}; + +class ServerStreamThatDropsBodyFactory : public QuicTestServer::StreamFactory { + public: + ServerStreamThatDropsBodyFactory() {} + + ~ServerStreamThatDropsBodyFactory() override{}; + + QuicSimpleServerStream* CreateStream(QuicStreamId id, + QuicSpdySession* session) override { + return new ServerStreamThatDropsBody(id, session); + } +}; + TEST_P(EndToEndTest, EarlyResponseFinRecording) { set_smaller_flow_control_receive_window(); @@ -2369,6 +2418,39 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) { EXPECT_EQ(12u, client_->num_responses()); } +// TODO(fayang): this test seems to cause net_unittests timeouts :| +TEST_P(EndToEndTest, DISABLED_TestHugePost) { + // This test tests a huge post with body size greater than 4GB, making sure + // QUIC code does not broke for 32-bit builds. + ServerStreamThatDropsBodyFactory stream_factory; + SetSpdyStreamFactory(&stream_factory); + ASSERT_TRUE(Initialize()); + // Set client's epoll server's time out to 0 to make this test be finished + // within a short time. + client_->epoll_server()->set_timeout_in_us(0); + + client_->client()->WaitForCryptoHandshakeConfirmed(); + + // To avoid storing the whole request body in memory, use a loop to repeatedly + // send body size of kSizeBytes until the whole request body size is reached. + const int kSizeBytes = 128 * 1024; + HTTPMessage request(HttpConstants::HTTP_1_1, HttpConstants::POST, "/foo"); + // Request body size is 4G plus one more kSizeBytes. + int64_t request_body_size_bytes = pow(2, 32) + kSizeBytes; + request.AddHeader("content-length", IntToString(request_body_size_bytes)); + request.set_has_complete_message(false); + string body; + test::GenerateBody(&body, kSizeBytes); + + client_->SendMessage(request); + for (int i = 0; i < request_body_size_bytes / kSizeBytes; ++i) { + bool fin = (i == request_body_size_bytes - 1); + client_->SendData(string(body.data(), kSizeBytes), fin); + client_->client()->WaitForEvents(); + } + VerifyCleanConnection(false); +} + } // namespace } // namespace test } // namespace net diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc index b0815d3..07617bb 100644 --- a/net/tools/quic/quic_client.cc +++ b/net/tools/quic/quic_client.cc @@ -391,7 +391,8 @@ void QuicClient::OnEvent(int fd, EpollEvent* event) { bool more_to_read = true; while (connected() && more_to_read) { more_to_read = packet_reader_->ReadAndDispatchPackets( - GetLatestFD(), QuicClient::GetLatestClientAddress().port(), this, + GetLatestFD(), QuicClient::GetLatestClientAddress().port(), + *helper()->GetClock(), this, overflow_supported_ ? &packets_dropped_ : nullptr); } } @@ -408,22 +409,22 @@ void QuicClient::OnClose(QuicSpdyStream* stream) { DCHECK(stream != nullptr); QuicSpdyClientStream* client_stream = static_cast<QuicSpdyClientStream*>(stream); - BalsaHeaders headers; - SpdyBalsaUtils::SpdyHeadersToResponseHeaders(client_stream->headers(), - &headers); + BalsaHeaders response_headers; + SpdyBalsaUtils::SpdyHeadersToResponseHeaders( + client_stream->response_headers(), &response_headers); if (response_listener_.get() != nullptr) { - response_listener_->OnCompleteResponse(stream->id(), headers, + response_listener_->OnCompleteResponse(stream->id(), response_headers, client_stream->data()); } // Store response headers and body. if (store_response_) { - latest_response_code_ = headers.parsed_response_code(); - headers.DumpHeadersToString(&latest_response_headers_); + latest_response_code_ = response_headers.parsed_response_code(); + response_headers.DumpHeadersToString(&latest_response_headers_); latest_response_body_ = client_stream->data(); latest_response_trailers_ = - client_stream->response_trailers().DebugString(); + client_stream->received_trailers().DebugString(); } } @@ -486,7 +487,7 @@ int QuicClient::GetLatestFD() const { void QuicClient::ProcessPacket(const IPEndPoint& self_address, const IPEndPoint& peer_address, - const QuicEncryptedPacket& packet) { + const QuicReceivedPacket& packet) { session()->connection()->ProcessUdpPacket(self_address, peer_address, packet); } diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h index ef6b711..1df8514 100644 --- a/net/tools/quic/quic_client.h +++ b/net/tools/quic/quic_client.h @@ -187,7 +187,7 @@ class QuicClient : public QuicClientBase, // packet. void ProcessPacket(const IPEndPoint& self_address, const IPEndPoint& peer_address, - const QuicEncryptedPacket& packet) override; + const QuicReceivedPacket& packet) override; QuicClientPushPromiseIndex* push_promise_index() { return &push_promise_index_; diff --git a/net/tools/quic/quic_client_session.h b/net/tools/quic/quic_client_session.h index 2cbf236..651469d 100644 --- a/net/tools/quic/quic_client_session.h +++ b/net/tools/quic/quic_client_session.h @@ -60,6 +60,11 @@ class QuicClientSession : public QuicClientSessionBase { protected: // QuicSession methods: QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override; + // If an outgoing stream can be created, return true. + bool ShouldCreateOutgoingDynamicStream() override; + + // If an incoming stream can be created, return true. + bool ShouldCreateIncomingDynamicStream(QuicStreamId id) override; // Create the crypto stream. Called by Initialize() virtual QuicCryptoClientStreamBase* CreateQuicCryptoStream(); @@ -74,12 +79,6 @@ class QuicClientSession : public QuicClientSessionBase { QuicCryptoClientConfig* crypto_config() { return crypto_config_; } private: - // If an outgoing stream can be created, return true. - bool ShouldCreateOutgoingDynamicStream(); - - // If an incoming stream can be created, return true. - bool ShouldCreateIncomingDynamicStream(QuicStreamId id); - scoped_ptr<QuicCryptoClientStreamBase> crypto_stream_; QuicServerId server_id_; QuicCryptoClientConfig* crypto_config_; diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc index f2aa9c0..2837ef4 100644 --- a/net/tools/quic/quic_client_session_test.cc +++ b/net/tools/quic/quic_client_session_test.cc @@ -248,14 +248,14 @@ TEST_P(QuicClientSessionTest, InvalidPacketReceived) { EXPECT_CALL(*connection_, OnError(_)).Times(1); // Verify that empty packets don't close the connection. - QuicEncryptedPacket zero_length_packet(nullptr, 0, false); + QuicReceivedPacket zero_length_packet(nullptr, 0, QuicTime::Zero(), false); EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(_, _)).Times(0); session_->ProcessUdpPacket(client_address, server_address, zero_length_packet); // Verifiy that small, invalid packets don't close the connection. char buf[2] = {0x00, 0x01}; - QuicEncryptedPacket valid_packet(buf, 2, false); + QuicReceivedPacket valid_packet(buf, 2, QuicTime::Zero(), false); // Close connection shouldn't be called. EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(_, _)).Times(0); session_->ProcessUdpPacket(client_address, server_address, valid_packet); @@ -264,11 +264,13 @@ TEST_P(QuicClientSessionTest, InvalidPacketReceived) { QuicConnectionId connection_id = session_->connection()->connection_id(); scoped_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( connection_id, false, false, false, kDefaultPathId, 100, "data")); + scoped_ptr<QuicReceivedPacket> received( + ConstructReceivedPacket(*packet, QuicTime::Zero())); // Change the last byte of the encrypted data. - *(const_cast<char*>(packet->data() + packet->length() - 1)) += 1; + *(const_cast<char*>(received->data() + received->length() - 1)) += 1; EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(_, _)).Times(0); EXPECT_CALL(*connection_, OnError(Truly(CheckForDecryptionError))).Times(1); - session_->ProcessUdpPacket(client_address, server_address, *packet); + session_->ProcessUdpPacket(client_address, server_address, *received); } // A packet with invalid framing should cause a connection to be closed. @@ -286,8 +288,10 @@ TEST_P(QuicClientSessionTest, InvalidFramedPacketReceived) { scoped_ptr<QuicEncryptedPacket> packet(ConstructMisFramedEncryptedPacket( connection_id, false, false, false, kDefaultPathId, 100, "data", PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, nullptr)); + scoped_ptr<QuicReceivedPacket> received( + ConstructReceivedPacket(*packet, QuicTime::Zero())); EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(_, _)).Times(1); - session_->ProcessUdpPacket(client_address, server_address, *packet); + session_->ProcessUdpPacket(client_address, server_address, *received); } TEST_P(QuicClientSessionTest, PushPromiseOnPromiseHeaders) { diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc index f662ee3..1b145ef 100644 --- a/net/tools/quic/quic_dispatcher.cc +++ b/net/tools/quic/quic_dispatcher.cc @@ -74,7 +74,7 @@ void QuicDispatcher::InitializeWithWriter(QuicPacketWriter* writer) { void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address, const IPEndPoint& client_address, - const QuicEncryptedPacket& packet) { + const QuicReceivedPacket& packet) { current_server_address_ = server_address; current_client_address_ = client_address; current_packet_ = &packet; diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h index 6ba8f2b..5ff52ce 100644 --- a/net/tools/quic/quic_dispatcher.h +++ b/net/tools/quic/quic_dispatcher.h @@ -63,7 +63,7 @@ class QuicDispatcher : public QuicServerSessionVisitor, // an existing session, or passing it to the time wait list. void ProcessPacket(const IPEndPoint& server_address, const IPEndPoint& client_address, - const QuicEncryptedPacket& packet) override; + const QuicReceivedPacket& packet) override; // Called when the socket becomes writable to allow queued writes to happen. void OnCanWrite() override; @@ -182,7 +182,7 @@ class QuicDispatcher : public QuicServerSessionVisitor, const IPEndPoint& current_server_address() { return current_server_address_; } const IPEndPoint& current_client_address() { return current_client_address_; } - const QuicEncryptedPacket& current_packet() { return *current_packet_; } + const QuicReceivedPacket& current_packet() { return *current_packet_; } const QuicConfig& config() const { return config_; } @@ -257,7 +257,7 @@ class QuicDispatcher : public QuicServerSessionVisitor, // Information about the packet currently being handled. IPEndPoint current_client_address_; IPEndPoint current_server_address_; - const QuicEncryptedPacket* current_packet_; + const QuicReceivedPacket* current_packet_; QuicConnectionId current_connection_id_; QuicFramer framer_; diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc index 67fb2d6..1172d1f 100644 --- a/net/tools/quic/quic_dispatcher_test.cc +++ b/net/tools/quic/quic_dispatcher_test.cc @@ -229,9 +229,12 @@ class QuicDispatcherTest : public ::testing::Test { scoped_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( connection_id, has_version_flag, false, false, 0, packet_number, data, connection_id_length, packet_number_length, &versions)); + scoped_ptr<QuicReceivedPacket> received_packet( + ConstructReceivedPacket(*packet, helper_.GetClock()->Now())); data_ = string(packet->data(), packet->length()); - dispatcher_.ProcessPacket(server_address_, client_address, *packet); + dispatcher_.ProcessPacket(server_address_, client_address, + *received_packet); } void ValidatePacket(const QuicEncryptedPacket& packet) { @@ -353,6 +356,8 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) { packet.nonce_proof = 132232; scoped_ptr<QuicEncryptedPacket> encrypted( QuicFramer::BuildPublicResetPacket(packet)); + scoped_ptr<QuicReceivedPacket> received( + ConstructReceivedPacket(*encrypted, helper_.GetClock()->Now())); EXPECT_CALL(*session1_, OnConnectionClosed(QUIC_PUBLIC_RESET, ConnectionCloseSource::FROM_PEER)) .Times(1) @@ -364,7 +369,7 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) { .WillOnce( Invoke(reinterpret_cast<MockConnection*>(session1_->connection()), &MockConnection::ReallyProcessUdpPacket)); - dispatcher_.ProcessPacket(IPEndPoint(), client_address, *encrypted); + dispatcher_.ProcessPacket(IPEndPoint(), client_address, *received); EXPECT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); // Dispatcher forwards subsequent packets for this connection_id to the time diff --git a/net/tools/quic/quic_packet_reader.cc b/net/tools/quic/quic_packet_reader.cc index 3f5f8c8..beba973 100644 --- a/net/tools/quic/quic_packet_reader.cc +++ b/net/tools/quic/quic_packet_reader.cc @@ -53,7 +53,7 @@ void QuicPacketReader::Initialize() { hdr->msg_iovlen = 1; hdr->msg_control = packets_[i].cbuf; - hdr->msg_controllen = kSpaceForOverflowAndIp; + hdr->msg_controllen = QuicSocketUtils::kSpaceForCmsg; } #endif } @@ -63,18 +63,22 @@ QuicPacketReader::~QuicPacketReader() {} bool QuicPacketReader::ReadAndDispatchPackets( int fd, int port, + const QuicClock& clock, ProcessPacketInterface* processor, QuicPacketCount* packets_dropped) { #if MMSG_MORE - return ReadAndDispatchManyPackets(fd, port, processor, packets_dropped); + return ReadAndDispatchManyPackets(fd, port, clock, processor, + packets_dropped); #else - return ReadAndDispatchSinglePacket(fd, port, processor, packets_dropped); + return ReadAndDispatchSinglePacket(fd, port, clock, processor, + packets_dropped); #endif } bool QuicPacketReader::ReadAndDispatchManyPackets( int fd, int port, + const QuicClock& clock, ProcessPacketInterface* processor, QuicPacketCount* packets_dropped) { #if MMSG_MORE @@ -84,7 +88,7 @@ bool QuicPacketReader::ReadAndDispatchManyPackets( msghdr* hdr = &mmsg_hdr_[i].msg_hdr; hdr->msg_namelen = sizeof(sockaddr_storage); DCHECK_EQ(1, hdr->msg_iovlen); - hdr->msg_controllen = kSpaceForOverflowAndIp; + hdr->msg_controllen = QuicSocketUtils::kSpaceForCmsg; } int packets_read = @@ -94,22 +98,42 @@ bool QuicPacketReader::ReadAndDispatchManyPackets( return false; // recvmmsg failed. } + QuicTime fallback_timestamp = QuicTime::Zero(); for (int i = 0; i < packets_read; ++i) { if (mmsg_hdr_[i].msg_len == 0) { continue; } + if (mmsg_hdr_[i].msg_hdr.msg_controllen >= QuicSocketUtils::kSpaceForCmsg) { + QUIC_BUG << "Incorrectly set control length: " + << mmsg_hdr_[i].msg_hdr.msg_controllen << ", expected " + << QuicSocketUtils::kSpaceForCmsg; + continue; + } + IPEndPoint client_address = IPEndPoint(packets_[i].raw_address); - IPAddressNumber server_ip = - QuicSocketUtils::GetAddressFromMsghdr(&mmsg_hdr_[i].msg_hdr); + IPAddressNumber server_ip; + QuicTime packet_timestamp = QuicTime::Zero(); + QuicSocketUtils::GetAddressAndTimestampFromMsghdr( + &mmsg_hdr_[i].msg_hdr, &server_ip, &packet_timestamp); if (!IsInitializedAddress(server_ip)) { QUIC_BUG << "Unable to get server address."; continue; } - QuicEncryptedPacket packet( - reinterpret_cast<char*>(packets_[i].iov.iov_base), mmsg_hdr_[i].msg_len, - false); + if (FLAGS_quic_use_socket_timestamp) { + if (packet_timestamp == QuicTime::Zero()) { + // This isn't particularly desirable, but not all platforms support + // socket timestamping. + if (fallback_timestamp == QuicTime::Zero()) { + fallback_timestamp = clock.Now(); + } + packet_timestamp = fallback_timestamp; + } + } + + QuicReceivedPacket packet(reinterpret_cast<char*>(packets_[i].iov.iov_base), + mmsg_hdr_[i].msg_len, packet_timestamp, false); IPEndPoint server_address(server_ip, port); processor->ProcessPacket(server_address, client_address, packet); } @@ -131,20 +155,33 @@ bool QuicPacketReader::ReadAndDispatchManyPackets( bool QuicPacketReader::ReadAndDispatchSinglePacket( int fd, int port, + const QuicClock& clock, ProcessPacketInterface* processor, QuicPacketCount* packets_dropped) { char buf[kMaxPacketSize]; IPEndPoint client_address; IPAddress server_ip; - int bytes_read = QuicSocketUtils::ReadPacket( - fd, buf, arraysize(buf), packets_dropped, &server_ip, &client_address); + QuicTime timestamp = QuicTime::Zero(); + int bytes_read = + QuicSocketUtils::ReadPacket(fd, buf, arraysize(buf), packets_dropped, + &server_ip, ×tamp, &client_address); if (bytes_read < 0) { return false; // ReadPacket failed. } - QuicEncryptedPacket packet(buf, bytes_read, false); + if (server_ip.empty()) { + QUIC_BUG << "Unable to get server address."; + return false; + } + if (FLAGS_quic_use_socket_timestamp && timestamp == QuicTime::Zero()) { + // This isn't particularly desirable, but not all platforms support socket + // timestamping. + timestamp = clock.Now(); + } + + QuicReceivedPacket packet(buf, bytes_read, timestamp, false); IPEndPoint server_address(server_ip, port); processor->ProcessPacket(server_address, client_address, packet); diff --git a/net/tools/quic/quic_packet_reader.h b/net/tools/quic/quic_packet_reader.h index 6ffe26b..b388406 100644 --- a/net/tools/quic/quic_packet_reader.h +++ b/net/tools/quic/quic_packet_reader.h @@ -11,8 +11,10 @@ #include <sys/socket.h> #include "base/macros.h" +#include "net/quic/quic_clock.h" #include "net/quic/quic_protocol.h" #include "net/tools/quic/quic_process_packet_interface.h" +#include "net/tools/quic/quic_socket_utils.h" #define MMSG_MORE 0 @@ -21,9 +23,6 @@ namespace net { #if MMSG_MORE // Read in larger batches to minimize recvmmsg overhead. const int kNumPacketsPerReadMmsgCall = 16; -// Allocate space for in6_pktinfo as it's larger than in_pktinfo -const int kSpaceForOverflowAndIp = - CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo)); #endif namespace test { @@ -43,8 +42,11 @@ class QuicPacketReader { // packets available on the socket. // Populates |packets_dropped| if it is non-null and the socket is configured // to track dropped packets and some packets are read. + // If the socket has timestamping enabled, the per packet timestamps will be + // passed to the processor. Otherwise, |clock| will be used. virtual bool ReadAndDispatchPackets(int fd, int port, + const QuicClock& clock, ProcessPacketInterface* processor, QuicPacketCount* packets_dropped); @@ -55,12 +57,14 @@ class QuicPacketReader { // Reads and dispatches many packets using recvmmsg. bool ReadAndDispatchManyPackets(int fd, int port, + const QuicClock& clock, ProcessPacketInterface* processor, QuicPacketCount* packets_dropped); // Reads and dispatches a single packet using recvmsg. static bool ReadAndDispatchSinglePacket(int fd, int port, + const QuicClock& clock, ProcessPacketInterface* processor, QuicPacketCount* packets_dropped); @@ -78,7 +82,7 @@ class QuicPacketReader { // call on the packets. struct sockaddr_storage raw_address; // cbuf is used for ancillary data from the kernel on recvmmsg. - char cbuf[kSpaceForOverflowAndIp]; + char cbuf[QuicSocketUtils::kSpaceForCmsg]; // buf is used for the data read from the kernel on recvmmsg. char buf[kMaxPacketSize]; }; diff --git a/net/tools/quic/quic_process_packet_interface.h b/net/tools/quic/quic_process_packet_interface.h index cc5924a..aa1035d 100644 --- a/net/tools/quic/quic_process_packet_interface.h +++ b/net/tools/quic/quic_process_packet_interface.h @@ -17,7 +17,7 @@ class ProcessPacketInterface { virtual ~ProcessPacketInterface() {} virtual void ProcessPacket(const IPEndPoint& server_address, const IPEndPoint& client_address, - const QuicEncryptedPacket& packet) = 0; + const QuicReceivedPacket& packet) = 0; }; } // namespace net diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc index 1c878f1..832c1b6 100644 --- a/net/tools/quic/quic_server.cc +++ b/net/tools/quic/quic_server.cc @@ -168,7 +168,7 @@ void QuicServer::OnEvent(int fd, EpollEvent* event) { bool more_to_read = true; while (more_to_read) { more_to_read = packet_reader_->ReadAndDispatchPackets( - fd_, port_, dispatcher_.get(), + fd_, port_, QuicEpollClock(&epoll_server_), dispatcher_.get(), overflow_supported_ ? &packets_dropped_ : nullptr); } } diff --git a/net/tools/quic/quic_server_session_base.h b/net/tools/quic/quic_server_session_base.h index a93fd9c..d14f02b 100644 --- a/net/tools/quic/quic_server_session_base.h +++ b/net/tools/quic/quic_server_session_base.h @@ -95,12 +95,12 @@ class QuicServerSessionBase : public QuicSpdySession { // Return false when connection is closed or forward secure encryption hasn't // established yet or number of server initiated streams already reaches the // upper limit. - virtual bool ShouldCreateOutgoingDynamicStream(); + bool ShouldCreateOutgoingDynamicStream() override; // If we should create an incoming stream, returns true. Otherwise // does error handling, including communicating the error to the client and // possibly closing the connection, and returns false. - virtual bool ShouldCreateIncomingDynamicStream(QuicStreamId id); + bool ShouldCreateIncomingDynamicStream(QuicStreamId id) override; virtual QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( const QuicCryptoServerConfig* crypto_config, diff --git a/net/tools/quic/quic_server_test.cc b/net/tools/quic/quic_server_test.cc index 1e55e23..d59bc70 100644 --- a/net/tools/quic/quic_server_test.cc +++ b/net/tools/quic/quic_server_test.cc @@ -32,7 +32,7 @@ class QuicServerDispatchPacketTest : public ::testing::Test { dispatcher_.InitializeWithWriter(new QuicDefaultPacketWriter(1234)); } - void DispatchPacket(const QuicEncryptedPacket& packet) { + void DispatchPacket(const QuicReceivedPacket& packet) { IPEndPoint client_addr, server_addr; dispatcher_.ProcessPacket(server_addr, client_addr, packet); } @@ -59,8 +59,9 @@ TEST_F(QuicServerDispatchPacketTest, DispatchPacket) { 0x00 }; // clang-format on - QuicEncryptedPacket encrypted_valid_packet(QuicUtils::AsChars(valid_packet), - arraysize(valid_packet), false); + QuicReceivedPacket encrypted_valid_packet(QuicUtils::AsChars(valid_packet), + arraysize(valid_packet), + QuicTime::Zero(), false); EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _)).Times(1); DispatchPacket(encrypted_valid_packet); diff --git a/net/tools/quic/quic_simple_client.cc b/net/tools/quic/quic_simple_client.cc index b1dcf19..928481a 100644 --- a/net/tools/quic/quic_simple_client.cc +++ b/net/tools/quic/quic_simple_client.cc @@ -339,7 +339,8 @@ void QuicSimpleClient::OnClose(QuicSpdyStream* stream) { QuicSpdyClientStream* client_stream = static_cast<QuicSpdyClientStream*>(stream); HttpResponseInfo response; - SpdyHeadersToHttpResponse(client_stream->headers(), net::HTTP2, &response); + SpdyHeadersToHttpResponse(client_stream->response_headers(), net::HTTP2, + &response); if (response_listener_.get() != nullptr) { response_listener_->OnCompleteResponse(stream->id(), *response.headers, client_stream->data()); @@ -388,7 +389,7 @@ void QuicSimpleClient::OnReadError(int result, Disconnect(); } -bool QuicSimpleClient::OnPacket(const QuicEncryptedPacket& packet, +bool QuicSimpleClient::OnPacket(const QuicReceivedPacket& packet, IPEndPoint local_address, IPEndPoint peer_address) { session()->connection()->ProcessUdpPacket(local_address, peer_address, diff --git a/net/tools/quic/quic_simple_client.h b/net/tools/quic/quic_simple_client.h index 0ac0087..bcd0bda 100644 --- a/net/tools/quic/quic_simple_client.h +++ b/net/tools/quic/quic_simple_client.h @@ -130,7 +130,7 @@ class QuicSimpleClient : public QuicClientBase, // QuicChromiumPacketReader::Visitor void OnReadError(int result, const DatagramClientSocket* socket) override; - bool OnPacket(const QuicEncryptedPacket& packet, + bool OnPacket(const QuicReceivedPacket& packet, IPEndPoint local_address, IPEndPoint peer_address) override; diff --git a/net/tools/quic/quic_simple_server.cc b/net/tools/quic/quic_simple_server.cc index 9e89a50..7713986 100644 --- a/net/tools/quic/quic_simple_server.cc +++ b/net/tools/quic/quic_simple_server.cc @@ -202,7 +202,8 @@ void QuicSimpleServer::OnReadComplete(int result) { return; } - QuicEncryptedPacket packet(read_buffer_->data(), result, false); + QuicReceivedPacket packet(read_buffer_->data(), result, + helper_->GetClock()->Now(), false); dispatcher_->ProcessPacket(server_address_, client_address_, packet); StartReading(); diff --git a/net/tools/quic/quic_simple_server_stream.cc b/net/tools/quic/quic_simple_server_stream.cc index b715574..e0a3c2f 100644 --- a/net/tools/quic/quic_simple_server_stream.cc +++ b/net/tools/quic/quic_simple_server_stream.cc @@ -58,7 +58,7 @@ void QuicSimpleServerStream::OnDataAvailable() { body_.append(static_cast<char*>(iov.iov_base), iov.iov_len); if (content_length_ >= 0 && - static_cast<int>(body_.size()) > content_length_) { + body_.size() > static_cast<uint64_t>(content_length_)) { DVLOG(1) << "Body size (" << body_.size() << ") > content length (" << content_length_ << ")."; SendErrorResponse(); @@ -86,7 +86,7 @@ void QuicSimpleServerStream::OnDataAvailable() { } if (content_length_ > 0 && - content_length_ != static_cast<int>(body_.size())) { + static_cast<uint64_t>(content_length_) != body_.size()) { DVLOG(1) << "Content length (" << content_length_ << ") != body size (" << body_.size() << ")."; SendErrorResponse(); diff --git a/net/tools/quic/quic_simple_server_stream.h b/net/tools/quic/quic_simple_server_stream.h index 90cb0dc..b88b847 100644 --- a/net/tools/quic/quic_simple_server_stream.h +++ b/net/tools/quic/quic_simple_server_stream.h @@ -73,7 +73,7 @@ class QuicSimpleServerStream : public QuicSpdyStream { // The parsed headers received from the client. SpdyHeaderBlock request_headers_; - int content_length_; + int64_t content_length_; std::string body_; DISALLOW_COPY_AND_ASSIGN(QuicSimpleServerStream); diff --git a/net/tools/quic/quic_simple_server_test.cc b/net/tools/quic/quic_simple_server_test.cc index c63501c..3a7c54e 100644 --- a/net/tools/quic/quic_simple_server_test.cc +++ b/net/tools/quic/quic_simple_server_test.cc @@ -30,7 +30,7 @@ class QuicChromeServerDispatchPacketTest : public ::testing::Test { dispatcher_.InitializeWithWriter(nullptr); } - void DispatchPacket(const QuicEncryptedPacket& packet) { + void DispatchPacket(const QuicReceivedPacket& packet) { IPEndPoint client_addr, server_addr; dispatcher_.ProcessPacket(server_addr, client_addr, packet); } @@ -51,8 +51,9 @@ TEST_F(QuicChromeServerDispatchPacketTest, DispatchPacket) { 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, // private flags 0x00}; - QuicEncryptedPacket encrypted_valid_packet(QuicUtils::AsChars(valid_packet), - arraysize(valid_packet), false); + QuicReceivedPacket encrypted_valid_packet(QuicUtils::AsChars(valid_packet), + arraysize(valid_packet), + QuicTime::Zero(), false); EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _)).Times(1); DispatchPacket(encrypted_valid_packet); diff --git a/net/tools/quic/quic_socket_utils.cc b/net/tools/quic/quic_socket_utils.cc index 9c8cac7..1ef874c 100644 --- a/net/tools/quic/quic_socket_utils.cc +++ b/net/tools/quic/quic_socket_utils.cc @@ -5,6 +5,7 @@ #include "net/tools/quic/quic_socket_utils.h" #include <errno.h> +#include <linux/net_tstamp.h> #include <netinet/in.h> #include <string.h> #include <sys/socket.h> @@ -12,6 +13,8 @@ #include <string> #include "base/logging.h" +#include "net/quic/quic_bug_tracker.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_protocol.h" #ifndef SO_RXQ_OVFL @@ -21,28 +24,36 @@ namespace net { // static -IPAddress QuicSocketUtils::GetAddressFromMsghdr(struct msghdr* hdr) { +void QuicSocketUtils::GetAddressAndTimestampFromMsghdr(struct msghdr* hdr, + IPAddress* address, + QuicTime* timestamp) { if (hdr->msg_controllen > 0) { for (cmsghdr* cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr; cmsg = CMSG_NXTHDR(hdr, cmsg)) { const uint8_t* addr_data = nullptr; int len = 0; if (cmsg->cmsg_type == IPV6_PKTINFO) { - in6_pktinfo* info = reinterpret_cast<in6_pktinfo*> CMSG_DATA(cmsg); + in6_pktinfo* info = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg)); addr_data = reinterpret_cast<const uint8_t*>(&info->ipi6_addr); len = sizeof(in6_addr); + *address = IPAddress(addr_data, len); } else if (cmsg->cmsg_type == IP_PKTINFO) { - in_pktinfo* info = reinterpret_cast<in_pktinfo*> CMSG_DATA(cmsg); + in_pktinfo* info = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg)); addr_data = reinterpret_cast<const uint8_t*>(&info->ipi_addr); len = sizeof(in_addr); - } else { - continue; + *address = IPAddress(addr_data, len); + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SO_TIMESTAMPING) { + LinuxTimestamping* lts = + reinterpret_cast<LinuxTimestamping*>(CMSG_DATA(cmsg)); + timespec* ts = <s->systime; + int64_t usec = (static_cast<int64_t>(ts->tv_sec) * 1000 * 1000) + + (static_cast<int64_t>(ts->tv_nsec) / 1000); + *timestamp = + QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(usec)); } - return IPAddress(addr_data, len); } } - DCHECK(false) << "Unable to get address from msghdr"; - return IPAddress(); } // static @@ -74,6 +85,13 @@ int QuicSocketUtils::SetGetAddressInfo(int fd, int address_family) { } // static +int QuicSocketUtils::SetGetSoftwareReceiveTimestamp(int fd) { + int timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE; + return setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, ×tamping, + sizeof(timestamping)); +} + +// static bool QuicSocketUtils::SetSendBufferSize(int fd, size_t size) { if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) != 0) { LOG(ERROR) << "Failed to set socket send size"; @@ -97,11 +115,10 @@ int QuicSocketUtils::ReadPacket(int fd, size_t buf_len, QuicPacketCount* dropped_packets, IPAddress* self_address, + QuicTime* timestamp, IPEndPoint* peer_address) { DCHECK(peer_address != nullptr); - const int kSpaceForOverflowAndIp = - CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo)); - char cbuf[kSpaceForOverflowAndIp]; + char cbuf[kSpaceForCmsg]; memset(cbuf, 0, arraysize(cbuf)); iovec iov = {buffer, buf_len}; @@ -130,13 +147,28 @@ int QuicSocketUtils::ReadPacket(int fd, return -1; } + if (hdr.msg_controllen >= arraysize(cbuf)) { + QUIC_BUG << "Incorrectly set control length: " << hdr.msg_controllen + << ", expected " << arraysize(cbuf); + return -1; + } + if (dropped_packets != nullptr) { GetOverflowFromMsghdr(&hdr, dropped_packets); } - if (self_address != nullptr) { - *self_address = QuicSocketUtils::GetAddressFromMsghdr(&hdr); + + IPAddress stack_address; + if (self_address == nullptr) { + self_address = &stack_address; + } + + QuicTime stack_timestamp = QuicTime::Zero(); + if (timestamp == nullptr) { + timestamp = &stack_timestamp; } + GetAddressAndTimestampFromMsghdr(&hdr, self_address, timestamp); + if (raw_address.ss_family == AF_INET) { CHECK(peer_address->FromSockAddr( reinterpret_cast<const sockaddr*>(&raw_address), @@ -245,19 +277,28 @@ int QuicSocketUtils::CreateUDPSocket(const IPEndPoint& address, *overflow_supported = true; } - if (!QuicSocketUtils::SetReceiveBufferSize(fd, kDefaultSocketReceiveBuffer)) { + if (!SetReceiveBufferSize(fd, kDefaultSocketReceiveBuffer)) { return -1; } - if (!QuicSocketUtils::SetSendBufferSize(fd, kDefaultSocketReceiveBuffer)) { + if (!SetSendBufferSize(fd, kDefaultSocketReceiveBuffer)) { return -1; } - rc = QuicSocketUtils::SetGetAddressInfo(fd, address_family); + rc = SetGetAddressInfo(fd, address_family); if (rc < 0) { LOG(ERROR) << "IP detection not supported" << strerror(errno); return -1; } + + if (FLAGS_quic_use_socket_timestamp) { + rc = SetGetSoftwareReceiveTimestamp(fd); + if (rc < 0) { + LOG(WARNING) << "SO_TIMESTAMPING not supported; using fallback: " + << strerror(errno); + } + } + return fd; } diff --git a/net/tools/quic/quic_socket_utils.h b/net/tools/quic/quic_socket_utils.h index a464089..72e90f8 100644 --- a/net/tools/quic/quic_socket_utils.h +++ b/net/tools/quic/quic_socket_utils.h @@ -7,6 +7,7 @@ #ifndef NET_TOOLS_QUIC_QUIC_SOCKET_UTILS_H_ #define NET_TOOLS_QUIC_QUIC_SOCKET_UTILS_H_ +#include <netinet/in.h> #include <stddef.h> #include <sys/socket.h> @@ -20,11 +21,37 @@ namespace net { +// This is the structure that SO_TIMESTAMPING fills into the cmsg header. It is +// well-defined, but does not have a definition in a public header. See +// https://www.kernel.org/doc/Documentation/networking/timestamping.txt for more +// information. +struct LinuxTimestamping { + // The converted system time of the timestamp. + struct timespec systime; + // Deprecated; serves only as padding. + struct timespec hwtimetrans; + // The raw hardware timestamp. + struct timespec hwtimeraw; +}; + class QuicSocketUtils { public: - // If the msghdr contains IP_PKTINFO or IPV6_PKTINFO, this will return the - // IPAddress in that header. Returns an empty IPAddress on failure. - static IPAddress GetAddressFromMsghdr(struct msghdr* hdr); + // The first integer is for overflow. The in6_pktinfo is the larger of the + // address structures present. LinuxTimestamping is present for socket + // timestamping. + // The final int is a sentinel so the msg_controllen feedback + // can be used to detect larger control messages than there is space for. + static const int kSpaceForCmsg = + CMSG_SPACE(CMSG_LEN(sizeof(int)) + CMSG_LEN(sizeof(in6_pktinfo)) + + CMSG_LEN(sizeof(LinuxTimestamping)) + + CMSG_LEN(sizeof(int))); + + // Fills in |address| if |hdr| contains IP_PKTINFO or IPV6_PKTINFO. Fills in + // |timestamp| if |hdr| contains |SO_TIMESTAMPING|. |address| and |timestamp| + // must not be null. + static void GetAddressAndTimestampFromMsghdr(struct msghdr* hdr, + IPAddress* address, + QuicTime* timestamp); // If the msghdr contains an SO_RXQ_OVFL entry, this will set dropped_packets // to the correct value and return true. Otherwise it will return false. @@ -35,6 +62,10 @@ class QuicSocketUtils { // address_family. Returns the return code from setsockopt. static int SetGetAddressInfo(int fd, int address_family); + // Sets SO_TIMESTAMPING on the socket for software receive timestamping. + // Returns the return code from setsockopt. + static int SetGetSoftwareReceiveTimestamp(int fd); + // Sets the send buffer size to |size| and returns false if it fails. static bool SetSendBufferSize(int fd, size_t size); @@ -50,11 +81,17 @@ class QuicSocketUtils { // // If self_address is non-null, it will be set to the address the peer sent // packets to, assuming a packet was read. + // + // If timestamp is non-null, it will be filled with the timestamp of the + // received packet, assuming a packet was read and the platform supports + // packet receipt timestamping. If the platform does not support packet + // receipt timestamping, timestamp will not be changed. static int ReadPacket(int fd, char* buffer, size_t buf_len, QuicPacketCount* dropped_packets, IPAddress* self_address, + QuicTime* timestamp, IPEndPoint* peer_address); // Writes buf_len to the socket. If writing is successful, sets the result's diff --git a/net/tools/quic/quic_spdy_client_stream.cc b/net/tools/quic/quic_spdy_client_stream.cc index af9ad0b..0274ee7 100644 --- a/net/tools/quic/quic_spdy_client_stream.cc +++ b/net/tools/quic/quic_spdy_client_stream.cc @@ -79,7 +79,7 @@ void QuicSpdyClientStream::OnTrailingHeadersComplete(bool fin, void QuicSpdyClientStream::OnPromiseHeadersComplete(QuicStreamId promised_id, size_t frame_len) { header_bytes_read_ += frame_len; - int content_length = -1; + int64_t content_length = -1; SpdyHeaderBlock promise_headers; if (!SpdyUtils::ParseHeaders(decompressed_headers().data(), decompressed_headers().length(), &content_length, @@ -111,7 +111,7 @@ void QuicSpdyClientStream::OnDataAvailable() { data_.append(static_cast<char*>(iov.iov_base), iov.iov_len); if (content_length_ >= 0 && - static_cast<int>(data_.size()) > content_length_) { + data_.size() > static_cast<uint64_t>(content_length_)) { Reset(QUIC_BAD_APPLICATION_PAYLOAD); return; } @@ -139,14 +139,4 @@ size_t QuicSpdyClientStream::SendRequest(const SpdyHeaderBlock& headers, return bytes_sent; } -void QuicSpdyClientStream::SendBody(const string& data, bool fin) { - SendBody(data, fin, nullptr); -} - -void QuicSpdyClientStream::SendBody(const string& data, - bool fin, - QuicAckListenerInterface* listener) { - WriteOrBufferData(data, fin, listener); -} - } // namespace net diff --git a/net/tools/quic/quic_spdy_client_stream.h b/net/tools/quic/quic_spdy_client_stream.h index dcb8896..f225717 100644 --- a/net/tools/quic/quic_spdy_client_stream.h +++ b/net/tools/quic/quic_spdy_client_stream.h @@ -51,18 +51,11 @@ class QuicSpdyClientStream : public QuicSpdyStream { base::StringPiece body, bool fin); - // Sends body data to the server, or buffers if it can't be sent immediately. - void SendBody(const std::string& data, bool fin); - // As above, but |delegate| will be notified once |data| is ACKed. - void SendBody(const std::string& data, - bool fin, - QuicAckListenerInterface* listener); - // Returns the response data. const std::string& data() { return data_; } // Returns whatever headers have been received for this stream. - const SpdyHeaderBlock& headers() { return response_headers_; } + const SpdyHeaderBlock& response_headers() { return response_headers_; } size_t header_bytes_read() const { return header_bytes_read_; } @@ -87,7 +80,7 @@ class QuicSpdyClientStream : public QuicSpdyStream { SpdyHeaderBlock response_headers_; // The parsed content-length, or -1 if none is specified. - int content_length_; + int64_t content_length_; int response_code_; std::string data_; size_t header_bytes_read_; diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc index 8b42df5..85452bf 100644 --- a/net/tools/quic/quic_spdy_client_stream_test.cc +++ b/net/tools/quic/quic_spdy_client_stream_test.cc @@ -100,7 +100,7 @@ TEST_F(QuicSpdyClientStreamTest, TestFraming) { stream_->OnStreamHeadersComplete(false, headers_string_.size()); stream_->OnStreamFrame( QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, body_)); - EXPECT_EQ("200", stream_->headers().find(":status")->second); + EXPECT_EQ("200", stream_->response_headers().find(":status")->second); EXPECT_EQ(200, stream_->response_code()); EXPECT_EQ(body_, stream_->data()); } @@ -110,7 +110,7 @@ TEST_F(QuicSpdyClientStreamTest, TestFramingOnePacket) { stream_->OnStreamHeadersComplete(false, headers_string_.size()); stream_->OnStreamFrame( QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, body_)); - EXPECT_EQ("200", stream_->headers().find(":status")->second); + EXPECT_EQ("200", stream_->response_headers().find(":status")->second); EXPECT_EQ(200, stream_->response_code()); EXPECT_EQ(body_, stream_->data()); } @@ -122,7 +122,7 @@ TEST_F(QuicSpdyClientStreamTest, DISABLED_TestFramingExtraData) { stream_->OnStreamHeadersComplete(false, headers_string_.size()); // The headers should parse successfully. EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error()); - EXPECT_EQ("200", stream_->headers().find(":status")->second); + EXPECT_EQ("200", stream_->response_headers().find(":status")->second); EXPECT_EQ(200, stream_->response_code()); EXPECT_CALL(*connection_, diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc index 12cb7fb..0ddfb4f 100644 --- a/net/tools/quic/quic_time_wait_list_manager_test.cc +++ b/net/tools/quic/quic_time_wait_list_manager_test.cc @@ -278,8 +278,7 @@ TEST_F(QuicTimeWaitListManagerTest, SendPublicReset) { const int kRandomSequenceNumber = 1; EXPECT_CALL(writer_, WritePacket(_, _, server_address_.address(), client_address_, _)) - .With(Args<0, 1>( - PublicResetPacketEq(connection_id_, kRandomSequenceNumber))) + .With(Args<0, 1>(PublicResetPacketEq(connection_id_, 0))) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); ProcessPacket(connection_id_, kRandomSequenceNumber); @@ -380,14 +379,14 @@ TEST_F(QuicTimeWaitListManagerTest, SendQueuedPackets) { // Let first write through. EXPECT_CALL(writer_, WritePacket(_, _, server_address_.address(), client_address_, _)) - .With(Args<0, 1>(PublicResetPacketEq(connection_id, packet_number))) + .With(Args<0, 1>(PublicResetPacketEq(connection_id, 0))) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length()))); ProcessPacket(connection_id, packet_number); // write block for the next packet. EXPECT_CALL(writer_, WritePacket(_, _, server_address_.address(), client_address_, _)) - .With(Args<0, 1>(PublicResetPacketEq(connection_id, packet_number))) + .With(Args<0, 1>(PublicResetPacketEq(connection_id, 0))) .WillOnce(DoAll(Assign(&writer_is_blocked_, true), Return(WriteResult(WRITE_STATUS_BLOCKED, EAGAIN)))); EXPECT_CALL(visitor_, OnWriteBlocked(&time_wait_list_manager_)); @@ -412,12 +411,11 @@ TEST_F(QuicTimeWaitListManagerTest, SendQueuedPackets) { writer_is_blocked_ = false; EXPECT_CALL(writer_, WritePacket(_, _, server_address_.address(), client_address_, _)) - .With(Args<0, 1>(PublicResetPacketEq(connection_id, packet_number))) + .With(Args<0, 1>(PublicResetPacketEq(connection_id, 0))) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, packet->length()))); EXPECT_CALL(writer_, WritePacket(_, _, server_address_.address(), client_address_, _)) - .With(Args<0, 1>( - PublicResetPacketEq(other_connection_id, other_packet_number))) + .With(Args<0, 1>(PublicResetPacketEq(other_connection_id, 0))) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, other_packet->length()))); time_wait_list_manager_.OnCanWrite(); } diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc index 7ce3621..97625d8 100644 --- a/net/tools/quic/test_tools/quic_test_client.cc +++ b/net/tools/quic/test_tools/quic_test_client.cc @@ -278,7 +278,7 @@ ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest( ret = stream->SendRequest(spdy_headers, body, fin); ++num_requests_; } else { - stream->SendBody(body.as_string(), fin, delegate); + stream->WriteOrBufferBody(body.as_string(), fin, delegate); ret = body.length(); } if (FLAGS_enable_quic_stateless_reject_support) { @@ -463,7 +463,7 @@ void QuicTestClient::ClearPerRequestState() { response_ = ""; response_complete_ = false; response_headers_complete_ = false; - headers_.Clear(); + response_headers_.Clear(); bytes_read_ = 0; bytes_written_ = 0; response_header_size_ = 0; @@ -531,10 +531,11 @@ bool QuicTestClient::response_headers_complete() const { const BalsaHeaders* QuicTestClient::response_headers() const { if (stream_ != nullptr) { - SpdyBalsaUtils::SpdyHeadersToResponseHeaders(stream_->headers(), &headers_); - return &headers_; + SpdyBalsaUtils::SpdyHeadersToResponseHeaders(stream_->response_headers(), + &response_headers_); + return &response_headers_; } else { - return &headers_; + return &response_headers_; } } @@ -569,13 +570,14 @@ void QuicTestClient::OnClose(QuicSpdyStream* stream) { } response_complete_ = true; response_headers_complete_ = stream_->headers_decompressed(); - SpdyBalsaUtils::SpdyHeadersToResponseHeaders(stream_->headers(), &headers_); - response_trailers_ = stream_->response_trailers(); + SpdyBalsaUtils::SpdyHeadersToResponseHeaders(stream_->response_headers(), + &response_headers_); + response_trailers_ = stream_->received_trailers(); stream_error_ = stream_->stream_error(); bytes_read_ = stream_->stream_bytes_read() + stream_->header_bytes_read(); bytes_written_ = stream_->stream_bytes_written() + stream_->header_bytes_written(); - response_header_size_ = headers_.GetSizeForWriteBuffer(); + response_header_size_ = response_headers_.GetSizeForWriteBuffer(); response_body_size_ = stream_->data().size(); stream_ = nullptr; ++num_responses_; diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h index 93cc385..b8530f4 100644 --- a/net/tools/quic/test_tools/quic_test_client.h +++ b/net/tools/quic/test_tools/quic_test_client.h @@ -240,7 +240,7 @@ class QuicTestClient : public test::SimpleClient, bool response_complete_; bool response_headers_complete_; - mutable BalsaHeaders headers_; + mutable BalsaHeaders response_headers_; // Parsed response trailers (if present), copied from the stream in OnClose. SpdyHeaderBlock response_trailers_; |