diff options
Diffstat (limited to 'chromium/net/quic')
200 files changed, 8630 insertions, 3306 deletions
diff --git a/chromium/net/quic/chromium/bidirectional_stream_quic_impl.cc b/chromium/net/quic/chromium/bidirectional_stream_quic_impl.cc index e809c3e1634..b2c48aec8a8 100644 --- a/chromium/net/quic/chromium/bidirectional_stream_quic_impl.cc +++ b/chromium/net/quic/chromium/bidirectional_stream_quic_impl.cc @@ -12,6 +12,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/timer/timer.h" #include "net/http/bidirectional_stream_request_info.h" +#include "net/http/http_util.h" #include "net/quic/core/quic_connection.h" #include "net/quic/platform/api/quic_string_piece.h" #include "net/socket/next_proto.h" @@ -68,7 +69,8 @@ void BidirectionalStreamQuicImpl::Start( const NetLogWithSource& net_log, bool send_request_headers_automatically, BidirectionalStreamImpl::Delegate* delegate, - std::unique_ptr<base::Timer> /* timer */) { + std::unique_ptr<base::Timer> timer, + const NetworkTrafficAnnotationTag& traffic_annotation) { ScopedBoolSaver saver(&may_invoke_callbacks_, false); DCHECK(!stream_); CHECK(delegate); @@ -79,12 +81,11 @@ void BidirectionalStreamQuicImpl::Start( delegate_ = delegate; request_info_ = request_info; - // TODO(https://crbug.com/656607): Add proper annotation here. int rv = session_->RequestStream( - request_info_->method == "POST", + !HttpUtil::IsMethodSafe(request_info_->method), base::Bind(&BidirectionalStreamQuicImpl::OnStreamReady, weak_factory_.GetWeakPtr()), - NO_TRAFFIC_ANNOTATION_BUG_656607); + traffic_annotation); if (rv == ERR_IO_PENDING) return; diff --git a/chromium/net/quic/chromium/bidirectional_stream_quic_impl.h b/chromium/net/quic/chromium/bidirectional_stream_quic_impl.h index 8b63600bd90..00a70d2cccb 100644 --- a/chromium/net/quic/chromium/bidirectional_stream_quic_impl.h +++ b/chromium/net/quic/chromium/bidirectional_stream_quic_impl.h @@ -41,7 +41,8 @@ class NET_EXPORT_PRIVATE BidirectionalStreamQuicImpl const NetLogWithSource& net_log, bool send_request_headers_automatically, BidirectionalStreamImpl::Delegate* delegate, - std::unique_ptr<base::Timer> timer) override; + std::unique_ptr<base::Timer> timer, + const NetworkTrafficAnnotationTag& traffic_annotation) override; void SendRequestHeaders() override; int ReadData(IOBuffer* buffer, int buffer_len) override; void SendvData(const std::vector<scoped_refptr<IOBuffer>>& buffers, diff --git a/chromium/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc b/chromium/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc index 79794cdfafc..fac7558c616 100644 --- a/chromium/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc +++ b/chromium/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc @@ -28,6 +28,7 @@ #include "net/quic/chromium/quic_chromium_packet_writer.h" #include "net/quic/chromium/quic_http_utils.h" #include "net/quic/chromium/quic_server_info.h" +#include "net/quic/chromium/quic_stream_factory.h" #include "net/quic/chromium/quic_test_packet_maker.h" #include "net/quic/chromium/test_task_runner.h" #include "net/quic/core/crypto/crypto_protocol.h" @@ -46,6 +47,7 @@ #include "net/quic/test_tools/quic_test_utils.h" #include "net/socket/socket_test_util.h" #include "net/test/gtest_util.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -167,7 +169,7 @@ class TestDelegateBase : public BidirectionalStreamImpl::Delegate { not_expect_callback_ = true; stream_ = std::make_unique<BidirectionalStreamQuicImpl>(std::move(session)); stream_->Start(request_info, net_log, send_request_headers_automatically_, - this, nullptr); + this, nullptr, TRAFFIC_ANNOTATION_FOR_TESTS); not_expect_callback_ = false; } @@ -990,28 +992,16 @@ TEST_P(BidirectionalStreamQuicImplTest, CoalesceDataBuffersNotHeadersFrame) { AddWrite(ConstructRequestHeadersPacketInner( 2, GetNthClientInitiatedStreamId(0), !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length, &header_stream_offset)); - if (FLAGS_quic_reloadable_flag_quic_use_mem_slices) { - AddWrite(ConstructDataPacket(3, kIncludeVersion, !kFin, 0, - "here are some datadata keep coming", - &client_maker_)); - } else { AddWrite(ConstructClientMultipleDataFramesPacket(3, kIncludeVersion, !kFin, 0, {kBody1, kBody2})); - } // Ack server's data packet. AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); const char kBody3[] = "hello there"; const char kBody4[] = "another piece of small data"; const char kBody5[] = "really small"; QuicStreamOffset data_offset = strlen(kBody1) + strlen(kBody2); - if (FLAGS_quic_reloadable_flag_quic_use_mem_slices) { - AddWrite(ConstructDataPacket( - 5, !kIncludeVersion, kFin, data_offset, - "hello thereanother piece of small datareally small", &client_maker_)); - } else { AddWrite(ConstructClientMultipleDataFramesPacket( 5, !kIncludeVersion, kFin, data_offset, {kBody3, kBody4, kBody5})); - } Initialize(); BidirectionalStreamRequestInfo request; @@ -1207,27 +1197,18 @@ TEST_P(BidirectionalStreamQuicImplTest, AddWrite(ConstructInitialSettingsPacket(1, &header_stream_offset)); const char kBody1[] = "here are some data"; const char kBody2[] = "data keep coming"; - const char kBody1And2[] = "here are some datadata keep coming"; std::vector<std::string> two_writes = {kBody1, kBody2}; - std::vector<std::string> one_write = {kBody1And2}; AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket( 2, !kFin, DEFAULT_PRIORITY, &header_stream_offset, - &spdy_request_headers_frame_length, - FLAGS_quic_reloadable_flag_quic_use_mem_slices ? one_write : two_writes)); + &spdy_request_headers_frame_length, two_writes)); // Ack server's data packet. AddWrite(ConstructClientAckPacket(3, 3, 1, 1)); const char kBody3[] = "hello there"; const char kBody4[] = "another piece of small data"; const char kBody5[] = "really small"; QuicStreamOffset data_offset = strlen(kBody1) + strlen(kBody2); - if (FLAGS_quic_reloadable_flag_quic_use_mem_slices) { - AddWrite(ConstructDataPacket( - 4, !kIncludeVersion, kFin, data_offset, - "hello thereanother piece of small datareally small", &client_maker_)); - } else { AddWrite(ConstructClientMultipleDataFramesPacket( 4, !kIncludeVersion, kFin, data_offset, {kBody3, kBody4, kBody5})); - } Initialize(); BidirectionalStreamRequestInfo request; @@ -1465,84 +1446,6 @@ TEST_P(BidirectionalStreamQuicImplTest, PostRequest) { delegate->GetTotalReceivedBytes()); } -TEST_P(BidirectionalStreamQuicImplTest, PutRequest) { - SetRequest("PUT", "/", DEFAULT_PRIORITY); - size_t spdy_request_headers_frame_length; - AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY, - &spdy_request_headers_frame_length)); - AddWrite(ConstructDataPacket(2, kIncludeVersion, kFin, 0, kUploadData, - &client_maker_)); - AddWrite(ConstructClientAckPacket(3, 3, 1, 1)); - - Initialize(); - - BidirectionalStreamRequestInfo request; - request.method = "PUT"; - request.url = GURL("http://www.google.com/"); - request.end_stream_on_headers = false; - request.priority = DEFAULT_PRIORITY; - - scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); - std::unique_ptr<TestDelegateBase> delegate( - new TestDelegateBase(read_buffer.get(), kReadBufferSize)); - delegate->Start(&request, net_log().bound(), - session()->CreateHandle(destination_)); - delegate->WaitUntilNextCallback(kOnStreamReady); - - // Send a DATA frame. - scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData)); - - delegate->SendData(buf, buf->size(), true); - delegate->WaitUntilNextCallback(kOnDataSent); - - // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0, 0)); - - // Server sends the response headers. - SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); - size_t spdy_response_headers_frame_length; - QuicStreamOffset offset = 0; - ProcessPacket(ConstructResponseHeadersPacket( - 2, !kFin, std::move(response_headers), - &spdy_response_headers_frame_length, &offset)); - - delegate->WaitUntilNextCallback(kOnHeadersReceived); - TestCompletionCallback cb; - int rv = delegate->ReadData(cb.callback()); - EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); - EXPECT_EQ("200", delegate->response_headers().find(":status")->second); - const char kResponseBody[] = "Hello world!"; - // Server sends data. - ProcessPacket( - ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody)); - - EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult()); - - size_t spdy_trailers_frame_length; - SpdyHeaderBlock trailers; - trailers["foo"] = "bar"; - trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody)); - // Server sends trailers. - ProcessPacket(ConstructResponseTrailersPacket( - 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset)); - - delegate->WaitUntilNextCallback(kOnTrailersReceived); - trailers.erase(kFinalOffsetHeaderKey); - EXPECT_EQ(trailers, delegate->trailers()); - EXPECT_THAT(delegate->ReadData(cb.callback()), IsOk()); - - EXPECT_EQ(1, delegate->on_data_read_count()); - EXPECT_EQ(1, delegate->on_data_sent_count()); - EXPECT_EQ(kProtoQUIC, delegate->GetProtocol()); - EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length + - strlen(kUploadData)), - delegate->GetTotalSentBytes()); - EXPECT_EQ( - static_cast<int64_t>(spdy_response_headers_frame_length + - strlen(kResponseBody) + spdy_trailers_frame_length), - delegate->GetTotalReceivedBytes()); -} - TEST_P(BidirectionalStreamQuicImplTest, InterleaveReadDataAndSendData) { SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; diff --git a/chromium/net/quic/chromium/crypto/proof_verifier_chromium_test.cc b/chromium/net/quic/chromium/crypto/proof_verifier_chromium_test.cc index 696efbbad07..942b88a118c 100644 --- a/chromium/net/quic/chromium/crypto/proof_verifier_chromium_test.cc +++ b/chromium/net/quic/chromium/crypto/proof_verifier_chromium_test.cc @@ -62,8 +62,10 @@ class MockCTPolicyEnforcer : public CTPolicyEnforcer { class MockRequireCTDelegate : public TransportSecurityState::RequireCTDelegate { public: - MOCK_METHOD1(IsCTRequiredForHost, - CTRequirementLevel(const std::string& host)); + MOCK_METHOD3(IsCTRequiredForHost, + CTRequirementLevel(const std::string& host, + const X509Certificate* chain, + const HashValueVector& hashes)); }; // Proof source callback which saves the signature into |signature|. @@ -114,9 +116,8 @@ class ProofVerifierChromiumTest : public ::testing::Test { .WillRepeatedly( Return(ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS)); - scoped_refptr<const CTLogVerifier> log( - CTLogVerifier::Create(ct::GetTestPublicKey(), kLogDescription, - "https://test.example.com", "dns.example.com")); + scoped_refptr<const CTLogVerifier> log(CTLogVerifier::Create( + ct::GetTestPublicKey(), kLogDescription, "dns.example.com")); ASSERT_TRUE(log); log_verifiers_.push_back(log); @@ -597,10 +598,10 @@ TEST_F(ProofVerifierChromiumTest, CTIsRequired) { // Set up CT. MockRequireCTDelegate require_ct_delegate; transport_security_state_.SetRequireCTDelegate(&require_ct_delegate); - EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_)) + EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_, _, _)) .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate:: CTRequirementLevel::NOT_REQUIRED)); - EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(kTestHostname)) + EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(kTestHostname, _, _)) .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate:: CTRequirementLevel::REQUIRED)); EXPECT_CALL(ct_policy_enforcer_, CheckCompliance(_, _, _)) @@ -649,10 +650,10 @@ TEST_F(ProofVerifierChromiumTest, CTIsRequiredHistogramNonCompliant) { // Set up CT. MockRequireCTDelegate require_ct_delegate; transport_security_state_.SetRequireCTDelegate(&require_ct_delegate); - EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_)) + EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_, _, _)) .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate:: CTRequirementLevel::NOT_REQUIRED)); - EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(kTestHostname)) + EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(kTestHostname, _, _)) .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate:: CTRequirementLevel::REQUIRED)); EXPECT_CALL(ct_policy_enforcer_, CheckCompliance(_, _, _)) @@ -696,10 +697,10 @@ TEST_F(ProofVerifierChromiumTest, CTIsRequiredHistogramCompliant) { // Set up CT. MockRequireCTDelegate require_ct_delegate; transport_security_state_.SetRequireCTDelegate(&require_ct_delegate); - EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_)) + EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_, _, _)) .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate:: CTRequirementLevel::NOT_REQUIRED)); - EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(kTestHostname)) + EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(kTestHostname, _, _)) .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate:: CTRequirementLevel::REQUIRED)); EXPECT_CALL(ct_policy_enforcer_, CheckCompliance(_, _, _)) @@ -805,10 +806,10 @@ TEST_F(ProofVerifierChromiumTest, PKPAndCTBothTested) { // Set up CT. MockRequireCTDelegate require_ct_delegate; transport_security_state_.SetRequireCTDelegate(&require_ct_delegate); - EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_)) + EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_, _, _)) .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate:: CTRequirementLevel::NOT_REQUIRED)); - EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(kTestHostname)) + EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(kTestHostname, _, _)) .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate:: CTRequirementLevel::REQUIRED)); EXPECT_CALL(ct_policy_enforcer_, CheckCompliance(_, _, _)) @@ -917,7 +918,7 @@ TEST_F(ProofVerifierChromiumTest, CTRequirementsFlagNotMet) { // Set up CT. MockRequireCTDelegate require_ct_delegate; transport_security_state_.SetRequireCTDelegate(&require_ct_delegate); - EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_)) + EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_, _, _)) .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate:: CTRequirementLevel::REQUIRED)); EXPECT_CALL(ct_policy_enforcer_, CheckCompliance(_, _, _)) @@ -959,7 +960,7 @@ TEST_F(ProofVerifierChromiumTest, CTRequirementsFlagMet) { // Set up CT. MockRequireCTDelegate require_ct_delegate; transport_security_state_.SetRequireCTDelegate(&require_ct_delegate); - EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_)) + EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_, _, _)) .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate:: CTRequirementLevel::REQUIRED)); EXPECT_CALL(ct_policy_enforcer_, CheckCompliance(_, _, _)) diff --git a/chromium/net/quic/chromium/quic_chromium_client_session.cc b/chromium/net/quic/chromium/quic_chromium_client_session.cc index d366ad8a759..fcbaa1349a8 100644 --- a/chromium/net/quic/chromium/quic_chromium_client_session.cc +++ b/chromium/net/quic/chromium/quic_chromium_client_session.cc @@ -76,6 +76,12 @@ const int kDefaultRTTMilliSecs = 300; // The maximum size of uncompressed QUIC headers that will be allowed. const size_t kMaxUncompressedHeaderSize = 256 * 1024; +// The maximum time allowed to have no retransmittable packets on the wire +// (after sending the first retransmittable packet) if +// |migrate_session_early_v2_| is true. PING frames will be sent as needed to +// enforce this. +const size_t kDefaultRetransmittableOnWireTimeoutMillisecs = 100; + // Histograms for tracking down the crashes from http://crbug.com/354669 // Note: these values must be kept in sync with the corresponding values in: // tools/metrics/histograms/histograms.xml @@ -130,26 +136,6 @@ std::unique_ptr<base::Value> NetLogQuicConnectionMigrationSuccessCallback( return std::move(dict); } -void HistogramAndLogMigrationFailure(const NetLogWithSource& net_log, - enum QuicConnectionMigrationStatus status, - QuicConnectionId connection_id, - std::string reason) { - UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionMigration", status, - MIGRATION_STATUS_MAX); - net_log.AddEvent(NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE, - base::Bind(&NetLogQuicConnectionMigrationFailureCallback, - connection_id, reason)); -} - -void HistogramAndLogMigrationSuccess(const NetLogWithSource& net_log, - QuicConnectionId connection_id) { - UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionMigration", - MIGRATION_STATUS_SUCCESS, MIGRATION_STATUS_MAX); - net_log.AddEvent( - NetLogEventType::QUIC_CONNECTION_MIGRATION_SUCCESS, - base::Bind(&NetLogQuicConnectionMigrationSuccessCallback, connection_id)); -} - // Histogram for recording the different reasons that a QUIC session is unable // to complete the handshake. enum HandshakeFailureReason { @@ -180,6 +166,29 @@ void RecordHandshakeState(HandshakeState state) { NUM_HANDSHAKE_STATES); } +std::string ConnectionMigrationCauseToString(ConnectionMigrationCause cause) { + switch (cause) { + case UNKNOWN: + return "Unknown"; + case ON_NETWORK_CONNECTED: + return "OnNetworkConnected"; + case ON_NETWORK_DISCONNECTED: + return "OnNetworkDisconnected"; + case ON_WRITE_ERROR: + return "OnWriteError"; + case ON_NETWORK_MADE_DEFAULT: + return "OnNetworkMadeDefault"; + case ON_MIGRATE_BACK_TO_DEFAULT_NETWORK: + return "OnMigrateBackToDefaultNetwork"; + case ON_PATH_DEGRADING: + return "OnPathDegrading"; + default: + QUIC_NOTREACHED(); + break; + } + return "InvalidCause"; +} + std::unique_ptr<base::Value> NetLogQuicClientSessionCallback( const QuicServerId* server_id, int cert_verify_flags, @@ -207,6 +216,19 @@ std::unique_ptr<base::Value> NetLogQuicPushPromiseReceivedCallback( return std::move(dict); } +// TODO(fayang): Remove this when necessary data is collected. +void LogProbeResultToHistogram(ConnectionMigrationCause cause, bool success) { + UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ConnectionMigrationProbeSuccess", + success); + const std::string histogram_name = + "Net.QuicSession.ConnectionMigrationProbeSuccess." + + ConnectionMigrationCauseToString(cause); + STATIC_HISTOGRAM_POINTER_GROUP( + histogram_name, cause, MIGRATION_CAUSE_MAX, AddBoolean(success), + base::BooleanHistogram::FactoryGet( + histogram_name, base::HistogramBase::kUmaTargetedHistogramFlag)); +} + class HpackEncoderDebugVisitor : public QuicHpackDebugVisitor { void OnUseEntry(QuicTime::Delta elapsed) override { UMA_HISTOGRAM_TIMES( @@ -721,6 +743,7 @@ QuicChromiumClientSession::QuicChromiumClientSession( bytes_pushed_and_unclaimed_count_(0), probing_manager_(this, task_runner_), retry_migrate_back_count_(0), + current_connection_migration_cause_(UNKNOWN), migration_pending_(false), headers_include_h2_stream_dependency_( headers_include_h2_stream_dependency && @@ -751,6 +774,11 @@ QuicChromiumClientSession::QuicChromiumClientSession( } connect_timing_.dns_start = dns_resolution_start_time; connect_timing_.dns_end = dns_resolution_end_time; + if (migrate_session_early_v2_) { + connection->set_retransmittable_on_wire_timeout( + QuicTime::Delta::FromMilliseconds( + kDefaultRetransmittableOnWireTimeoutMillisecs)); + } } QuicChromiumClientSession::~QuicChromiumClientSession() { @@ -780,7 +808,7 @@ QuicChromiumClientSession::~QuicChromiumClientSession() { if (connection()->connected()) { // Ensure that the connection is closed by the time the session is // destroyed. - RecordInternalErrorLocation(QUIC_CHROMIUM_CLIENT_SESSION); + RecordInternalErrorLocation(QUIC_CHROMIUM_CLIENT_SESSION_DESTRUCTOR); connection()->CloseConnection(QUIC_INTERNAL_ERROR, "session torn down", ConnectionCloseBehavior::SILENT_CLOSE); } @@ -900,11 +928,12 @@ void QuicChromiumClientSession::OnHeadersHeadOfLineBlocking( base::TimeDelta::FromMicroseconds(delta.ToMicroseconds())); } -void QuicChromiumClientSession::UnregisterStreamPriority(QuicStreamId id) { - if (headers_include_h2_stream_dependency_) { +void QuicChromiumClientSession::UnregisterStreamPriority(QuicStreamId id, + bool is_static) { + if (headers_include_h2_stream_dependency_ && !is_static) { priority_dependency_state_.OnStreamDestruction(id); } - QuicSpdySession::UnregisterStreamPriority(id); + QuicSpdySession::UnregisterStreamPriority(id, is_static); } void QuicChromiumClientSession::UpdateStreamPriority( @@ -1563,7 +1592,7 @@ void QuicChromiumClientSession::OnConnectionClosed( void QuicChromiumClientSession::OnSuccessfulVersionNegotiation( const ParsedQuicVersion& version) { - logger_->OnSuccessfulVersionNegotiation(version.transport_version); + logger_->OnSuccessfulVersionNegotiation(version); QuicSpdySession::OnSuccessfulVersionNegotiation(version); } @@ -1619,6 +1648,8 @@ void QuicChromiumClientSession::MigrateSessionOnWriteError(int error_code) { if (!migration_pending_) return; + current_connection_migration_cause_ = ON_WRITE_ERROR; + MigrationResult result = MigrationResult::FAILURE; if (stream_factory_ != nullptr) { const NetLogWithSource migration_net_log = NetLogWithSource::Make( @@ -1672,11 +1703,7 @@ void QuicChromiumClientSession::WriteToNewSocket() { // Unblock the connection before sending a PING packet, since it // may have been blocked before the migration started. connection()->OnCanWrite(); - if (use_control_frame_manager()) { - SendPing(); - } else { - connection()->SendPing(); - } + SendPing(); return; } @@ -1700,9 +1727,8 @@ void QuicChromiumClientSession::OnMigrationTimeout(size_t num_sockets) { // If number of sockets has changed, this migration task is stale. if (num_sockets != sockets_.size()) return; - UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionMigration", - MIGRATION_STATUS_NO_ALTERNATE_NETWORK, - MIGRATION_STATUS_MAX); + + LogConnectionMigrationResultToHistogram(MIGRATION_STATUS_TIMEOUT); CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK); } @@ -1721,6 +1747,8 @@ void QuicChromiumClientSession::OnProbeNetworkSucceeded( NetLogEventType::QUIC_CONNECTION_CONNECTIVITY_PROBING_SUCCEEDED, NetLog::Int64Callback("network", network)); + LogProbeResultToHistogram(current_connection_migration_cause_, true); + // Set |this| to listen on socket write events on the packet writer // that was used for probing. writer->set_delegate(this); @@ -1745,6 +1773,7 @@ void QuicChromiumClientSession::OnProbeNetworkSucceeded( << "successful probing network: " << network << "."; current_migrations_to_non_default_network_on_path_degrading_++; if (!migrate_back_to_default_timer_.IsRunning()) { + current_connection_migration_cause_ = ON_MIGRATE_BACK_TO_DEFAULT_NETWORK; // Session gets off the |default_network|, stay on |network| for now but // try to migrate back to default network after 1 second. StartMigrateBackToDefaultNetworkTimer( @@ -1758,6 +1787,8 @@ void QuicChromiumClientSession::OnProbeNetworkFailed( net_log_.AddEvent( NetLogEventType::QUIC_CONNECTION_CONNECTIVITY_PROBING_FAILED, NetLog::Int64Callback("network", network)); + + LogProbeResultToHistogram(current_connection_migration_cause_, false); // Probing failure for default network can be ignored. DVLOG(1) << "Connectivity probing failed on NetworkHandle " << network; DVLOG_IF(1, network == default_network_ && @@ -1782,6 +1813,7 @@ void QuicChromiumClientSession::OnNetworkConnected( if (!migration_pending_) return; + current_connection_migration_cause_ = ON_NETWORK_CONNECTED; // |migration_pending_| is true, there was no working network previously. // |network| is now the only possible candidate, migrate immediately. if (migrate_session_on_network_change_v2_) { @@ -1806,6 +1838,7 @@ void QuicChromiumClientSession::OnNetworkDisconnected( if (!migrate_session_on_network_change_) return; + current_connection_migration_cause_ = ON_NETWORK_DISCONNECTED; MaybeMigrateOrCloseSession( alternate_network, /*close_if_cannot_migrate*/ true, migration_net_log); } @@ -1829,6 +1862,7 @@ void QuicChromiumClientSession::OnNetworkDisconnectedV2( return; } + current_connection_migration_cause_ = ON_NETWORK_DISCONNECTED; // Attempt to find alternative network. NetworkChangeNotifier::NetworkHandle new_network = stream_factory_->FindAlternateNetwork(disconnected_network); @@ -1837,6 +1871,7 @@ void QuicChromiumClientSession::OnNetworkDisconnectedV2( OnNoNewNetwork(); return; } + // Current network is being disconnected, migrate immediately to the // alternative network. MigrateImmediately(new_network); @@ -1855,6 +1890,7 @@ void QuicChromiumClientSession::OnNetworkMadeDefault( DCHECK_NE(NetworkChangeNotifier::kInvalidNetworkHandle, new_network); default_network_ = new_network; + current_connection_migration_cause_ = ON_NETWORK_MADE_DEFAULT; if (!migrate_session_on_network_change_v2_) { MaybeMigrateOrCloseSession(new_network, /*close_if_cannot_migrate*/ false, @@ -1943,6 +1979,7 @@ void QuicChromiumClientSession::OnPathDegrading() { NetworkChangeNotifier::NetworkHandle alternate_network = stream_factory_->FindAlternateNetwork( GetDefaultSocket()->GetBoundNetwork()); + current_connection_migration_cause_ = ON_PATH_DEGRADING; if (alternate_network != NetworkChangeNotifier::kInvalidNetworkHandle) { if (GetDefaultSocket()->GetBoundNetwork() == default_network_ && current_migrations_to_non_default_network_on_path_degrading_ >= @@ -1970,8 +2007,8 @@ void QuicChromiumClientSession::OnPathDegrading() { migration_net_log); } else { HistogramAndLogMigrationFailure( - migration_net_log, MIGRATION_STATUS_NOT_ENABLED, connection_id(), - "Migration on path degrading not enabled"); + migration_net_log, MIGRATION_STATUS_PATH_DEGRADING_NOT_ENABLED, + connection_id(), "Migration on path degrading not enabled"); } migration_net_log.EndEvent( NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED); @@ -2027,6 +2064,10 @@ void QuicChromiumClientSession::StartReading() { void QuicChromiumClientSession::CloseSessionOnError(int net_error, QuicErrorCode quic_error) { base::UmaHistogramSparse("Net.QuicSession.CloseSessionOnError", -net_error); + if (quic_error == QUIC_INTERNAL_ERROR) { + RecordInternalErrorLocation( + QUIC_CHROMIUM_CLIENT_SESSION_CLOSE_SESSION_ON_ERROR); + } if (!callback_.is_null()) { base::ResetAndReturn(&callback_).Run(net_error); @@ -2189,6 +2230,9 @@ ProbingResult QuicChromiumClientSession::StartProbeNetwork( void QuicChromiumClientSession::StartMigrateBackToDefaultNetworkTimer( base::TimeDelta delay) { + if (current_connection_migration_cause_ != ON_NETWORK_MADE_DEFAULT) + current_connection_migration_cause_ = ON_MIGRATE_BACK_TO_DEFAULT_NETWORK; + CancelMigrateBackToDefaultNetworkTimer(); // Post a task to try migrate back to default network after |delay|. migrate_back_to_default_timer_.Start( @@ -2360,6 +2404,40 @@ void QuicChromiumClientSession::LogMetricsOnNetworkMadeDefault() { } } +void QuicChromiumClientSession::LogConnectionMigrationResultToHistogram( + QuicConnectionMigrationStatus status) { + UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionMigration", status, + MIGRATION_STATUS_MAX); + + // Log the connection migraiton result to different histograms based on the + // cause of the connection migration. + std::string histogram_name = + "Net.QuicSession.ConnectionMigration." + + ConnectionMigrationCauseToString(current_connection_migration_cause_); + base::UmaHistogramEnumeration(histogram_name, status, MIGRATION_STATUS_MAX); + current_connection_migration_cause_ = UNKNOWN; +} + +void QuicChromiumClientSession::HistogramAndLogMigrationFailure( + const NetLogWithSource& net_log, + QuicConnectionMigrationStatus status, + QuicConnectionId connection_id, + const std::string& reason) { + LogConnectionMigrationResultToHistogram(status); + net_log.AddEvent(NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE, + base::Bind(&NetLogQuicConnectionMigrationFailureCallback, + connection_id, reason)); +} + +void QuicChromiumClientSession::HistogramAndLogMigrationSuccess( + const NetLogWithSource& net_log, + QuicConnectionId connection_id) { + LogConnectionMigrationResultToHistogram(MIGRATION_STATUS_SUCCESS); + net_log.AddEvent( + NetLogEventType::QUIC_CONNECTION_MIGRATION_SUCCESS, + base::Bind(&NetLogQuicConnectionMigrationSuccessCallback, connection_id)); +} + std::unique_ptr<base::Value> QuicChromiumClientSession::GetInfoAsValue( const std::set<HostPortPair>& aliases) { std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); @@ -2403,13 +2481,31 @@ void QuicChromiumClientSession::OnReadError( int result, const DatagramClientSocket* socket) { DCHECK(socket != nullptr); + base::UmaHistogramSparse("Net.QuicSession.ReadError.AnyNetwork", -result); if (socket != GetDefaultSocket()) { - // Ignore read errors from old sockets that are no longer active. + base::UmaHistogramSparse("Net.QuicSession.ReadError.OtherNetworks", + -result); + // Ignore read errors from sockets that are not affecting the current + // network, i.e., sockets that are no longer active and probing socket. // TODO(jri): Maybe clean up old sockets on error. return; } + + base::UmaHistogramSparse("Net.QuicSession.ReadError.CurrentNetwork", -result); + if (IsCryptoHandshakeConfirmed()) { + base::UmaHistogramSparse( + "Net.QuicSession.ReadError.CurrentNetwork.HandshakeConfirmed", -result); + } + + if (migration_pending_) { + // Ignore read errors during pending migration. Connection will be closed if + // pending migration failed or timed out. + base::UmaHistogramSparse("Net.QuicSession.ReadError.PendingMigration", + -result); + return; + } + DVLOG(1) << "Closing session on read error: " << result; - base::UmaHistogramSparse("Net.QuicSession.ReadError", -result); connection()->CloseConnection(QUIC_PACKET_READ_ERROR, ErrorToString(result), ConnectionCloseBehavior::SILENT_CLOSE); } @@ -2666,7 +2762,7 @@ bool QuicChromiumClientSession::HandlePromised(QuicStreamId id, // push promise headers are received, send a PRIORITY frame for the // promised stream ID. Send |kDefaultPriority| since that will be the // initial SpdyPriority of the push promise stream when created. - const SpdyPriority priority = kDefaultPriority; + const SpdyPriority priority = QuicStream::kDefaultPriority; SpdyStreamId parent_stream_id = 0; int weight = 0; bool exclusive = false; diff --git a/chromium/net/quic/chromium/quic_chromium_client_session.h b/chromium/net/quic/chromium/quic_chromium_client_session.h index 21b4cb4bfc0..68ef0c92f0e 100644 --- a/chromium/net/quic/chromium/quic_chromium_client_session.h +++ b/chromium/net/quic/chromium/quic_chromium_client_session.h @@ -81,6 +81,35 @@ enum class ConnectionMigrationMode { FULL_MIGRATION_V2 }; +// Cause of connection migration. +enum ConnectionMigrationCause { + UNKNOWN, + ON_NETWORK_CONNECTED, // No probing. + ON_NETWORK_DISCONNECTED, // No probing. + ON_WRITE_ERROR, // No probing. + ON_NETWORK_MADE_DEFAULT, // With probing. + ON_MIGRATE_BACK_TO_DEFAULT_NETWORK, // With probing. + ON_PATH_DEGRADING, // With probing. + MIGRATION_CAUSE_MAX +}; + +// Result of connection migration. +enum QuicConnectionMigrationStatus { + MIGRATION_STATUS_NO_MIGRATABLE_STREAMS, + MIGRATION_STATUS_ALREADY_MIGRATED, + MIGRATION_STATUS_INTERNAL_ERROR, + MIGRATION_STATUS_TOO_MANY_CHANGES, + MIGRATION_STATUS_SUCCESS, + MIGRATION_STATUS_NON_MIGRATABLE_STREAM, + MIGRATION_STATUS_NOT_ENABLED, + MIGRATION_STATUS_NO_ALTERNATE_NETWORK, + MIGRATION_STATUS_ON_PATH_DEGRADING_DISABLED, + MIGRATION_STATUS_DISABLED_BY_CONFIG, + MIGRATION_STATUS_PATH_DEGRADING_NOT_ENABLED, + MIGRATION_STATUS_TIMEOUT, + MIGRATION_STATUS_MAX +}; + // Result of a connectivity probing attempt. enum class ProbingResult { PENDING, // Probing started, pending result. @@ -426,7 +455,7 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) override; void OnHeadersHeadOfLineBlocking(QuicTime::Delta delta) override; - void UnregisterStreamPriority(QuicStreamId id) override; + void UnregisterStreamPriority(QuicStreamId id, bool is_static) override; void UpdateStreamPriority(QuicStreamId id, SpdyPriority new_priority) override; @@ -687,6 +716,14 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession const NetLogWithSource& migration_net_log); void LogMetricsOnNetworkDisconnected(); void LogMetricsOnNetworkMadeDefault(); + void LogConnectionMigrationResultToHistogram( + QuicConnectionMigrationStatus status); + void HistogramAndLogMigrationFailure(const NetLogWithSource& net_log, + QuicConnectionMigrationStatus status, + QuicConnectionId connection_id, + const std::string& reason); + void HistogramAndLogMigrationSuccess(const NetLogWithSource& net_log, + QuicConnectionId connection_id); // Notifies the factory that this session is going away and no more streams // should be created from it. This needs to be called before closing any @@ -763,6 +800,7 @@ class NET_EXPORT_PRIVATE QuicChromiumClientSession QuicConnectivityProbingManager probing_manager_; int retry_migrate_back_count_; base::OneShotTimer migrate_back_to_default_timer_; + ConnectionMigrationCause current_connection_migration_cause_; // TODO(jri): Replace use of migration_pending_ sockets_.size(). // When a task is posted for MigrateSessionOnError, pass in // sockets_.size(). Then in MigrateSessionOnError, check to see if diff --git a/chromium/net/quic/chromium/quic_chromium_client_session_test.cc b/chromium/net/quic/chromium/quic_chromium_client_session_test.cc index 88e20fb455a..36509ccb712 100644 --- a/chromium/net/quic/chromium/quic_chromium_client_session_test.cc +++ b/chromium/net/quic/chromium/quic_chromium_client_session_test.cc @@ -7,7 +7,6 @@ #include "base/base64.h" #include "base/files/file_path.h" #include "base/memory/ptr_util.h" -#include "base/rand_util.h" #include "base/run_loop.h" #include "base/test/histogram_tester.h" #include "base/threading/thread_task_runner_handle.h" @@ -36,14 +35,16 @@ #include "net/quic/core/quic_packet_writer.h" #include "net/quic/core/tls_client_handshaker.h" #include "net/quic/platform/api/quic_flags.h" -#include "net/quic/platform/impl/quic_test_impl.h" +#include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/quic_client_promised_info_peer.h" +#include "net/quic/test_tools/quic_connection_peer.h" #include "net/quic/test_tools/quic_stream_peer.h" #include "net/quic/test_tools/quic_test_utils.h" #include "net/quic/test_tools/simple_quic_framer.h" #include "net/socket/datagram_client_socket.h" #include "net/socket/socket_test_util.h" +#include "net/spdy/chromium/spdy_test_util_common.h" #include "net/spdy/core/spdy_test_utils.h" #include "net/test/cert_test_util.h" #include "net/test/gtest_util.h" @@ -111,7 +112,8 @@ class QuicChromiumClientSessionTest &clock_, kServerHostname, Perspective::IS_SERVER, - false) { + false), + migrate_session_early_v2_(false) { // Advance the time, because timers do not like uninitialized times. clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); } @@ -129,7 +131,6 @@ class QuicChromiumClientSessionTest socket_factory_.AddSocketDataProvider(socket_data_.get()); std::unique_ptr<DatagramClientSocket> socket = socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND, - base::Bind(&base::RandInt), &net_log_, NetLogSource()); socket->Connect(kIpEndPoint); QuicChromiumPacketWriter* writer = new net::QuicChromiumPacketWriter( @@ -144,10 +145,9 @@ class QuicChromiumClientSessionTest /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_, &transport_security_state_, base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)), session_key_, - /*require_confirmation=*/false, /*migrate_session_early*/ false, - /*migrate_session_on_network_change*/ false, - /*migrate_session_early_v2*/ false, - /*migrate_session_on_network_change_v2*/ false, + /*require_confirmation=*/false, /*migrate_session_early=*/false, + /*migrate_session_on_network_change=*/false, migrate_session_early_v2_, + /*migrate_session_on_network_change_v2=*/false, base::TimeDelta::FromSeconds(kMaxTimeOnNonDefaultNetworkSecs), kMaxMigrationsToNonDefaultNetworkOnPathDegrading, kQuicYieldAfterPacketsRead, @@ -219,6 +219,7 @@ class QuicChromiumClientSessionTest QuicTestPacketMaker client_maker_; QuicTestPacketMaker server_maker_; ProofVerifyDetailsChromium verify_details_; + bool migrate_session_early_v2_; }; INSTANTIATE_TEST_CASE_P( @@ -1236,15 +1237,9 @@ TEST_P(QuicChromiumClientSessionTest, MigrateToSocket) { char data[] = "ABCD"; std::unique_ptr<QuicEncryptedPacket> client_ping; std::unique_ptr<QuicEncryptedPacket> ack_and_data_out; - if (session_->use_control_frame_manager()) { client_ping = client_maker_.MakeAckAndPingPacket(2, false, 1, 1, 1); ack_and_data_out = client_maker_.MakeDataPacket(3, 5, false, false, 0, QuicStringPiece(data)); - } else { - client_ping = client_maker_.MakePingPacket(2, /*include_version=*/false); - ack_and_data_out = client_maker_.MakeAckAndDataPacket( - 3, false, 5, 1, 1, 1, false, 0, QuicStringPiece(data)); - } std::unique_ptr<QuicEncryptedPacket> server_ping( server_maker_.MakePingPacket(1, /*include_version=*/false)); MockRead reads[] = { @@ -1260,7 +1255,6 @@ TEST_P(QuicChromiumClientSessionTest, MigrateToSocket) { // Create connected socket. std::unique_ptr<DatagramClientSocket> new_socket = socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND, - base::Bind(&base::RandInt), &net_log_, NetLogSource()); EXPECT_THAT(new_socket->Connect(kIpEndPoint), IsOk()); @@ -1319,7 +1313,6 @@ TEST_P(QuicChromiumClientSessionTest, MigrateToSocketMaxReaders) { // Create connected socket. std::unique_ptr<DatagramClientSocket> new_socket = socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND, - base::Bind(&base::RandInt), &net_log_, NetLogSource()); EXPECT_THAT(new_socket->Connect(kIpEndPoint), IsOk()); @@ -1355,11 +1348,7 @@ TEST_P(QuicChromiumClientSessionTest, MigrateToSocketReadError) { std::unique_ptr<QuicEncryptedPacket> settings_packet( client_maker_.MakeInitialSettingsPacket(1, nullptr)); std::unique_ptr<QuicEncryptedPacket> client_ping; - if (FLAGS_quic_reloadable_flag_quic_use_control_frame_manager) { client_ping = client_maker_.MakeAckAndPingPacket(2, false, 1, 1, 1); - } else { - client_ping = client_maker_.MakePingPacket(2, /*include_version=*/false); - } std::unique_ptr<QuicEncryptedPacket> server_ping( server_maker_.MakePingPacket(1, /*include_version=*/false)); MockWrite old_writes[] = { @@ -1386,7 +1375,6 @@ TEST_P(QuicChromiumClientSessionTest, MigrateToSocketReadError) { // Create connected socket. std::unique_ptr<DatagramClientSocket> new_socket = socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND, - base::Bind(&base::RandInt), &net_log_, NetLogSource()); EXPECT_THAT(new_socket->Connect(kIpEndPoint), IsOk()); @@ -1425,6 +1413,53 @@ TEST_P(QuicChromiumClientSessionTest, MigrateToSocketReadError) { EXPECT_TRUE(new_socket_data.AllWriteDataConsumed()); } +TEST_P(QuicChromiumClientSessionTest, RetransmittableOnWireTimeout) { + migrate_session_early_v2_ = true; + + MockQuicData quic_data; + quic_data.AddWrite(client_maker_.MakeInitialSettingsPacket(1, nullptr)); + quic_data.AddWrite(client_maker_.MakePingPacket(2, true)); + quic_data.AddRead(server_maker_.MakeAckPacket(1, 2, 1, 1, false)); + + quic_data.AddWrite(client_maker_.MakePingPacket(3, false)); + quic_data.AddRead(ASYNC, ERR_IO_PENDING); + quic_data.AddRead(ASYNC, OK); // EOF + quic_data.AddSocketDataToFactory(&socket_factory_); + + Initialize(); + CompleteCryptoHandshake(); + + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), + session_->connection()->retransmittable_on_wire_timeout()); + + // Open a stream since the connection only sends PINGs to keep a + // retransmittable packet on the wire if there's an open stream. + EXPECT_TRUE(QuicChromiumClientSessionPeer::CreateOutgoingDynamicStream( + session_.get())); + + QuicAlarm* alarm = + QuicConnectionPeer::GetRetransmittableOnWireAlarm(session_->connection()); + EXPECT_FALSE(alarm->IsSet()); + + // Send PING, which will be ACKed by the server. After the ACK, there will be + // no retransmittable packets on the wire, so the alarm should be set. + session_->SendPing(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(alarm->IsSet()); + EXPECT_EQ(clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(100), + alarm->deadline()); + + // Advance clock and simulate the alarm firing. This should cause a PING to be + // sent. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100)); + alarm_factory_.FireAlarm(alarm); + base::RunLoop().RunUntilIdle(); + + quic_data.Resume(); + EXPECT_TRUE(quic_data.AllReadDataConsumed()); + EXPECT_TRUE(quic_data.AllWriteDataConsumed()); +} + } // namespace } // namespace test } // namespace net diff --git a/chromium/net/quic/chromium/quic_chromium_client_stream.cc b/chromium/net/quic/chromium/quic_chromium_client_stream.cc index 4db1630d7dc..aa886ddd2e1 100644 --- a/chromium/net/quic/chromium/quic_chromium_client_stream.cc +++ b/chromium/net/quic/chromium/quic_chromium_client_stream.cc @@ -18,6 +18,7 @@ #include "net/quic/core/quic_spdy_session.h" #include "net/quic/core/quic_write_blocked_list.h" #include "net/quic/core/spdy_utils.h" +#include "net/spdy/chromium/spdy_log_util.h" namespace net { namespace { @@ -536,17 +537,11 @@ bool QuicChromiumClientStream::WritevStreamData( // Must not be called when data is buffered. DCHECK(!HasBufferedData()); // Writes the data, or buffers it. - if (session_->can_use_slices()) { - WriteMemSlices(QuicMemSliceSpan(QuicMemSliceSpanImpl( - buffers.data(), lengths.data(), buffers.size())), - fin); - } else { for (size_t i = 0; i < buffers.size(); ++i) { bool is_fin = fin && (i == buffers.size() - 1); QuicStringPiece string_data(buffers[i]->data(), lengths[i]); WriteOrBufferData(string_data, is_fin, nullptr); } - } return !HasBufferedData(); // Was all data written? } diff --git a/chromium/net/quic/chromium/quic_chromium_client_stream_test.cc b/chromium/net/quic/chromium/quic_chromium_client_stream_test.cc index bd6ba937536..e37e55f6d8d 100644 --- a/chromium/net/quic/chromium/quic_chromium_client_stream_test.cc +++ b/chromium/net/quic/chromium/quic_chromium_client_stream_test.cc @@ -606,14 +606,9 @@ TEST_P(QuicChromiumClientStreamTest, WritevStreamData) { new StringIOBuffer("Just a small payload")); // All data written. - if (session_.can_use_slices()) { - EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _)) - .WillOnce(Return(QuicConsumedData(buf1->size() + buf2->size(), true))); - } else { EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _)) .WillOnce(Return(QuicConsumedData(buf1->size(), false))) .WillOnce(Return(QuicConsumedData(buf2->size(), true))); - } TestCompletionCallback callback; EXPECT_EQ( OK, handle_->WritevStreamData({buf1, buf2}, {buf1->size(), buf2->size()}, @@ -626,16 +621,11 @@ TEST_P(QuicChromiumClientStreamTest, WritevStreamDataAsync) { new StringIOBuffer("Just a small payload")); // Only a part of the data is written. - if (session_.can_use_slices()) { - EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _)) - .WillOnce(Return(QuicConsumedData(buf1->size(), false))); - } else { EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _)) // First piece of data is written. .WillOnce(Return(QuicConsumedData(buf1->size(), false))) // Second piece of data is queued. .WillOnce(Return(QuicConsumedData(0, false))); - } TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, handle_->WritevStreamData({buf1.get(), buf2.get()}, diff --git a/chromium/net/quic/chromium/quic_chromium_packet_writer.cc b/chromium/net/quic/chromium/quic_chromium_packet_writer.cc index af3b7c0a20b..5786a7f0192 100644 --- a/chromium/net/quic/chromium/quic_chromium_packet_writer.cc +++ b/chromium/net/quic/chromium/quic_chromium_packet_writer.cc @@ -38,6 +38,32 @@ void RecordRetryCount(int count) { count, kMaxRetries + 1); } +const net::NetworkTrafficAnnotationTag kTrafficAnnotation = + net::DefineNetworkTrafficAnnotation("quic_chromium_packet_writer", R"( + semantics { + sender: "QUIC Packet Writer" + description: + "A QUIC packet is written to the wire based on a request from " + "a QUIC stream." + trigger: + "A request from QUIC stream." + data: "Any data sent by the stream." + destination: OTHER + destination_other: "Any destination choosen by the stream." + } + policy { + cookies_allowed: NO + setting: "This feature cannot be disabled in settings." + policy_exception_justification: + "Essential for network access." + } + comments: + "All requests that are received by QUIC streams have network traffic " + "annotation, but the annotation is not passed to the writer function " + "due to technial overheads. Please see QuicChromiumClientSession and " + "QuicChromiumClientStream classes for references." + )"); + } // namespace QuicChromiumPacketWriter::ReusableIOBuffer::ReusableIOBuffer(size_t capacity) @@ -108,34 +134,9 @@ WriteResult QuicChromiumPacketWriter::WritePacketToSocket( WriteResult QuicChromiumPacketWriter::WritePacketToSocketImpl() { base::TimeTicks now = base::TimeTicks::Now(); - net::NetworkTrafficAnnotationTag traffic_annotation = - net::DefineNetworkTrafficAnnotation("quic_chromium_packet_writer", R"( - semantics { - sender: "QUIC Packet Writer" - description: - "A QUIC packet is written to the wire based on a request from " - "a QUIC stream." - trigger: - "A request from QUIC stream." - data: "Any data sent by the stream." - destination: OTHER - destination_other: "Any destination choosen by the stream." - } - policy { - cookies_allowed: NO - setting: "This feature cannot be disabled in settings." - policy_exception_justification: - "Essential for network access." - } - comments: - "All requests that are received by QUIC streams have network traffic " - "annotation, but the annotation is not passed to the writer function " - "due to technial overheads. Please see QuicChromiumClientSession and " - "QuicChromiumClientStream classes for references." - )"); int rv = socket_->Write(packet_.get(), packet_->size(), write_callback_, - traffic_annotation); + kTrafficAnnotation); if (MaybeRetryAfterWriteError(rv)) return WriteResult(WRITE_STATUS_BLOCKED, ERR_IO_PENDING); diff --git a/chromium/net/quic/chromium/quic_connection_logger.cc b/chromium/net/quic/chromium/quic_connection_logger.cc index 048c4922a2e..d9e4ceefd38 100644 --- a/chromium/net/quic/chromium/quic_connection_logger.cc +++ b/chromium/net/quic/chromium/quic_connection_logger.cc @@ -711,10 +711,10 @@ void QuicConnectionLogger::OnConnectionClosed(QuicErrorCode error, } void QuicConnectionLogger::OnSuccessfulVersionNegotiation( - const QuicTransportVersion& version) { + const ParsedQuicVersion& version) { if (!net_log_is_capturing_) return; - string quic_version = QuicVersionToString(version); + string quic_version = QuicVersionToString(version.transport_version); net_log_.AddEvent(NetLogEventType::QUIC_SESSION_VERSION_NEGOTIATED, NetLog::StringCallback("version", &quic_version)); } diff --git a/chromium/net/quic/chromium/quic_connection_logger.h b/chromium/net/quic/chromium/quic_connection_logger.h index 07b6894e456..25638374c46 100644 --- a/chromium/net/quic/chromium/quic_connection_logger.h +++ b/chromium/net/quic/chromium/quic_connection_logger.h @@ -77,7 +77,7 @@ class NET_EXPORT_PRIVATE QuicConnectionLogger const std::string& error_details, ConnectionCloseSource source) override; void OnSuccessfulVersionNegotiation( - const QuicTransportVersion& version) override; + const ParsedQuicVersion& version) override; void OnRttChanged(QuicTime::Delta rtt) const override; void OnCryptoHandshakeMessageReceived(const CryptoHandshakeMessage& message); diff --git a/chromium/net/quic/chromium/quic_connectivity_probing_manager_test.cc b/chromium/net/quic/chromium/quic_connectivity_probing_manager_test.cc index 7b7b0c5c5cc..6d77dead83a 100644 --- a/chromium/net/quic/chromium/quic_connectivity_probing_manager_test.cc +++ b/chromium/net/quic/chromium/quic_connectivity_probing_manager_test.cc @@ -4,7 +4,6 @@ #include "net/quic/chromium/quic_connectivity_probing_manager.h" -#include "base/rand_util.h" #include "base/test/test_mock_time_task_runner.h" #include "net/log/test_net_log.h" #include "net/quic/test_tools/mock_clock.h" @@ -84,8 +83,7 @@ class QuicConnectivityProbingManagerTest : public ::testing::Test { socket_factory_.AddSocketDataProvider(socket_data_.get()); // Create a connected socket for probing. socket_ = socket_factory_.CreateDatagramClientSocket( - DatagramSocket::DEFAULT_BIND, base::Bind(&base::RandInt), &net_log_, - NetLogSource()); + DatagramSocket::DEFAULT_BIND, &net_log_, NetLogSource()); EXPECT_THAT(socket_->Connect(kIpEndPoint), IsOk()); IPEndPoint self_address; socket_->GetLocalAddress(&self_address); diff --git a/chromium/net/quic/chromium/quic_end_to_end_unittest.cc b/chromium/net/quic/chromium/quic_end_to_end_unittest.cc index ae892bec698..ce0b3fbe1ee 100644 --- a/chromium/net/quic/chromium/quic_end_to_end_unittest.cc +++ b/chromium/net/quic/chromium/quic_end_to_end_unittest.cc @@ -28,7 +28,7 @@ #include "net/http/http_transaction_test_util.h" #include "net/http/transport_security_state.h" #include "net/log/net_log_with_source.h" -#include "net/proxy_resolution/proxy_service.h" +#include "net/proxy_resolution/proxy_resolution_service.h" #include "net/quic/platform/api/quic_string_piece.h" #include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/quic_test_utils.h" diff --git a/chromium/net/quic/chromium/quic_http_stream.cc b/chromium/net/quic/chromium/quic_http_stream.cc index bd1f159af5b..307604da0e5 100644 --- a/chromium/net/quic/chromium/quic_http_stream.cc +++ b/chromium/net/quic/chromium/quic_http_stream.cc @@ -15,6 +15,7 @@ #include "net/base/net_errors.h" #include "net/http/http_response_headers.h" #include "net/http/http_util.h" +#include "net/log/net_log.h" #include "net/log/net_log_event_type.h" #include "net/log/net_log_source.h" #include "net/quic/chromium/quic_http_utils.h" @@ -467,6 +468,9 @@ void QuicHttpStream::DoCallback(int rv) { int QuicHttpStream::DoLoop(int rv) { CHECK(!in_loop_); base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true); + std::unique_ptr<QuicConnection::ScopedPacketFlusher> packet_flusher = + quic_session()->CreatePacketBundler( + QuicConnection::AckBundling::SEND_ACK_IF_QUEUED); do { State state = next_state_; next_state_ = STATE_NONE; diff --git a/chromium/net/quic/chromium/quic_http_stream_test.cc b/chromium/net/quic/chromium/quic_http_stream_test.cc index b0b026be692..4d68b369db3 100644 --- a/chromium/net/quic/chromium/quic_http_stream_test.cc +++ b/chromium/net/quic/chromium/quic_http_stream_test.cc @@ -34,6 +34,7 @@ #include "net/quic/chromium/quic_chromium_packet_writer.h" #include "net/quic/chromium/quic_http_utils.h" #include "net/quic/chromium/quic_server_info.h" +#include "net/quic/chromium/quic_stream_factory.h" #include "net/quic/chromium/quic_test_packet_maker.h" #include "net/quic/chromium/test_task_runner.h" #include "net/quic/core/congestion_control/send_algorithm_interface.h" @@ -420,6 +421,45 @@ class QuicHttpStreamTest spdy_headers_frame_length, offset); } + std::unique_ptr<QuicReceivedPacket> + ConstructRequestHeadersAndDataFramesPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + RequestPriority request_priority, + QuicStreamId parent_stream_id, + QuicStreamOffset* offset, + size_t* spdy_headers_frame_length, + const std::vector<std::string>& data_writes) { + SpdyPriority priority = + ConvertRequestPriorityToQuicPriority(request_priority); + return client_maker_.MakeRequestHeadersAndMultipleDataFramesPacket( + packet_number, stream_id, should_include_version, fin, priority, + std::move(request_headers_), parent_stream_id, offset, + spdy_headers_frame_length, data_writes); + } + + std::unique_ptr<QuicReceivedPacket> ConstructRequestAndRstPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + RequestPriority request_priority, + QuicStreamId parent_stream_id, + size_t* spdy_headers_frame_length, + QuicStreamOffset* header_stream_offset, + QuicRstStreamErrorCode error_code, + size_t bytes_written) { + SpdyPriority priority = + ConvertRequestPriorityToQuicPriority(request_priority); + return client_maker_.MakeRequestHeadersAndRstPacket( + packet_number, stream_id, should_include_version, fin, priority, + std::move(request_headers_), parent_stream_id, + spdy_headers_frame_length, header_stream_offset, error_code, + bytes_written); + } + std::unique_ptr<QuicReceivedPacket> ConstructRequestHeadersPacket( QuicPacketNumber packet_number, bool fin, @@ -1141,12 +1181,13 @@ TEST_P(QuicHttpStreamTest, SendPostRequest) { size_t spdy_request_headers_frame_length; QuicStreamOffset header_stream_offset = 0; AddWrite(ConstructInitialSettingsPacket(&header_stream_offset)); - AddWrite(InnerConstructRequestHeadersPacket( - 2, GetNthClientInitiatedStreamId(0), kIncludeVersion, !kFin, - DEFAULT_PRIORITY, &spdy_request_headers_frame_length, - &header_stream_offset)); - AddWrite(ConstructClientDataPacket(3, kIncludeVersion, kFin, 0, kUploadData)); - AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); + + AddWrite(ConstructRequestHeadersAndDataFramesPacket( + 2, GetNthClientInitiatedStreamId(0), kIncludeVersion, kFin, + DEFAULT_PRIORITY, 0, &header_stream_offset, + &spdy_request_headers_frame_length, {kUploadData})); + + AddWrite(ConstructClientAckPacket(3, 3, 1, 1)); Initialize(); @@ -1212,12 +1253,11 @@ TEST_P(QuicHttpStreamTest, SendPostRequestAndReceiveSoloFin) { size_t spdy_request_headers_frame_length; QuicStreamOffset header_stream_offset = 0; AddWrite(ConstructInitialSettingsPacket(&header_stream_offset)); - AddWrite(InnerConstructRequestHeadersPacket( - 2, GetNthClientInitiatedStreamId(0), kIncludeVersion, !kFin, - DEFAULT_PRIORITY, &spdy_request_headers_frame_length, - &header_stream_offset)); - AddWrite(ConstructClientDataPacket(3, kIncludeVersion, kFin, 0, kUploadData)); - AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); + AddWrite(ConstructRequestHeadersAndDataFramesPacket( + 2, GetNthClientInitiatedStreamId(0), kIncludeVersion, kFin, + DEFAULT_PRIORITY, 0, &header_stream_offset, + &spdy_request_headers_frame_length, {kUploadData})); + AddWrite(ConstructClientAckPacket(3, 3, 1, 1)); Initialize(); @@ -1286,15 +1326,13 @@ TEST_P(QuicHttpStreamTest, SendChunkedPostRequest) { size_t spdy_request_headers_frame_length; QuicStreamOffset header_stream_offset = 0; AddWrite(ConstructInitialSettingsPacket(&header_stream_offset)); - AddWrite(InnerConstructRequestHeadersPacket( + AddWrite(ConstructRequestHeadersAndDataFramesPacket( 2, GetNthClientInitiatedStreamId(0), kIncludeVersion, !kFin, - DEFAULT_PRIORITY, &spdy_request_headers_frame_length, - &header_stream_offset)); - AddWrite( - ConstructClientDataPacket(3, kIncludeVersion, !kFin, 0, kUploadData)); - AddWrite(ConstructClientDataPacket(4, kIncludeVersion, kFin, chunk_size, + DEFAULT_PRIORITY, 0, &header_stream_offset, + &spdy_request_headers_frame_length, {kUploadData})); + AddWrite(ConstructClientDataPacket(3, kIncludeVersion, kFin, chunk_size, kUploadData)); - AddWrite(ConstructClientAckPacket(5, 3, 1, 1)); + AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); Initialize(); upload_data_stream_ = std::make_unique<ChunkedUploadDataStream>(0); @@ -1361,14 +1399,12 @@ TEST_P(QuicHttpStreamTest, SendChunkedPostRequestWithFinalEmptyDataPacket) { size_t spdy_request_headers_frame_length; QuicStreamOffset header_stream_offset = 0; AddWrite(ConstructInitialSettingsPacket(&header_stream_offset)); - AddWrite(InnerConstructRequestHeadersPacket( + AddWrite(ConstructRequestHeadersAndDataFramesPacket( 2, GetNthClientInitiatedStreamId(0), kIncludeVersion, !kFin, - DEFAULT_PRIORITY, &spdy_request_headers_frame_length, - &header_stream_offset)); - AddWrite( - ConstructClientDataPacket(3, kIncludeVersion, !kFin, 0, kUploadData)); - AddWrite(ConstructClientDataPacket(4, kIncludeVersion, kFin, chunk_size, "")); - AddWrite(ConstructClientAckPacket(5, 3, 1, 1)); + DEFAULT_PRIORITY, 0, &header_stream_offset, + &spdy_request_headers_frame_length, {kUploadData})); + AddWrite(ConstructClientDataPacket(3, kIncludeVersion, kFin, chunk_size, "")); + AddWrite(ConstructClientAckPacket(4, 3, 1, 1)); Initialize(); upload_data_stream_ = std::make_unique<ChunkedUploadDataStream>(0); @@ -1589,12 +1625,10 @@ TEST_P(QuicHttpStreamTest, SessionClosedDuringDoLoop) { size_t spdy_request_headers_frame_length; QuicStreamOffset header_stream_offset = 0; AddWrite(ConstructInitialSettingsPacket(&header_stream_offset)); - AddWrite(InnerConstructRequestHeadersPacket( + AddWrite(ConstructRequestHeadersAndDataFramesPacket( 2, GetNthClientInitiatedStreamId(0), kIncludeVersion, !kFin, - DEFAULT_PRIORITY, &spdy_request_headers_frame_length, - &header_stream_offset)); - AddWrite( - ConstructClientDataPacket(3, kIncludeVersion, !kFin, 0, kUploadData)); + DEFAULT_PRIORITY, 0, &header_stream_offset, + &spdy_request_headers_frame_length, {kUploadData})); // Second data write will result in a synchronous failure which will close // the session. AddWrite(SYNCHRONOUS, ERR_FAILED); @@ -1618,11 +1652,16 @@ TEST_P(QuicHttpStreamTest, SessionClosedDuringDoLoop) { QuicHttpStream* stream = stream_.get(); DeleteStreamCallback delete_stream_callback(std::move(stream_)); // SendRequest() completes asynchronously after the final chunk is added. + // Error does not surface yet since packet write is triggered by a packet + // flusher that tries to bundle request body writes. ASSERT_EQ(ERR_IO_PENDING, stream->SendRequest(headers_, &response_, callback_.callback())); chunked_upload_stream->AppendData(kUploadData, chunk_size, true); int rv = callback_.WaitForResult(); - EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, rv); + EXPECT_EQ(OK, rv); + // Error will be surfaced once an attempt to read the response occurs. + ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR, + stream->ReadResponseHeaders(callback_.callback())); } TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendHeadersComplete) { @@ -1633,6 +1672,8 @@ TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendHeadersComplete) { Initialize(); upload_data_stream_ = std::make_unique<ChunkedUploadDataStream>(0); + auto* chunked_upload_stream = + static_cast<ChunkedUploadDataStream*>(upload_data_stream_.get()); request_.method = "POST"; request_.url = GURL("https://www.example.org/"); @@ -1643,9 +1684,49 @@ TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendHeadersComplete) { ASSERT_EQ(OK, stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); - ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR, + ASSERT_EQ(ERR_IO_PENDING, stream_->SendRequest(headers_, &response_, callback_.callback())); + // Error will be surfaced once |upload_data_stream| triggers the next write. + size_t chunk_size = strlen(kUploadData); + chunked_upload_stream->AppendData(kUploadData, chunk_size, true); + ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR, callback_.WaitForResult()); + + EXPECT_LE(0, stream_->GetTotalSentBytes()); + EXPECT_EQ(0, stream_->GetTotalReceivedBytes()); +} + +TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendHeadersCompleteReadResponse) { + SetRequest("POST", "/", DEFAULT_PRIORITY); + QuicStreamOffset header_stream_offset = 0; + AddWrite(ConstructInitialSettingsPacket(&header_stream_offset)); + AddWrite(SYNCHRONOUS, ERR_FAILED); + Initialize(); + + upload_data_stream_ = std::make_unique<ChunkedUploadDataStream>(0); + auto* chunked_upload_stream = + static_cast<ChunkedUploadDataStream*>(upload_data_stream_.get()); + + request_.method = "POST"; + request_.url = GURL("https://www.example.org/"); + request_.upload_data_stream = upload_data_stream_.get(); + + size_t chunk_size = strlen(kUploadData); + chunked_upload_stream->AppendData(kUploadData, chunk_size, true); + + ASSERT_EQ(OK, request_.upload_data_stream->Init( + TestCompletionCallback().callback(), NetLogWithSource())); + + ASSERT_EQ(OK, + stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, + net_log_.bound(), callback_.callback())); + ASSERT_EQ(OK, + stream_->SendRequest(headers_, &response_, callback_.callback())); + + // Error will be surfaced once an attempt to read the response occurs. + ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR, + stream_->ReadResponseHeaders(callback_.callback())); + EXPECT_LE(0, stream_->GetTotalSentBytes()); EXPECT_EQ(0, stream_->GetTotalReceivedBytes()); } @@ -1665,8 +1746,6 @@ TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendBodyComplete) { upload_data_stream_ = std::make_unique<ChunkedUploadDataStream>(0); auto* chunked_upload_stream = static_cast<ChunkedUploadDataStream*>(upload_data_stream_.get()); - size_t chunk_size = strlen(kUploadData); - chunked_upload_stream->AppendData(kUploadData, chunk_size, false); request_.method = "POST"; request_.url = GURL("https://www.example.org/"); @@ -1677,8 +1756,65 @@ TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendBodyComplete) { ASSERT_EQ(OK, stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); + ASSERT_EQ(ERR_IO_PENDING, + stream_->SendRequest(headers_, &response_, callback_.callback())); + + size_t chunk_size = strlen(kUploadData); + chunked_upload_stream->AppendData(kUploadData, chunk_size, true); + // Error does not surface yet since packet write is triggered by a packet + // flusher that tries to bundle request body writes. + ASSERT_EQ(OK, callback_.WaitForResult()); + // Error will be surfaced once an attempt to read the response occurs. ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR, + stream_->ReadResponseHeaders(callback_.callback())); + + EXPECT_LE(0, stream_->GetTotalSentBytes()); + EXPECT_EQ(0, stream_->GetTotalReceivedBytes()); +} + +TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendBundledBodyComplete) { + SetRequest("POST", "/", DEFAULT_PRIORITY); + size_t spdy_request_headers_frame_length; + QuicStreamOffset header_stream_offset = 0; + AddWrite(ConstructInitialSettingsPacket(&header_stream_offset)); + AddWrite(ConstructRequestHeadersAndDataFramesPacket( + 2, GetNthClientInitiatedStreamId(0), kIncludeVersion, !kFin, + DEFAULT_PRIORITY, 0, &header_stream_offset, + &spdy_request_headers_frame_length, {kUploadData})); + AddWrite(SYNCHRONOUS, ERR_FAILED); + Initialize(); + + upload_data_stream_ = std::make_unique<ChunkedUploadDataStream>(0); + auto* chunked_upload_stream = + static_cast<ChunkedUploadDataStream*>(upload_data_stream_.get()); + + request_.method = "POST"; + request_.url = GURL("https://www.example.org/"); + request_.upload_data_stream = upload_data_stream_.get(); + + size_t chunk_size = strlen(kUploadData); + chunked_upload_stream->AppendData(kUploadData, chunk_size, false); + + ASSERT_EQ(OK, request_.upload_data_stream->Init( + TestCompletionCallback().callback(), NetLogWithSource())); + + ASSERT_EQ(OK, + stream_->InitializeStream(&request_, false, DEFAULT_PRIORITY, + net_log_.bound(), callback_.callback())); + ASSERT_EQ(ERR_IO_PENDING, stream_->SendRequest(headers_, &response_, callback_.callback())); + + chunked_upload_stream->AppendData(kUploadData, chunk_size, true); + + // Error does not surface yet since packet write is triggered by a packet + // flusher that tries to bundle request body writes. + ASSERT_EQ(OK, callback_.WaitForResult()); + // Error will be surfaced once an attempt to read the response occurs. + ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR, + stream_->ReadResponseHeaders(callback_.callback())); + + EXPECT_LE(0, stream_->GetTotalSentBytes()); + EXPECT_EQ(0, stream_->GetTotalReceivedBytes()); } TEST_P(QuicHttpStreamTest, ServerPushGetRequest) { @@ -2164,11 +2300,10 @@ TEST_P(QuicHttpStreamTest, DataReadErrorSynchronous) { size_t spdy_request_headers_frame_length; QuicStreamOffset header_stream_offset = 0; AddWrite(ConstructInitialSettingsPacket(&header_stream_offset)); - AddWrite(InnerConstructRequestHeadersPacket( + AddWrite(ConstructRequestAndRstPacket( 2, GetNthClientInitiatedStreamId(0), kIncludeVersion, !kFin, - DEFAULT_PRIORITY, &spdy_request_headers_frame_length, - &header_stream_offset)); - AddWrite(ConstructClientRstStreamErrorPacket(3, kIncludeVersion)); + DEFAULT_PRIORITY, 0, &spdy_request_headers_frame_length, + &header_stream_offset, QUIC_ERROR_PROCESSING_STREAM, 0)); Initialize(); diff --git a/chromium/net/quic/chromium/quic_http_utils.cc b/chromium/net/quic/chromium/quic_http_utils.cc index 664ab42bd65..a0b52a27552 100644 --- a/chromium/net/quic/chromium/quic_http_utils.cc +++ b/chromium/net/quic/chromium/quic_http_utils.cc @@ -8,6 +8,7 @@ #include "base/metrics/histogram_macros.h" #include "net/quic/platform/api/quic_endian.h" +#include "net/spdy/chromium/spdy_log_util.h" namespace net { diff --git a/chromium/net/quic/chromium/quic_http_utils.h b/chromium/net/quic/chromium/quic_http_utils.h index f2839b82724..1c2d4848bea 100644 --- a/chromium/net/quic/chromium/quic_http_utils.h +++ b/chromium/net/quic/chromium/quic_http_utils.h @@ -8,6 +8,7 @@ #include "base/values.h" #include "net/base/net_export.h" #include "net/base/request_priority.h" +#include "net/log/net_log_capture_mode.h" #include "net/quic/core/quic_packets.h" #include "net/spdy/core/spdy_header_block.h" #include "net/spdy/core/spdy_protocol.h" diff --git a/chromium/net/quic/chromium/quic_network_transaction_unittest.cc b/chromium/net/quic/chromium/quic_network_transaction_unittest.cc index ca11773b3b0..e270c0d8e8d 100644 --- a/chromium/net/quic/chromium/quic_network_transaction_unittest.cc +++ b/chromium/net/quic/chromium/quic_network_transaction_unittest.cc @@ -37,8 +37,8 @@ #include "net/log/test_net_log_entry.h" #include "net/log/test_net_log_util.h" #include "net/proxy_resolution/proxy_config_service_fixed.h" +#include "net/proxy_resolution/proxy_resolution_service.h" #include "net/proxy_resolution/proxy_resolver.h" -#include "net/proxy_resolution/proxy_service.h" #include "net/quic/chromium/crypto/proof_verifier_chromium.h" #include "net/quic/chromium/mock_crypto_client_stream_factory.h" #include "net/quic/chromium/mock_quic_data.h" @@ -53,7 +53,7 @@ #include "net/quic/core/quic_framer.h" #include "net/quic/platform/api/quic_str_cat.h" #include "net/quic/platform/api/quic_string_piece.h" -#include "net/quic/platform/impl/quic_test_impl.h" +#include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/crypto_test_utils.h" #include "net/quic/test_tools/mock_clock.h" #include "net/quic/test_tools/mock_random.h" @@ -423,20 +423,19 @@ class QuicNetworkTransactionTest : public PlatformTest, ConvertRequestPriorityToQuicPriority(request_priority), offset); } - std::unique_ptr<QuicEncryptedPacket> ConstructClientAckAndPriorityPacket( + std::unique_ptr<QuicEncryptedPacket> + ConstructClientAckAndPriorityFramesPacket( QuicPacketNumber packet_number, bool should_include_version, QuicPacketNumber largest_received, QuicPacketNumber smallest_received, QuicPacketNumber least_unacked, - QuicStreamId stream_id, - QuicStreamId parent_stream_id, - RequestPriority request_priority, + const std::vector<QuicTestPacketMaker::Http2StreamDependency>& + priority_frames, QuicStreamOffset* offset) { - return client_maker_.MakeAckAndPriorityPacket( + return client_maker_.MakeAckAndMultiplePriorityFramesPacket( packet_number, should_include_version, largest_received, - smallest_received, least_unacked, stream_id, parent_stream_id, - ConvertRequestPriorityToQuicPriority(request_priority), offset); + smallest_received, least_unacked, priority_frames, offset); } // Uses default QuicTestPacketMaker. @@ -568,6 +567,26 @@ class QuicNetworkTransactionTest : public PlatformTest, std::move(headers), parent_stream_id, offset); } + std::unique_ptr<QuicReceivedPacket> + ConstructClientRequestHeadersAndDataFramesPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + RequestPriority request_priority, + SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, + QuicStreamOffset* offset, + size_t* spdy_headers_frame_length, + const std::vector<std::string>& data_writes) { + SpdyPriority priority = + ConvertRequestPriorityToQuicPriority(request_priority); + return client_maker_.MakeRequestHeadersAndMultipleDataFramesPacket( + packet_number, stream_id, should_include_version, fin, priority, + std::move(headers), parent_stream_id, offset, spdy_headers_frame_length, + data_writes); + } + std::unique_ptr<QuicEncryptedPacket> ConstructClientMultipleDataFramesPacket( QuicPacketNumber packet_number, QuicStreamId stream_id, @@ -837,7 +856,7 @@ class QuicNetworkTransactionTest : public PlatformTest, session_context_.proxy_delegate = &test_proxy_delegate; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "HTTPS myproxy.org:443"); + "HTTPS myproxy.org:443", TRAFFIC_ANNOTATION_FOR_TESTS); CreateSession(); EXPECT_TRUE(test_proxy_delegate.alternative_proxy_server().is_valid()); @@ -928,6 +947,7 @@ INSTANTIATE_TEST_CASE_P( ::testing::Bool())); TEST_P(QuicNetworkTransactionTest, WriteErrorHandshakeConfirmed) { + session_params_.retry_without_alt_svc_on_quic_errors = false; base::HistogramTester histograms; session_params_.origins_to_force_quic_on.insert( HostPortPair::FromString("mail.example.org:443")); @@ -959,6 +979,7 @@ TEST_P(QuicNetworkTransactionTest, WriteErrorHandshakeConfirmed) { } TEST_P(QuicNetworkTransactionTest, WriteErrorHandshakeConfirmedAsync) { + session_params_.retry_without_alt_svc_on_quic_errors = false; base::HistogramTester histograms; session_params_.origins_to_force_quic_on.insert( HostPortPair::FromString("mail.example.org:443")); @@ -1166,6 +1187,7 @@ TEST_P(QuicNetworkTransactionTest, LargeResponseHeaders) { } TEST_P(QuicNetworkTransactionTest, TooLargeResponseHeaders) { + session_params_.retry_without_alt_svc_on_quic_errors = false; session_params_.origins_to_force_quic_on.insert( HostPortPair::FromString("mail.example.org:443")); @@ -1253,7 +1275,7 @@ TEST_P(QuicNetworkTransactionTest, ForceQuicForAll) { TEST_P(QuicNetworkTransactionTest, QuicProxy) { session_params_.enable_quic = true; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "QUIC mail.example.org:70"); + "QUIC mail.example.org:70", TRAFFIC_ANNOTATION_FOR_TESTS); MockQuicData mock_quic_data; QuicStreamOffset header_stream_offset = 0; @@ -1295,7 +1317,7 @@ TEST_P(QuicNetworkTransactionTest, QuicProxyWithCert) { session_params_.enable_quic = true; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "QUIC " + proxy_host + ":70"); + "QUIC " + proxy_host + ":70", TRAFFIC_ANNOTATION_FOR_TESTS); client_maker_.set_hostname(origin_host); MockQuicData mock_quic_data; @@ -2050,6 +2072,7 @@ TEST_P(QuicNetworkTransactionTest, GoAwayWithConnectionMigrationOnPortsOnly) { // Verify that if a QUIC connection times out, the QuicHttpStream will // return QUIC_PROTOCOL_ERROR. TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmed) { + session_params_.retry_without_alt_svc_on_quic_errors = false; session_params_.quic_idle_connection_timeout_seconds = 5; // The request will initially go out over QUIC. @@ -2143,6 +2166,7 @@ TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmed) { // Verify that if a QUIC connection RTOs, the QuicHttpStream will // return QUIC_PROTOCOL_ERROR. TEST_P(QuicNetworkTransactionTest, TooManyRtosAfterHandshakeConfirmed) { + session_params_.retry_without_alt_svc_on_quic_errors = false; session_params_.quic_connection_options.push_back(k5RTO); // The request will initially go out over QUIC. @@ -2345,6 +2369,7 @@ TEST_P(QuicNetworkTransactionTest, // Verify that if a QUIC protocol error occurs after the handshake is confirmed // the request fails with QUIC_PROTOCOL_ERROR. TEST_P(QuicNetworkTransactionTest, ProtocolErrorAfterHandshakeConfirmed) { + session_params_.retry_without_alt_svc_on_quic_errors = false; // The request will initially go out over QUIC. MockQuicData quic_data; QuicStreamOffset header_stream_offset = 0; @@ -2527,7 +2552,6 @@ TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmedThenBroken) { // connection times out, then QUIC will be marked as broken and the request // retried over TCP. TEST_P(QuicNetworkTransactionTest, TimeoutAfterHandshakeConfirmedThenBroken2) { - session_params_.retry_without_alt_svc_on_quic_errors = true; session_params_.quic_idle_connection_timeout_seconds = 5; // The request will initially go out over QUIC. @@ -2997,7 +3021,6 @@ TEST_P(QuicNetworkTransactionTest, // retried over TCP and the QUIC will be marked as broken. TEST_P(QuicNetworkTransactionTest, ProtocolErrorAfterHandshakeConfirmedThenBroken) { - session_params_.retry_without_alt_svc_on_quic_errors = true; session_params_.quic_idle_connection_timeout_seconds = 5; // The request will initially go out over QUIC. @@ -3085,8 +3108,6 @@ TEST_P(QuicNetworkTransactionTest, // request is reset from, then QUIC will be marked as broken and the request // retried over TCP. TEST_P(QuicNetworkTransactionTest, ResetAfterHandshakeConfirmedThenBroken) { - session_params_.retry_without_alt_svc_on_quic_errors = true; - // The request will initially go out over QUIC. MockQuicData quic_data; QuicStreamOffset header_stream_offset = 0; @@ -3247,7 +3268,6 @@ TEST_P(QuicNetworkTransactionTest, RemoteAltSvcWorkingWhileLocalAltSvcBroken) { TEST_P(QuicNetworkTransactionTest, ResetPooledAfterHandshakeConfirmedThenBroken) { session_params_.quic_allow_remote_alt_svc = true; - session_params_.retry_without_alt_svc_on_quic_errors = true; GURL origin1 = request_.url; GURL origin2("https://www.example.org/"); @@ -3374,10 +3394,10 @@ TEST_P(QuicNetworkTransactionTest, SendRequestAndExpectHttpResponse("hello world"); } -// When multiple alternative services are advertised, -// HttpStreamFactoryImpl::RequestStreamInternal() should select the alternative -// service which uses existing QUIC session if available. If no existing QUIC -// session can be used, use the first alternative service from the list. +// When multiple alternative services are advertised, HttpStreamFactoryImpl +// should select the alternative service which uses existing QUIC session if +// available. If no existing QUIC session can be used, use the first alternative +// service from the list. TEST_P(QuicNetworkTransactionTest, UseExistingAlternativeServiceForQuic) { session_params_.quic_allow_remote_alt_svc = true; MockRead http_reads[] = { @@ -3492,7 +3512,7 @@ TEST_P(QuicNetworkTransactionTest, UseExistingQUICAlternativeProxy) { TestProxyDelegate test_proxy_delegate; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "HTTPS mail.example.org:443"); + "HTTPS mail.example.org:443", TRAFFIC_ANNOTATION_FOR_TESTS); test_proxy_delegate.set_alternative_proxy_server( ProxyServer::FromPacString("QUIC mail.example.org:443")); @@ -3889,7 +3909,7 @@ TEST_P(QuicNetworkTransactionTest, UseAlternativeServiceForQuicForHttps) { TEST_P(QuicNetworkTransactionTest, QuicProxyWithRacing) { base::HistogramTester histogram_tester; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "HTTPS mail.example.org:443"); + "HTTPS mail.example.org:443", TRAFFIC_ANNOTATION_FOR_TESTS); MockQuicData mock_quic_data; QuicStreamOffset header_stream_offset = 0; @@ -4054,8 +4074,8 @@ TEST_P(QuicNetworkTransactionTest, ZeroRTTWithNoHttpRace) { } TEST_P(QuicNetworkTransactionTest, ZeroRTTWithProxy) { - proxy_resolution_service_ = - ProxyResolutionService::CreateFixedFromPacResult("PROXY myproxy:70"); + proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( + "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS); // Since we are using a proxy, the QUIC job will not succeed. MockWrite http_writes[] = { @@ -4144,6 +4164,7 @@ TEST_P(QuicNetworkTransactionTest, ZeroRTTWithConfirmationRequired) { TEST_P(QuicNetworkTransactionTest, LogGranularQuicErrorCodeOnQuicProtocolErrorLocal) { + session_params_.retry_without_alt_svc_on_quic_errors = false; MockQuicData mock_quic_data; QuicStreamOffset header_stream_offset = 0; mock_quic_data.AddWrite( @@ -4197,6 +4218,7 @@ TEST_P(QuicNetworkTransactionTest, TEST_P(QuicNetworkTransactionTest, LogGranularQuicErrorCodeOnQuicProtocolErrorRemote) { + session_params_.retry_without_alt_svc_on_quic_errors = false; MockQuicData mock_quic_data; QuicStreamOffset header_stream_offset = 0; mock_quic_data.AddWrite( @@ -4315,6 +4337,7 @@ TEST_P(QuicNetworkTransactionTest, RstSteamErrorHandling) { } TEST_P(QuicNetworkTransactionTest, RstSteamBeforeHeaders) { + session_params_.retry_without_alt_svc_on_quic_errors = false; MockQuicData mock_quic_data; QuicStreamOffset header_stream_offset = 0; mock_quic_data.AddWrite( @@ -4781,8 +4804,8 @@ TEST_P(QuicNetworkTransactionTest, ConnectionCloseDuringConnectProxy) { EXPECT_TRUE(test_proxy_delegate.alternative_proxy_server().is_quic()); session_context_.proxy_delegate = &test_proxy_delegate; - proxy_resolution_service_ = - ProxyResolutionService::CreateFixedFromPacResult("HTTPS myproxy.org:443"); + proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( + "HTTPS myproxy.org:443", TRAFFIC_ANNOTATION_FOR_TESTS); request_.url = GURL("http://mail.example.org/"); // In order for a new QUIC session to be established via alternate-protocol @@ -4837,7 +4860,7 @@ TEST_P(QuicNetworkTransactionTest, DISABLED_QuicUploadToAlternativeProxyServer) { base::HistogramTester histogram_tester; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "HTTPS mail.example.org:443"); + "HTTPS mail.example.org:443", TRAFFIC_ANNOTATION_FOR_TESTS); TestProxyDelegate test_proxy_delegate; @@ -4910,6 +4933,7 @@ TEST_P(QuicNetworkTransactionTest, QuicUpload) { } TEST_P(QuicNetworkTransactionTest, QuicUploadWriteError) { + session_params_.retry_without_alt_svc_on_quic_errors = false; ScopedMockNetworkChangeNotifier network_change_notifier; MockNetworkChangeNotifier* mock_ncn = network_change_notifier.mock_network_change_notifier(); @@ -5015,6 +5039,7 @@ TEST_P(QuicNetworkTransactionTest, RetryAfterSynchronousNoBufferSpace) { } TEST_P(QuicNetworkTransactionTest, MaxRetriesAfterAsyncNoBufferSpace) { + session_params_.retry_without_alt_svc_on_quic_errors = false; session_params_.origins_to_force_quic_on.insert( HostPortPair::FromString("mail.example.org:443")); @@ -5052,6 +5077,7 @@ TEST_P(QuicNetworkTransactionTest, MaxRetriesAfterAsyncNoBufferSpace) { } TEST_P(QuicNetworkTransactionTest, MaxRetriesAfterSynchronousNoBufferSpace) { + session_params_.retry_without_alt_svc_on_quic_errors = false; session_params_.origins_to_force_quic_on.insert( HostPortPair::FromString("mail.example.org:443")); @@ -5089,6 +5115,7 @@ TEST_P(QuicNetworkTransactionTest, MaxRetriesAfterSynchronousNoBufferSpace) { } TEST_P(QuicNetworkTransactionTest, NoMigrationForMsgTooBig) { + session_params_.retry_without_alt_svc_on_quic_errors = false; session_params_.origins_to_force_quic_on.insert( HostPortPair::FromString("mail.example.org:443")); const QuicString error_details = @@ -5192,6 +5219,7 @@ TEST_P(QuicNetworkTransactionTest, QuicServerPush) { // is closed before the pushed headers arrive, but after the connection // is closed and before the callbacks are executed. TEST_P(QuicNetworkTransactionTest, CancelServerPushAfterConnectionClose) { + session_params_.retry_without_alt_svc_on_quic_errors = false; session_params_.origins_to_force_quic_on.insert( HostPortPair::FromString("mail.example.org:443")); @@ -5278,14 +5306,10 @@ TEST_P(QuicNetworkTransactionTest, QuicForceHolBlocking) { QuicStreamOffset offset = 0; mock_quic_data.AddWrite(ConstructInitialSettingsPacket(1, &offset)); - mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( - 2, GetNthClientInitiatedStreamId(0), true, false, - GetRequestHeaders("POST", "https", "/"), &offset)); - std::unique_ptr<QuicEncryptedPacket> packet; - packet = ConstructClientDataPacket(3, GetNthClientInitiatedStreamId(0), true, - true, 0, "1"); - mock_quic_data.AddWrite(std::move(packet)); + mock_quic_data.AddWrite(ConstructClientRequestHeadersAndDataFramesPacket( + 2, GetNthClientInitiatedStreamId(0), true, true, DEFAULT_PRIORITY, + GetRequestHeaders("POST", "https", "/"), 0, &offset, nullptr, {"1"})); mock_quic_data.AddRead(ConstructServerResponseHeadersPacket( 1, GetNthClientInitiatedStreamId(0), false, false, @@ -5294,7 +5318,7 @@ TEST_P(QuicNetworkTransactionTest, QuicForceHolBlocking) { mock_quic_data.AddRead(ConstructServerDataPacket( 2, GetNthClientInitiatedStreamId(0), false, true, 0, "hello!")); - mock_quic_data.AddWrite(ConstructClientAckPacket(4, 2, 1, 1)); + mock_quic_data.AddWrite(ConstructClientAckPacket(3, 2, 1, 1)); mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read mock_quic_data.AddRead(ASYNC, 0); // EOF @@ -6068,13 +6092,11 @@ TEST_P(QuicNetworkTransactionTest, QuicServerPushMatchesRequestWithBody) { client_packet_number++, GetNthServerInitiatedStreamId(0), QUIC_STREAM_CANCELLED, 5, 5, 1)); const char kBody[] = "1"; - mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket( - client_packet_number++, GetNthClientInitiatedStreamId(1), false, false, - GetRequestHeaders("GET", "https", "/pushed.jpg"), - GetNthServerInitiatedStreamId(0), &header_stream_offset)); - mock_quic_data.AddWrite(ConstructClientMultipleDataFramesPacket( + mock_quic_data.AddWrite(ConstructClientRequestHeadersAndDataFramesPacket( client_packet_number++, GetNthClientInitiatedStreamId(1), false, true, - {kBody}, 0)); + DEFAULT_PRIORITY, GetRequestHeaders("GET", "https", "/pushed.jpg"), + GetNthServerInitiatedStreamId(0), &header_stream_offset, nullptr, + {kBody})); // We see the same response as for the earlier pushed and cancelled // stream. @@ -6168,7 +6190,7 @@ TEST_P(QuicNetworkTransactionTest, QuicServerPushWithEmptyHostname) { TEST_P(QuicNetworkTransactionTest, QuicProxyConnectHttpsServer) { session_params_.enable_quic = true; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "QUIC proxy.example.org:70"); + "QUIC proxy.example.org:70", TRAFFIC_ANNOTATION_FOR_TESTS); MockQuicData mock_quic_data; QuicStreamOffset header_stream_offset = 0; @@ -6237,7 +6259,7 @@ TEST_P(QuicNetworkTransactionTest, QuicProxyConnectHttpsServer) { TEST_P(QuicNetworkTransactionTest, QuicProxyConnectSpdyServer) { session_params_.enable_quic = true; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "QUIC proxy.example.org:70"); + "QUIC proxy.example.org:70", TRAFFIC_ANNOTATION_FOR_TESTS); MockQuicData mock_quic_data; QuicStreamOffset header_stream_offset = 0; @@ -6310,7 +6332,7 @@ TEST_P(QuicNetworkTransactionTest, QuicProxyConnectSpdyServer) { TEST_P(QuicNetworkTransactionTest, QuicProxyConnectReuseTransportSocket) { session_params_.enable_quic = true; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "QUIC proxy.example.org:70"); + "QUIC proxy.example.org:70", TRAFFIC_ANNOTATION_FOR_TESTS); MockQuicData mock_quic_data; QuicStreamOffset header_stream_offset = 0; @@ -6425,7 +6447,7 @@ TEST_P(QuicNetworkTransactionTest, QuicProxyConnectReuseTransportSocket) { TEST_P(QuicNetworkTransactionTest, QuicProxyConnectReuseQuicSession) { session_params_.enable_quic = true; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "QUIC proxy.example.org:70"); + "QUIC proxy.example.org:70", TRAFFIC_ANNOTATION_FOR_TESTS); MockQuicData mock_quic_data; QuicStreamOffset client_header_stream_offset = 0; @@ -6549,7 +6571,7 @@ TEST_P(QuicNetworkTransactionTest, QuicProxyConnectReuseQuicSession) { TEST_P(QuicNetworkTransactionTest, QuicProxyConnectFailure) { session_params_.enable_quic = true; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "QUIC proxy.example.org:70"); + "QUIC proxy.example.org:70", TRAFFIC_ANNOTATION_FOR_TESTS); MockQuicData mock_quic_data; QuicStreamOffset header_stream_offset = 0; @@ -6591,7 +6613,7 @@ TEST_P(QuicNetworkTransactionTest, QuicProxyConnectFailure) { TEST_P(QuicNetworkTransactionTest, QuicProxyQuicConnectionError) { session_params_.enable_quic = true; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "QUIC proxy.example.org:70"); + "QUIC proxy.example.org:70", TRAFFIC_ANNOTATION_FOR_TESTS); MockQuicData mock_quic_data; QuicStreamOffset header_stream_offset = 0; @@ -6626,7 +6648,7 @@ TEST_P(QuicNetworkTransactionTest, QuicProxyQuicConnectionError) { TEST_P(QuicNetworkTransactionTest, QuicProxyConnectBadCertificate) { session_params_.enable_quic = true; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "QUIC proxy.example.org:70"); + "QUIC proxy.example.org:70", TRAFFIC_ANNOTATION_FOR_TESTS); MockQuicData mock_quic_data; QuicStreamOffset client_header_stream_offset = 0; @@ -6720,7 +6742,7 @@ TEST_P(QuicNetworkTransactionTest, QuicProxyConnectBadCertificate) { TEST_P(QuicNetworkTransactionTest, QuicProxyUserAgent) { session_params_.enable_quic = true; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "QUIC proxy.example.org:70"); + "QUIC proxy.example.org:70", TRAFFIC_ANNOTATION_FOR_TESTS); MockQuicData mock_quic_data; QuicStreamOffset header_stream_offset = 0; @@ -6762,7 +6784,7 @@ TEST_P(QuicNetworkTransactionTest, QuicProxyUserAgent) { TEST_P(QuicNetworkTransactionTest, QuicProxyRequestPriority) { session_params_.enable_quic = true; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "QUIC proxy.example.org:70"); + "QUIC proxy.example.org:70", TRAFFIC_ANNOTATION_FOR_TESTS); const RequestPriority request_priority = MEDIUM; @@ -6817,7 +6839,7 @@ TEST_P(QuicNetworkTransactionTest, QuicProxyAuth) { session_params_.enable_quic = true; proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult( - "QUIC proxy.example.org:70"); + "QUIC proxy.example.org:70", TRAFFIC_ANNOTATION_FOR_TESTS); MockQuicData mock_quic_data; QuicStreamOffset client_header_stream_offset = 0; @@ -7004,8 +7026,10 @@ TEST_P(QuicNetworkTransactionTest, QuicServerPushUpdatesPriority) { 4, client_stream_0, push_stream_0, false, GetRequestHeaders("GET", "https", "/pushed_0.jpg"), &server_header_offset, &server_maker_)); - mock_quic_data.AddWrite(ConstructClientAckAndPriorityPacket( - 6, false, 4, 3, 1, push_stream_0, client_stream_2, DEFAULT_PRIORITY, + mock_quic_data.AddWrite(ConstructClientAckAndPriorityFramesPacket( + 6, false, 4, 3, 1, + {{push_stream_0, client_stream_2, + ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY)}}, &header_stream_offset)); mock_quic_data.AddRead(ConstructServerPushPromisePacket( 5, client_stream_0, push_stream_1, false, @@ -7027,29 +7051,30 @@ TEST_P(QuicNetworkTransactionTest, QuicServerPushUpdatesPriority) { // Request for "pushed_0.jpg" matches |push_stream_0|. |push_stream_0|'s // priority updates to match the request's priority. Client sends PRIORITY // frames to inform server of new HTTP/2 stream dependencies. - mock_quic_data.AddWrite(ConstructClientAckAndPriorityPacket( - 9, false, 7, 7, 1, push_stream_1, client_stream_2, DEFAULT_PRIORITY, + mock_quic_data.AddWrite(ConstructClientAckAndPriorityFramesPacket( + 9, false, 7, 7, 1, + {{push_stream_1, client_stream_2, + ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY)}, + {push_stream_0, client_stream_0, + ConvertRequestPriorityToQuicPriority(HIGHEST)}}, &header_stream_offset)); - mock_quic_data.AddWrite( - ConstructClientPriorityPacket(10, false, push_stream_0, client_stream_0, - HIGHEST, &header_stream_offset)); // Server sends data for the three requests and the two push promises. mock_quic_data.AddRead(ConstructServerDataPacket(8, client_stream_0, false, true, 0, "hello 0!")); mock_quic_data.AddSynchronousRead(ConstructServerDataPacket( 9, client_stream_1, false, true, 0, "hello 1!")); - mock_quic_data.AddWrite(ConstructClientAckPacket(11, 9, 8, 1)); + mock_quic_data.AddWrite(ConstructClientAckPacket(10, 9, 8, 1)); mock_quic_data.AddRead(ConstructServerDataPacket(10, client_stream_2, false, true, 0, "hello 2!")); mock_quic_data.AddSynchronousRead(ConstructServerDataPacket( 11, push_stream_0, false, true, 0, "and hello 0!")); - mock_quic_data.AddWrite(ConstructClientAckPacket(12, 11, 10, 1)); + mock_quic_data.AddWrite(ConstructClientAckPacket(11, 11, 10, 1)); mock_quic_data.AddRead(ConstructServerDataPacket(12, push_stream_1, false, true, 0, "and hello 1!")); mock_quic_data.AddWrite(ConstructClientAckAndRstPacket( - 13, push_stream_0, QUIC_RST_ACKNOWLEDGEMENT, 12, 12, 1)); + 12, push_stream_0, QUIC_RST_ACKNOWLEDGEMENT, 12, 12, 1)); mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read mock_quic_data.AddRead(ASYNC, 0); // EOF diff --git a/chromium/net/quic/chromium/quic_proxy_client_socket_unittest.cc b/chromium/net/quic/chromium/quic_proxy_client_socket_unittest.cc index b87795d17b7..cd205c97287 100644 --- a/chromium/net/quic/chromium/quic_proxy_client_socket_unittest.cc +++ b/chromium/net/quic/chromium/quic_proxy_client_socket_unittest.cc @@ -25,6 +25,7 @@ #include "net/quic/chromium/quic_chromium_packet_writer.h" #include "net/quic/chromium/quic_http_utils.h" #include "net/quic/chromium/quic_server_info.h" +#include "net/quic/chromium/quic_stream_factory.h" #include "net/quic/chromium/quic_test_packet_maker.h" #include "net/quic/chromium/test_task_runner.h" #include "net/quic/core/crypto/null_encrypter.h" @@ -1362,13 +1363,8 @@ TEST_P(QuicProxyClientSocketTest, RstWithReadAndWritePending) { mock_quic_data_.AddRead(SYNCHRONOUS, ERR_IO_PENDING); mock_quic_data_.AddAsyncWrite( ConstructAckAndDataPacket(3, 1, 1, 1, 0, kMsg2, kLen2)); - if (FLAGS_quic_reloadable_flag_quic_use_control_frame_manager) { mock_quic_data_.AddWrite( ConstructAckAndRstPacket(4, QUIC_RST_ACKNOWLEDGEMENT, 2, 2, 1, kLen2)); - } else { - mock_quic_data_.AddWrite( - ConstructRstPacket(4, QUIC_RST_ACKNOWLEDGEMENT, kLen2)); - } Initialize(); @@ -1485,13 +1481,8 @@ TEST_P(QuicProxyClientSocketTest, RstWithReadAndWritePendingDelete) { mock_quic_data_.AddRead(SYNCHRONOUS, ERR_IO_PENDING); mock_quic_data_.AddAsyncWrite( ConstructAckAndDataPacket(3, 1, 1, 1, 0, kMsg1, kLen1)); - if (FLAGS_quic_reloadable_flag_quic_use_control_frame_manager) { mock_quic_data_.AddWrite( ConstructAckAndRstPacket(4, QUIC_RST_ACKNOWLEDGEMENT, 2, 2, 1, kLen1)); - } else { - mock_quic_data_.AddWrite( - ConstructRstPacket(4, QUIC_RST_ACKNOWLEDGEMENT, kLen1)); - } Initialize(); diff --git a/chromium/net/quic/chromium/quic_stream_factory.cc b/chromium/net/quic/chromium/quic_stream_factory.cc index 6e816ad9edf..9448749cd60 100644 --- a/chromium/net/quic/chromium/quic_stream_factory.cc +++ b/chromium/net/quic/chromium/quic_stream_factory.cc @@ -14,7 +14,6 @@ #include "base/metrics/field_trial.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/rand_util.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -32,6 +31,7 @@ #include "net/cert/cert_verifier.h" #include "net/cert/ct_verifier.h" #include "net/dns/host_resolver.h" +#include "net/log/net_log.h" #include "net/log/net_log_capture_mode.h" #include "net/log/net_log_event_type.h" #include "net/log/net_log_source_type.h" @@ -1346,7 +1346,7 @@ std::unique_ptr<DatagramClientSocket> QuicStreamFactory::CreateSocket( NetLog* net_log, const NetLogSource& source) { auto socket = client_socket_factory_->CreateDatagramClientSocket( - DatagramSocket::DEFAULT_BIND, RandIntCallback(), net_log, source); + DatagramSocket::DEFAULT_BIND, net_log, source); if (enable_socket_recv_optimization_) socket->EnableRecvOptimization(); return socket; diff --git a/chromium/net/quic/chromium/quic_stream_factory.h b/chromium/net/quic/chromium/quic_stream_factory.h index 92dab824bfc..041bd2e52e9 100644 --- a/chromium/net/quic/chromium/quic_stream_factory.h +++ b/chromium/net/quic/chromium/quic_stream_factory.h @@ -77,19 +77,13 @@ class QuicStreamFactoryPeer; // When a connection is idle for 30 seconds it will be closed. const int kIdleConnectionTimeoutSeconds = 30; -enum QuicConnectionMigrationStatus { - MIGRATION_STATUS_NO_MIGRATABLE_STREAMS, - MIGRATION_STATUS_ALREADY_MIGRATED, - MIGRATION_STATUS_INTERNAL_ERROR, - MIGRATION_STATUS_TOO_MANY_CHANGES, - MIGRATION_STATUS_SUCCESS, - MIGRATION_STATUS_NON_MIGRATABLE_STREAM, - MIGRATION_STATUS_NOT_ENABLED, - MIGRATION_STATUS_NO_ALTERNATE_NETWORK, - MIGRATION_STATUS_ON_PATH_DEGRADING_DISABLED, - MIGRATION_STATUS_DISABLED_BY_CONFIG, - MIGRATION_STATUS_MAX -}; +// The default maximum time QUIC session could be on non-default network before +// migrate back to default network. +const int64_t kMaxTimeOnNonDefaultNetworkSecs = 128; + +// The default maximum number of migrations to non default network on path +// degrading per network. Used in chromium only. +const int64_t kMaxMigrationsToNonDefaultNetworkOnPathDegrading = 5; enum QuicPlatformNotification { NETWORK_CONNECTED, diff --git a/chromium/net/quic/chromium/quic_stream_factory_test.cc b/chromium/net/quic/chromium/quic_stream_factory_test.cc index 0122d1f6696..03c813265b5 100644 --- a/chromium/net/quic/chromium/quic_stream_factory_test.cc +++ b/chromium/net/quic/chromium/quic_stream_factory_test.cc @@ -40,7 +40,7 @@ #include "net/quic/core/crypto/quic_decrypter.h" #include "net/quic/core/crypto/quic_encrypter.h" #include "net/quic/core/quic_client_promised_info.h" -#include "net/quic/platform/impl/quic_test_impl.h" +#include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/mock_clock.h" #include "net/quic/test_tools/mock_random.h" #include "net/quic/test_tools/quic_config_peer.h" @@ -49,6 +49,7 @@ #include "net/socket/next_proto.h" #include "net/socket/socket_test_util.h" #include "net/spdy/chromium/spdy_session_test_util.h" +#include "net/spdy/chromium/spdy_test_util_common.h" #include "net/spdy/core/spdy_test_utils.h" #include "net/ssl/channel_id_service.h" #include "net/ssl/default_channel_id_store.h" @@ -189,7 +190,6 @@ class TestConnectionMigrationSocketFactory : public MockClientSocketFactory { std::unique_ptr<DatagramClientSocket> CreateDatagramClientSocket( DatagramSocket::BindType bind_type, - const RandIntCallback& rand_int_cb, NetLog* net_log, const NetLogSource& source) override { SocketDataProvider* data_provider = mock_data().GetNext(); @@ -2067,11 +2067,7 @@ void QuicStreamFactoryTestBase::OnNetworkMadeDefault(bool async_write_before) { // Do an async write to leave writer blocked. if (async_write_before) { - if (session->use_control_frame_manager()) { - session->SendPing(); - } else { - session->connection()->SendPing(); - } + session->SendPing(); } // Set up second socket data provider that is used after migration. @@ -2206,11 +2202,7 @@ void QuicStreamFactoryTestBase::OnNetworkDisconnected(bool async_write_before) { // Do an async write to leave writer blocked. if (async_write_before) { - if (session->use_control_frame_manager()) { - session->SendPing(); - } else { - session->connection()->SendPing(); - } + session->SendPing(); } // Set up second socket data provider that is used after migration. diff --git a/chromium/net/quic/chromium/quic_test_packet_maker.cc b/chromium/net/quic/chromium/quic_test_packet_maker.cc index 9676a59007d..70d83bb4234 100644 --- a/chromium/net/quic/chromium/quic_test_packet_maker.cc +++ b/chromium/net/quic/chromium/quic_test_packet_maker.cc @@ -439,8 +439,9 @@ QuicTestPacketMaker::MakeRequestHeadersAndMultipleDataFramesPacket( size_t* spdy_headers_frame_length, const std::vector<std::string>& data_writes) { InitializeHeader(packet_number, should_include_version); - SpdySerializedFrame spdy_frame = MakeSpdyHeadersFrame( - stream_id, fin, priority, std::move(headers), parent_stream_id); + SpdySerializedFrame spdy_frame = + MakeSpdyHeadersFrame(stream_id, fin && data_writes.empty(), priority, + std::move(headers), parent_stream_id); if (spdy_headers_frame_length) { *spdy_headers_frame_length = spdy_frame.size(); @@ -451,6 +452,7 @@ QuicTestPacketMaker::MakeRequestHeadersAndMultipleDataFramesPacket( QuicStreamFrame frame(kHeadersStreamId, false, header_offset, QuicStringPiece(spdy_frame.data(), spdy_frame.size())); frames.push_back(QuicFrame(&frame)); + DVLOG(1) << "Adding frame: " << frames.back(); if (header_stream_offset != nullptr) { *header_stream_offset += spdy_frame.size(); } @@ -542,6 +544,45 @@ QuicTestPacketMaker::MakeRequestHeadersPacketAndSaveData( } } +std::unique_ptr<QuicReceivedPacket> +QuicTestPacketMaker::MakeRequestHeadersAndRstPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + SpdyPriority priority, + SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, + size_t* spdy_headers_frame_length, + QuicStreamOffset* header_stream_offset, + QuicRstStreamErrorCode error_code, + size_t bytes_written) { + SpdySerializedFrame spdy_frame = MakeSpdyHeadersFrame( + stream_id, fin, priority, std::move(headers), parent_stream_id); + if (spdy_headers_frame_length) { + *spdy_headers_frame_length = spdy_frame.size(); + } + QuicStreamOffset header_offset = 0; + if (header_stream_offset != nullptr) { + header_offset = *header_stream_offset; + *header_stream_offset += spdy_frame.size(); + } + QuicStreamFrame headers_frame( + kHeadersStreamId, false, header_offset, + QuicStringPiece(spdy_frame.data(), spdy_frame.size())); + + QuicRstStreamFrame rst_frame(1, stream_id, error_code, bytes_written); + + QuicFrames frames; + frames.push_back(QuicFrame(&headers_frame)); + DVLOG(1) << "Adding frame: " << frames.back(); + frames.push_back(QuicFrame(&rst_frame)); + DVLOG(1) << "Adding frame: " << frames.back(); + + InitializeHeader(packet_number, should_include_version); + return MakeMultipleFramesPacket(header_, frames); +} + SpdySerializedFrame QuicTestPacketMaker::MakeSpdyHeadersFrame( QuicStreamId stream_id, bool fin, @@ -830,15 +871,13 @@ std::unique_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakePriorityPacket( } std::unique_ptr<QuicReceivedPacket> -QuicTestPacketMaker::MakeAckAndPriorityPacket( +QuicTestPacketMaker::MakeAckAndMultiplePriorityFramesPacket( QuicPacketNumber packet_number, bool should_include_version, QuicPacketNumber largest_received, QuicPacketNumber smallest_received, QuicPacketNumber least_unacked, - QuicStreamId stream_id, - QuicStreamId parent_stream_id, - SpdyPriority spdy_priority, + const std::vector<Http2StreamDependency>& priority_frames, QuicStreamOffset* offset) { QuicAckFrame ack(MakeAckFrame(largest_received)); ack.ack_delay_time = QuicTime::Delta::Zero(); @@ -857,22 +896,33 @@ QuicTestPacketMaker::MakeAckAndPriorityPacket( frames.push_back(QuicFrame(&stop_waiting)); DVLOG(1) << "Adding frame: " << frames[1]; - bool exclusive = client_headers_include_h2_stream_dependency_; - SpdyPriorityIR priority_frame(stream_id, parent_stream_id, - Spdy3PriorityToHttp2Weight(spdy_priority), - exclusive); - SpdySerializedFrame spdy_frame = - spdy_request_framer_.SerializeFrame(priority_frame); + const bool exclusive = client_headers_include_h2_stream_dependency_; QuicStreamOffset header_offset = 0; - if (offset != nullptr) { - header_offset = *offset; - *offset += spdy_frame.size(); + if (offset == nullptr) { + offset = &header_offset; + } + // Keep SpdySerializedFrames alive until MakeMultipleFramesPacket is done. + // Keep StreamFrames alive until MakeMultipleFramesPacket is done. + std::vector<std::unique_ptr<SpdySerializedFrame>> spdy_frames; + std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames; + for (const Http2StreamDependency& info : priority_frames) { + SpdyPriorityIR priority_frame( + info.stream_id, info.parent_stream_id, + Spdy3PriorityToHttp2Weight(info.spdy_priority), exclusive); + + spdy_frames.push_back(std::make_unique<SpdySerializedFrame>( + spdy_request_framer_.SerializeFrame(priority_frame))); + + SpdySerializedFrame* spdy_frame = spdy_frames.back().get(); + stream_frames.push_back(std::make_unique<QuicStreamFrame>( + kHeadersStreamId, false, *offset, + QuicStringPiece(spdy_frame->data(), spdy_frame->size()))); + *offset += spdy_frame->size(); + + frames.push_back(QuicFrame(stream_frames.back().get())); + DVLOG(1) << "Adding frame: " << frames.back(); + ; } - QuicStreamFrame priority( - kHeadersStreamId, false, header_offset, - QuicStringPiece(spdy_frame.data(), spdy_frame.size())); - frames.push_back(QuicFrame(&priority)); - DVLOG(1) << "Adding frame: " << frames[2]; InitializeHeader(packet_number, should_include_version); return MakeMultipleFramesPacket(header_, frames); diff --git a/chromium/net/quic/chromium/quic_test_packet_maker.h b/chromium/net/quic/chromium/quic_test_packet_maker.h index 925596dee09..c5a4a2b10b4 100644 --- a/chromium/net/quic/chromium/quic_test_packet_maker.h +++ b/chromium/net/quic/chromium/quic_test_packet_maker.h @@ -27,6 +27,12 @@ namespace test { class QuicTestPacketMaker { public: + struct Http2StreamDependency { + QuicStreamId stream_id; + QuicStreamId parent_stream_id; + SpdyPriority spdy_priority; + }; + // |client_headers_include_h2_stream_dependency| affects the output of // the MakeRequestHeaders...() methods. If its value is true, then request // headers are constructed with the exclusive flag set to true and the parent @@ -194,6 +200,19 @@ class QuicTestPacketMaker { QuicStreamOffset* offset, std::string* stream_data); + std::unique_ptr<QuicReceivedPacket> MakeRequestHeadersAndRstPacket( + QuicPacketNumber packet_number, + QuicStreamId stream_id, + bool should_include_version, + bool fin, + SpdyPriority priority, + SpdyHeaderBlock headers, + QuicStreamId parent_stream_id, + size_t* spdy_headers_frame_length, + QuicStreamOffset* header_stream_offset, + QuicRstStreamErrorCode error_code, + size_t bytes_written); + // Convenience method for calling MakeRequestHeadersPacket with nullptr for // |spdy_headers_frame_length|. std::unique_ptr<QuicReceivedPacket> @@ -268,15 +287,13 @@ class QuicTestPacketMaker { SpdyPriority priority, QuicStreamOffset* offset); - std::unique_ptr<QuicReceivedPacket> MakeAckAndPriorityPacket( + std::unique_ptr<QuicReceivedPacket> MakeAckAndMultiplePriorityFramesPacket( QuicPacketNumber packet_number, bool should_include_version, QuicPacketNumber largest_received, QuicPacketNumber smallest_received, QuicPacketNumber least_unacked, - QuicStreamId stream_id, - QuicStreamId parent_stream_id, - SpdyPriority spdy_priority, + const std::vector<Http2StreamDependency>& priority_frames, QuicStreamOffset* offset); SpdyHeaderBlock GetRequestHeaders(const std::string& method, diff --git a/chromium/net/quic/core/congestion_control/bandwidth_sampler.h b/chromium/net/quic/core/congestion_control/bandwidth_sampler.h index b42e8b91569..4255e614650 100644 --- a/chromium/net/quic/core/congestion_control/bandwidth_sampler.h +++ b/chromium/net/quic/core/congestion_control/bandwidth_sampler.h @@ -9,7 +9,6 @@ #include "net/quic/core/quic_bandwidth.h" #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_time.h" -#include "net/quic/platform/api/quic_containers.h" #include "net/quic/platform/api/quic_export.h" namespace net { @@ -250,9 +249,6 @@ class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface { is_app_limited(false) {} }; - typedef QuicLinkedHashMap<QuicPacketNumber, ConnectionStateOnSentPacket> - ConnectionStateMap; - // The total number of congestion controlled bytes sent during the connection. QuicByteCount total_bytes_sent_; diff --git a/chromium/net/quic/core/congestion_control/bbr_sender.cc b/chromium/net/quic/core/congestion_control/bbr_sender.cc index 05266e3176f..ecbdbd78b2f 100644 --- a/chromium/net/quic/core/congestion_control/bbr_sender.cc +++ b/chromium/net/quic/core/congestion_control/bbr_sender.cc @@ -138,6 +138,14 @@ BbrSender::BbrSender(const RttStats* rtt_stats, BbrSender::~BbrSender() {} +void BbrSender::SetInitialCongestionWindowInPackets( + QuicPacketCount congestion_window) { + if (mode_ == STARTUP) { + initial_congestion_window_ = congestion_window * kDefaultTCPMSS; + congestion_window_ = congestion_window * kDefaultTCPMSS; + } +} + bool BbrSender::InSlowStart() const { return mode_ == STARTUP; } @@ -412,6 +420,11 @@ bool BbrSender::UpdateBandwidthAndMinRtt( const AckedPacketVector& acked_packets) { QuicTime::Delta sample_min_rtt = QuicTime::Delta::Infinite(); for (const auto& packet : acked_packets) { + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3) && + packet.bytes_acked == 0) { + // Skip acked packets with 0 in flight bytes when updating bandwidth. + continue; + } BandwidthSample bandwidth_sample = sampler_->OnPacketAcknowledged(now, packet.packet_number); last_sample_is_app_limited_ = bandwidth_sample.is_app_limited; diff --git a/chromium/net/quic/core/congestion_control/bbr_sender.h b/chromium/net/quic/core/congestion_control/bbr_sender.h index b351665bcd7..46993fc2891 100644 --- a/chromium/net/quic/core/congestion_control/bbr_sender.h +++ b/chromium/net/quic/core/congestion_control/bbr_sender.h @@ -109,6 +109,8 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { void AdjustNetworkParameters(QuicBandwidth bandwidth, QuicTime::Delta rtt) override; void SetNumEmulatedConnections(int num_connections) override {} + void SetInitialCongestionWindowInPackets( + QuicPacketCount congestion_window) override; void OnCongestionEvent(bool rtt_updated, QuicByteCount prior_in_flight, QuicTime event_time, diff --git a/chromium/net/quic/core/congestion_control/bbr_sender_test.cc b/chromium/net/quic/core/congestion_control/bbr_sender_test.cc index 3de677b22ca..38fee561d62 100644 --- a/chromium/net/quic/core/congestion_control/bbr_sender_test.cc +++ b/chromium/net/quic/core/congestion_control/bbr_sender_test.cc @@ -250,6 +250,12 @@ class BbrSenderTest : public QuicTest { } }; +TEST_F(BbrSenderTest, SetInitialCongestionWindow) { + EXPECT_NE(3u * kDefaultTCPMSS, sender_->GetCongestionWindow()); + sender_->SetInitialCongestionWindowInPackets(3); + EXPECT_EQ(3u * kDefaultTCPMSS, sender_->GetCongestionWindow()); +} + // Test a simple long data transfer in the default setup. TEST_F(BbrSenderTest, SimpleTransfer) { // Adding TSO CWND causes packet loss before exiting startup. diff --git a/chromium/net/quic/core/congestion_control/rtt_stats.cc b/chromium/net/quic/core/congestion_control/rtt_stats.cc index 8bf8b6bc4a8..9e098d17f4b 100644 --- a/chromium/net/quic/core/congestion_control/rtt_stats.cc +++ b/chromium/net/quic/core/congestion_control/rtt_stats.cc @@ -70,12 +70,8 @@ void RttStats::UpdateRtt(QuicTime::Delta send_delta, // an RTT sample at least as large as min_rtt. Otherwise, only use the // send_delta. if (rtt_sample > ack_delay) { - if (GetQuicReloadableFlag(quic_min_rtt_ack_delay)) { - if (rtt_sample - min_rtt_ >= ack_delay) { - max_ack_delay_ = std::max(max_ack_delay_, ack_delay); - rtt_sample = rtt_sample - ack_delay; - } - } else { + if (rtt_sample - min_rtt_ >= ack_delay) { + max_ack_delay_ = std::max(max_ack_delay_, ack_delay); rtt_sample = rtt_sample - ack_delay; } } diff --git a/chromium/net/quic/core/congestion_control/rtt_stats_test.cc b/chromium/net/quic/core/congestion_control/rtt_stats_test.cc index 1e026bab5af..bc065e094cb 100644 --- a/chromium/net/quic/core/congestion_control/rtt_stats_test.cc +++ b/chromium/net/quic/core/congestion_control/rtt_stats_test.cc @@ -30,29 +30,6 @@ TEST_F(RttStatsTest, DefaultsBeforeUpdate) { } TEST_F(RttStatsTest, SmoothedRtt) { - SetQuicReloadableFlag(quic_min_rtt_ack_delay, false); - // Verify that ack_delay is corrected for in Smoothed RTT. - rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300), - QuicTime::Delta::FromMilliseconds(100), - QuicTime::Zero()); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt()); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt()); - // Verify that effective RTT of zero does not change Smoothed RTT. - rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200), - QuicTime::Delta::FromMilliseconds(200), - QuicTime::Zero()); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt()); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt()); - // Verify that large erroneous ack_delay does not change Smoothed RTT. - rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200), - QuicTime::Delta::FromMilliseconds(300), - QuicTime::Zero()); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt()); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt()); -} - -TEST_F(RttStatsTest, SmoothedRttMaxAckDelay) { - SetQuicReloadableFlag(quic_min_rtt_ack_delay, true); // Verify that ack_delay is ignored in the first measurement. rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300), QuicTime::Delta::FromMilliseconds(100), @@ -241,10 +218,7 @@ TEST_F(RttStatsTest, ResetAfterConnectionMigrations) { EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.min_rtt()); - if (GetQuicReloadableFlag(quic_min_rtt_ack_delay)) { - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), - rtt_stats_.max_ack_delay()); - } + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats_.max_ack_delay()); // Reset rtt stats on connection migrations. rtt_stats_.OnConnectionMigration(); diff --git a/chromium/net/quic/core/congestion_control/send_algorithm_interface.h b/chromium/net/quic/core/congestion_control/send_algorithm_interface.h index 3b68b9e59fd..df25ba17523 100644 --- a/chromium/net/quic/core/congestion_control/send_algorithm_interface.h +++ b/chromium/net/quic/core/congestion_control/send_algorithm_interface.h @@ -49,6 +49,10 @@ class QUIC_EXPORT_PRIVATE SendAlgorithmInterface { // particularly for congestion avoidance. Can be set any time. virtual void SetNumEmulatedConnections(int num_connections) = 0; + // Sets the initial congestion window in number of packets. May be ignored + // if called after the initial congestion window is no longer relevant. + virtual void SetInitialCongestionWindowInPackets(QuicPacketCount packets) = 0; + // Indicates an update to the congestion state, caused either by an incoming // ack or loss event timeout. |rtt_updated| indicates whether a new // latest_rtt sample has been taken, |prior_in_flight| the bytes in flight diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc index f3e77cfccbb..55cda43d009 100644 --- a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc +++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc @@ -62,30 +62,32 @@ TcpCubicSenderBytes::~TcpCubicSenderBytes() {} void TcpCubicSenderBytes::SetFromConfig(const QuicConfig& config, Perspective perspective) { if (perspective == Perspective::IS_SERVER) { - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kIW03)) { - // Initial window experiment. - SetCongestionWindowInPackets(3); - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) { - // Initial window experiment. - SetCongestionWindowInPackets(10); - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kIW20)) { - // Initial window experiment. - SetCongestionWindowInPackets(20); - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kIW50)) { - // Initial window experiment. - SetCongestionWindowInPackets(50); - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN1)) { - // Min CWND experiment. - SetMinCongestionWindowInPackets(1); + if (!GetQuicReloadableFlag(quic_unified_iw_options)) { + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kIW03)) { + // Initial window experiment. + SetInitialCongestionWindowInPackets(3); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) { + // Initial window experiment. + SetInitialCongestionWindowInPackets(10); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kIW20)) { + // Initial window experiment. + SetInitialCongestionWindowInPackets(20); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kIW50)) { + // Initial window experiment. + SetInitialCongestionWindowInPackets(50); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN1)) { + // Min CWND experiment. + SetMinCongestionWindowInPackets(1); + } } if (config.HasReceivedConnectionOptions() && ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN4)) { @@ -272,7 +274,7 @@ void TcpCubicSenderBytes::SetCongestionWindowFromBandwidthAndRtt( kMaxResumptionCongestionWindow * kDefaultTCPMSS)); } -void TcpCubicSenderBytes::SetCongestionWindowInPackets( +void TcpCubicSenderBytes::SetInitialCongestionWindowInPackets( QuicPacketCount congestion_window) { congestion_window_ = congestion_window * kDefaultTCPMSS; } @@ -321,7 +323,7 @@ void TcpCubicSenderBytes::OnPacketLost(QuicPacketNumber packet_number, prr_.OnPacketLost(prior_in_flight); } - // TODO(jri): Separate out all of slow start into a separate class. + // TODO(b/77268641): Separate out all of slow start into a separate class. if (slow_start_large_reduction_ && InSlowStart()) { DCHECK_LT(kDefaultTCPMSS, congestion_window_); if (congestion_window_ >= 2 * initial_tcp_congestion_window_) { diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h index fde4fbf835f..70071aeba2e 100644 --- a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h +++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h @@ -48,6 +48,8 @@ class QUIC_EXPORT_PRIVATE TcpCubicSenderBytes : public SendAlgorithmInterface { void AdjustNetworkParameters(QuicBandwidth bandwidth, QuicTime::Delta rtt) override; void SetNumEmulatedConnections(int num_connections) override; + void SetInitialCongestionWindowInPackets( + QuicPacketCount congestion_window) override; void OnConnectionMigration() override; void OnCongestionEvent(bool rtt_updated, QuicByteCount prior_in_flight, @@ -88,7 +90,6 @@ class QUIC_EXPORT_PRIVATE TcpCubicSenderBytes : public SendAlgorithmInterface { QuicTime event_time); void SetCongestionWindowFromBandwidthAndRtt(QuicBandwidth bandwidth, QuicTime::Delta rtt); - void SetCongestionWindowInPackets(QuicPacketCount congestion_window); void SetMinCongestionWindowInPackets(QuicPacketCount congestion_window); void ExitSlowstart(); void OnPacketLost(QuicPacketNumber largest_loss, diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc index 187a06036bb..d87be503cd6 100644 --- a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc +++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc @@ -544,6 +544,7 @@ TEST_F(TcpCubicSenderBytesTest, MultipleLossesInOneWindow) { } TEST_F(TcpCubicSenderBytesTest, ConfigureMaxInitialWindow) { + SetQuicReloadableFlag(quic_unified_iw_options, false); QuicConfig config; // Verify that kCOPT: kIW10 forces the congestion window to the default of 10. @@ -554,6 +555,12 @@ TEST_F(TcpCubicSenderBytesTest, ConfigureMaxInitialWindow) { EXPECT_EQ(10u * kDefaultTCPMSS, sender_->GetCongestionWindow()); } +TEST_F(TcpCubicSenderBytesTest, SetInitialCongestionWindow) { + EXPECT_NE(3u * kDefaultTCPMSS, sender_->GetCongestionWindow()); + sender_->SetInitialCongestionWindowInPackets(3); + EXPECT_EQ(3u * kDefaultTCPMSS, sender_->GetCongestionWindow()); +} + TEST_F(TcpCubicSenderBytesTest, 2ConnectionCongestionAvoidanceAtEndOfRecovery) { sender_->SetNumEmulatedConnections(2); // Ack 10 packets in 5 acks to raise the CWND to 20. diff --git a/chromium/net/quic/core/crypto/cert_compressor.cc b/chromium/net/quic/core/crypto/cert_compressor.cc index a8cefbcc9b4..a2670935e5e 100644 --- a/chromium/net/quic/core/crypto/cert_compressor.cc +++ b/chromium/net/quic/core/crypto/cert_compressor.cc @@ -12,6 +12,8 @@ #include "net/quic/platform/api/quic_string.h" #include "third_party/zlib/zlib.h" +using std::string; + namespace net { namespace { @@ -401,7 +403,7 @@ bool ParseEntries(QuicStringPiece* in_out, if (cert.empty()) { return false; } - out_certs->push_back(cert.as_string()); + out_certs->push_back(string(cert)); break; } default: @@ -627,7 +629,7 @@ bool CertCompressor::DecompressChain( if (uncompressed.size() < cert_len) { return false; } - (*out_certs)[i] = uncompressed.substr(0, cert_len).as_string(); + (*out_certs)[i] = string(uncompressed.substr(0, cert_len)); uncompressed.remove_prefix(cert_len); break; case CertEntry::CACHED: diff --git a/chromium/net/quic/core/crypto/common_cert_set.cc b/chromium/net/quic/core/crypto/common_cert_set.cc index 83c3e976706..8d4c2ad35a7 100644 --- a/chromium/net/quic/core/crypto/common_cert_set.cc +++ b/chromium/net/quic/core/crypto/common_cert_set.cc @@ -10,6 +10,7 @@ #include "base/memory/singleton.h" #include "net/quic/core/quic_utils.h" #include "net/quic/platform/api/quic_arraysize.h" +#include "net/quic/platform/api/quic_singleton.h" namespace net { @@ -143,14 +144,14 @@ class CommonCertSetsQUIC : public CommonCertSets { } static CommonCertSetsQUIC* GetInstance() { - return base::Singleton<CommonCertSetsQUIC>::get(); + return QuicSingleton<CommonCertSetsQUIC>::get(); } private: CommonCertSetsQUIC() {} ~CommonCertSetsQUIC() override {} - friend struct base::DefaultSingletonTraits<CommonCertSetsQUIC>; + friend QuicSingletonFriend<CommonCertSetsQUIC>; DISALLOW_COPY_AND_ASSIGN(CommonCertSetsQUIC); }; diff --git a/chromium/net/quic/core/crypto/crypto_framer.cc b/chromium/net/quic/core/crypto/crypto_framer.cc index 16c6e528d50..74ccacba2cc 100644 --- a/chromium/net/quic/core/crypto/crypto_framer.cc +++ b/chromium/net/quic/core/crypto/crypto_framer.cc @@ -9,11 +9,14 @@ #include "net/quic/core/quic_data_writer.h" #include "net/quic/core/quic_packets.h" #include "net/quic/platform/api/quic_fallthrough.h" +#include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_str_cat.h" #include "net/quic/platform/api/quic_string.h" #include "net/quic/platform/api/quic_string_piece.h" +using std::string; + namespace net { namespace { @@ -45,7 +48,11 @@ class OneShotVisitor : public CryptoFramerVisitorInterface { } // namespace CryptoFramer::CryptoFramer() - : visitor_(nullptr), error_detail_(""), num_entries_(0), values_len_(0) { + : visitor_(nullptr), + error_detail_(""), + num_entries_(0), + values_len_(0), + process_truncated_messages_(false) { Clear(); } @@ -302,11 +309,20 @@ QuicErrorCode CryptoFramer::Process(QuicStringPiece input, } case STATE_READING_VALUES: if (reader.BytesRemaining() < values_len_) { - break; + if (!process_truncated_messages_) { + break; + } + QUIC_LOG(ERROR) << "Trunacted message. Missing " + << values_len_ - reader.BytesRemaining() << " bytes."; } for (const std::pair<QuicTag, size_t>& item : tags_and_lengths_) { QuicStringPiece value; - reader.ReadStringPiece(&value, item.second); + if (!reader.ReadStringPiece(&value, item.second)) { + DCHECK(process_truncated_messages_); + // Store an empty value. + message_.SetStringPiece(item.first, ""); + continue; + } message_.SetStringPiece(item.first, value); } visitor_->OnHandshakeMessage(message_); @@ -315,7 +331,7 @@ QuicErrorCode CryptoFramer::Process(QuicStringPiece input, break; } // Save any remaining data. - buffer_ = reader.PeekRemainingPayload().as_string(); + buffer_ = string(reader.PeekRemainingPayload()); return QUIC_NO_ERROR; } diff --git a/chromium/net/quic/core/crypto/crypto_framer.h b/chromium/net/quic/core/crypto/crypto_framer.h index a3c3d091494..c4bca2bb8d5 100644 --- a/chromium/net/quic/core/crypto/crypto_framer.h +++ b/chromium/net/quic/core/crypto/crypto_framer.h @@ -84,6 +84,11 @@ class QUIC_EXPORT_PRIVATE CryptoFramer : public CryptoMessageParser { const CryptoHandshakeMessage& message, Perspective perspective); + // Debug only method which permits processing truncated messages. + void set_process_truncated_messages(bool process_truncated_messages) { + process_truncated_messages_ = process_truncated_messages; + } + private: // Clears per-message state. Does not clear the visitor. void Clear(); @@ -123,6 +128,8 @@ class QUIC_EXPORT_PRIVATE CryptoFramer : public CryptoMessageParser { std::vector<std::pair<QuicTag, size_t>> tags_and_lengths_; // Cumulative length of all values in the message currently being parsed. size_t values_len_; + // Set to true to allow of processing of truncated messages for debugging. + bool process_truncated_messages_; }; } // namespace net diff --git a/chromium/net/quic/core/crypto/crypto_handshake_message.cc b/chromium/net/quic/core/crypto/crypto_handshake_message.cc index f29bb5863a0..3c9b2a678d5 100644 --- a/chromium/net/quic/core/crypto/crypto_handshake_message.cc +++ b/chromium/net/quic/core/crypto/crypto_handshake_message.cc @@ -17,6 +17,7 @@ #include "net/quic/platform/api/quic_string.h" #include "net/quic/platform/api/quic_text_utils.h" +using std::string; namespace net { @@ -89,7 +90,7 @@ void CryptoHandshakeMessage::SetVersion(QuicTag tag, void CryptoHandshakeMessage::SetStringPiece(QuicTag tag, QuicStringPiece value) { - tag_value_map_[tag] = value.as_string(); + tag_value_map_[tag] = string(value); } void CryptoHandshakeMessage::Erase(QuicTag tag) { @@ -212,8 +213,8 @@ QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag, } QuicErrorCode CryptoHandshakeMessage::GetUint128(QuicTag tag, - uint128* out) const { - return GetPOD(tag, out, sizeof(uint128)); + QuicUint128* out) const { + return GetPOD(tag, out, sizeof(QuicUint128)); } size_t CryptoHandshakeMessage::size() const { diff --git a/chromium/net/quic/core/crypto/crypto_handshake_message.h b/chromium/net/quic/core/crypto/crypto_handshake_message.h index abdfe4c5651..772c0365f81 100644 --- a/chromium/net/quic/core/crypto/crypto_handshake_message.h +++ b/chromium/net/quic/core/crypto/crypto_handshake_message.h @@ -10,11 +10,11 @@ #include <memory> #include <vector> -#include "net/base/int128.h" #include "net/quic/core/quic_packets.h" #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_string.h" #include "net/quic/platform/api/quic_string_piece.h" +#include "net/quic/platform/api/quic_uint128.h" namespace net { @@ -107,7 +107,7 @@ class QUIC_EXPORT_PRIVATE CryptoHandshakeMessage { QuicStringPiece* out) const; QuicErrorCode GetUint32(QuicTag tag, uint32_t* out) const; QuicErrorCode GetUint64(QuicTag tag, uint64_t* out) const; - QuicErrorCode GetUint128(QuicTag tag, uint128* out) const; + QuicErrorCode GetUint128(QuicTag tag, QuicUint128* out) const; // size returns 4 (message tag) + 2 (uint16_t, number of entries) + // (4 (tag) + 4 (end offset))*tag_value_map_.size() + ∑ value sizes. diff --git a/chromium/net/quic/core/crypto/crypto_server_test.cc b/chromium/net/quic/core/crypto/crypto_server_test.cc index c7a9a336d75..8012d752fc7 100644 --- a/chromium/net/quic/core/crypto/crypto_server_test.cc +++ b/chromium/net/quic/core/crypto/crypto_server_test.cc @@ -35,6 +35,8 @@ #include "net/quic/test_tools/quic_test_utils.h" #include "third_party/boringssl/src/include/openssl/sha.h" +using std::string; + namespace net { namespace test { @@ -848,8 +850,8 @@ TEST_P(CryptoServerTest, ProofForSuppliedServerConfig) { CryptoUtils::HashHandshakeMessage(msg, &chlo_hash, Perspective::IS_SERVER); EXPECT_EQ(QUIC_SUCCESS, proof_verifier->VerifyProof( - "test.example.com", 443, scfg_str.as_string(), client_version_, - chlo_hash, certs, "", proof.as_string(), verify_context.get(), + "test.example.com", 443, (string(scfg_str)), client_version_, + chlo_hash, certs, "", (string(proof)), verify_context.get(), &error_details, &details, std::move(callback))); } @@ -1061,7 +1063,7 @@ TEST_F(CryptoServerConfigGenerationTest, SCIDIsHashOfServerConfig) { QuicStringPiece scid; EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid)); // Need to take a copy of |scid| has we're about to call |Erase|. - const QuicString scid_str(scid.as_string()); + const QuicString scid_str(scid); scfg->Erase(kSCID); scfg->MarkDirty(); diff --git a/chromium/net/quic/core/crypto/crypto_utils.cc b/chromium/net/quic/core/crypto/crypto_utils.cc index fd8fe1f9224..ccd1fd71b43 100644 --- a/chromium/net/quic/core/crypto/crypto_utils.cc +++ b/chromium/net/quic/core/crypto/crypto_utils.cc @@ -7,6 +7,8 @@ #include <memory> #include "crypto/hkdf.h" +#include "net/quic/core/crypto/aes_128_gcm_decrypter.h" +#include "net/quic/core/crypto/aes_128_gcm_encrypter.h" #include "net/quic/core/crypto/crypto_handshake.h" #include "net/quic/core/crypto/crypto_protocol.h" #include "net/quic/core/crypto/quic_decrypter.h" @@ -17,47 +19,118 @@ #include "net/quic/platform/api/quic_arraysize.h" #include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_logging.h" +#include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_string.h" #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/hkdf.h" #include "third_party/boringssl/src/include/openssl/sha.h" +using std::string; namespace net { // static -std::vector<uint8_t> CryptoUtils::HkdfExpandLabel( +std::vector<uint8_t> CryptoUtils::QhkdfExpand( const EVP_MD* prf, const std::vector<uint8_t>& secret, const QuicString& label, size_t out_len) { - CBB hkdf_label, inner_label; - const char label_prefix[] = "tls13 "; - if (!CBB_init(&hkdf_label, 1) || !CBB_add_u16(&hkdf_label, out_len) || - !CBB_add_u8_length_prefixed(&hkdf_label, &inner_label) || + bssl::ScopedCBB quic_hkdf_label; + CBB inner_label; + const char label_prefix[] = "QUIC "; + // The minimum possible length for the QuicHkdfLabel is 10 bytes - 2 bytes for + // Length, plus 1 byte for the length of the inner label, plus the length of + // that label (which is at least 6), plus 1 byte at the end. + if (!CBB_init(quic_hkdf_label.get(), 10) || + !CBB_add_u16(quic_hkdf_label.get(), out_len) || + !CBB_add_u8_length_prefixed(quic_hkdf_label.get(), &inner_label) || !CBB_add_bytes(&inner_label, reinterpret_cast<const uint8_t*>(label_prefix), QUIC_ARRAYSIZE(label_prefix) - 1) || !CBB_add_bytes(&inner_label, reinterpret_cast<const uint8_t*>(label.data()), label.size()) || - !CBB_add_u8(&hkdf_label, 0) || !CBB_flush(&hkdf_label)) { + !CBB_add_u8(quic_hkdf_label.get(), 0) || + !CBB_flush(quic_hkdf_label.get())) { QUIC_LOG(ERROR) << "Building HKDF label failed"; - CBB_cleanup(&hkdf_label); - std::vector<uint8_t>(); + return std::vector<uint8_t>(); } std::vector<uint8_t> out; out.resize(out_len); if (!HKDF_expand(out.data(), out_len, prf, secret.data(), secret.size(), - CBB_data(&hkdf_label), CBB_len(&hkdf_label))) { + CBB_data(quic_hkdf_label.get()), + CBB_len(quic_hkdf_label.get()))) { QUIC_LOG(ERROR) << "Running HKDF-Expand-Label failed"; - CBB_cleanup(&hkdf_label); - std::vector<uint8_t>(); + return std::vector<uint8_t>(); } - CBB_cleanup(&hkdf_label); return out; } +template <class QuicCrypter> +void CryptoUtils::SetKeyAndIV(const EVP_MD* prf, + const std::vector<uint8_t>& pp_secret, + QuicCrypter* crypter) { + std::vector<uint8_t> key = + CryptoUtils::QhkdfExpand(prf, pp_secret, "key", crypter->GetKeySize()); + std::vector<uint8_t> iv = + CryptoUtils::QhkdfExpand(prf, pp_secret, "iv", crypter->GetIVSize()); + crypter->SetKey( + QuicStringPiece(reinterpret_cast<char*>(key.data()), key.size())); + crypter->SetIV( + QuicStringPiece(reinterpret_cast<char*>(iv.data()), iv.size())); +} + +namespace { + +const uint8_t kQuicVersion1Salt[] = {0xaf, 0xc8, 0x24, 0xec, 0x5f, 0xc7, 0x7e, + 0xca, 0x1e, 0x9d, 0x36, 0xf3, 0x7f, 0xb2, + 0xd4, 0x65, 0x18, 0xc3, 0x66, 0x39}; + +} // namespace + +// static +void CryptoUtils::CreateTlsInitialCrypters(Perspective perspective, + QuicConnectionId connection_id, + CrypterPair* crypters) { + const EVP_MD* hash = EVP_sha256(); + + uint8_t connection_id_bytes[sizeof(connection_id)]; + for (size_t i = 0; i < sizeof(connection_id); ++i) { + connection_id_bytes[i] = + (connection_id >> ((sizeof(connection_id) - i - 1) * 8)) & 0xff; + } + + std::vector<uint8_t> handshake_secret; + handshake_secret.resize(EVP_MAX_MD_SIZE); + size_t handshake_secret_len; + if (!HKDF_extract(handshake_secret.data(), &handshake_secret_len, hash, + connection_id_bytes, arraysize(connection_id_bytes), + kQuicVersion1Salt, arraysize(kQuicVersion1Salt))) { + QUIC_BUG << "HKDF_extract failed when creating initial crypters"; + } + handshake_secret.resize(handshake_secret_len); + + const string client_label = "client hs"; + const string server_label = "server hs"; + string encryption_label, decryption_label; + if (perspective == Perspective::IS_CLIENT) { + encryption_label = client_label; + decryption_label = server_label; + } else { + encryption_label = server_label; + decryption_label = client_label; + } + crypters->encrypter = QuicMakeUnique<Aes128GcmEncrypter>(); + std::vector<uint8_t> encryption_secret = + QhkdfExpand(hash, handshake_secret, encryption_label, EVP_MD_size(hash)); + SetKeyAndIV(hash, encryption_secret, crypters->encrypter.get()); + + crypters->decrypter = QuicMakeUnique<Aes128GcmDecrypter>(); + std::vector<uint8_t> decryption_secret = + QhkdfExpand(hash, handshake_secret, decryption_label, EVP_MD_size(hash)); + SetKeyAndIV(hash, decryption_secret, crypters->decrypter.get()); +} + // static void CryptoUtils::GenerateNonce(QuicWallTime now, QuicRandom* random_generator, @@ -105,7 +178,7 @@ bool CryptoUtils::DeriveKeys(QuicStringPiece premaster_secret, QuicStringPiece nonce = client_nonce; QuicString nonce_storage; if (!server_nonce.empty()) { - nonce_storage = client_nonce.as_string() + server_nonce.as_string(); + nonce_storage = string(client_nonce) + string(server_nonce); nonce = nonce_storage; } @@ -197,7 +270,7 @@ bool CryptoUtils::ExportKeyingMaterial(QuicStringPiece subkey_secret, return false; } uint32_t context_length = static_cast<uint32_t>(context.length()); - QuicString info = label.as_string(); + QuicString info = string(label); info.push_back('\0'); info.append(reinterpret_cast<char*>(&context_length), sizeof(context_length)); info.append(context.data(), context.length()); diff --git a/chromium/net/quic/core/crypto/crypto_utils.h b/chromium/net/quic/core/crypto/crypto_utils.h index fc9545a24df..ab8f492aa72 100644 --- a/chromium/net/quic/core/crypto/crypto_utils.h +++ b/chromium/net/quic/core/crypto/crypto_utils.h @@ -69,21 +69,37 @@ class QUIC_EXPORT_PRIVATE CryptoUtils { DiversificationNonce* nonce_; }; - // Implements the HKDF-Expand-Label function as defined in section 7.1 of TLS - // 1.3. The HKDF-Expand-Label definition assumes that the TLS connection's PRF - // will be used as the Hash function for HKDF; in this function it is - // explicitly passed in as |prf|. The inputs to HKDF-Expand-Label are as - // follows: + // Implements the QHKDF-Expand function defined in section 5.2.3 of + // draft-ietf-quic-tls-09. The QHKDF-Expand function takes 3 explicit + // arguments, as well as an implicit PRF which is the hash function negotiated + // by TLS. This PRF is passed in as |prf|; the explicit arguments to + // QHKDF-Expand - Secret, Label, and Length - are passed in as |secret|, + // |label|, and |out_len|, respectively. + static std::vector<uint8_t> QhkdfExpand(const EVP_MD* prf, + const std::vector<uint8_t>& secret, + const std::string& label, + size_t out_len); + + // SetKeyAndIV derives the key and IV from the given packet protection secret + // |pp_secret| and sets those fields on the given QuicEncrypter or + // QuicDecrypter |*crypter|. This follows the derivation described in section + // 5.2.4 of draft-ietf-quic-tls-09. + template <class QuicCrypter> + static void SetKeyAndIV(const EVP_MD* prf, + const std::vector<uint8_t>& pp_secret, + QuicCrypter* crypter); + + // QUIC encrypts TLS handshake messages with a version-specific key (to + // prevent network observers that are not aware of that QUIC version from + // making decisions based on the TLS handshake). This packet protection secret + // is derived from the connection ID in the client's Initial packet. // - // Secret: |secret| - // Label: |label| - // Context: zero-length context - // Length: |out_len| - static std::vector<uint8_t> HkdfExpandLabel( - const EVP_MD* prf, - const std::vector<uint8_t>& secret, - const QuicString& label, - size_t out_len); + // This function takes that |connection_id| and creates the encrypter and + // decrypter (put in |*crypters|) to use for this packet protection, as well + // as setting the key and IV on those crypters. + static void CreateTlsInitialCrypters(Perspective perspective, + QuicConnectionId connection_id, + CrypterPair* crypters); // Generates the connection nonce. The nonce is formed as: // <4 bytes> current time diff --git a/chromium/net/quic/core/crypto/crypto_utils_test.cc b/chromium/net/quic/core/crypto/crypto_utils_test.cc index 58ff13b2c94..dfecd9195bd 100644 --- a/chromium/net/quic/core/crypto/crypto_utils_test.cc +++ b/chromium/net/quic/core/crypto/crypto_utils_test.cc @@ -18,21 +18,19 @@ namespace { class CryptoUtilsTest : public QuicTest {}; -TEST_F(CryptoUtilsTest, TestHkdfExpandLabel) { - // This test vector is from - // https://github.com/quicwg/base-drafts/wiki/Test-Vector-for-the-Clear-Text-AEAD-key-derivation +TEST_F(CryptoUtilsTest, TestQhkdfExpand) { const std::vector<uint8_t> secret = { 0x8f, 0x01, 0x00, 0x67, 0x9c, 0x96, 0x5a, 0xc5, 0x9f, 0x28, 0x3a, 0x02, 0x52, 0x2a, 0x6e, 0x43, 0xcf, 0xae, 0xf6, 0x3c, 0x45, 0x48, 0xb0, 0xa6, 0x8f, 0x91, 0x91, 0x40, 0xee, 0x7d, 0x9a, 0x48}; - const QuicString label = "QUIC client cleartext Secret"; + const QuicString label = "client hs"; std::vector<uint8_t> out = - CryptoUtils::HkdfExpandLabel(EVP_sha256(), secret, label, 32); + CryptoUtils::QhkdfExpand(EVP_sha256(), secret, label, 32); std::vector<uint8_t> expected_out = { - 0x31, 0xba, 0x96, 0x68, 0x73, 0xf7, 0xf4, 0x53, 0xe6, 0xc8, 0xa1, - 0xbf, 0x78, 0xed, 0x70, 0x13, 0xfa, 0xd8, 0x3f, 0xfc, 0xee, 0xfc, - 0x95, 0x68, 0x81, 0xcd, 0x24, 0x1c, 0x0a, 0xe3, 0xa7, 0xa6}; + 0x8e, 0x28, 0x6a, 0x27, 0x38, 0xe6, 0x66, 0x50, 0xb4, 0xf8, 0x8f, + 0xac, 0x5d, 0xc5, 0xd0, 0xef, 0x7d, 0x36, 0x9b, 0x07, 0xd4, 0x74, + 0x42, 0x99, 0x1a, 0x00, 0x0c, 0x55, 0xac, 0xc4, 0x0c, 0xf4}; EXPECT_EQ(out, expected_out); } diff --git a/chromium/net/quic/core/crypto/null_decrypter.cc b/chromium/net/quic/core/crypto/null_decrypter.cc index 8d76dfb7b0b..38f3fbb3c2f 100644 --- a/chromium/net/quic/core/crypto/null_decrypter.cc +++ b/chromium/net/quic/core/crypto/null_decrypter.cc @@ -6,10 +6,10 @@ #include <cstdint> -#include "net/base/int128.h" #include "net/quic/core/quic_data_reader.h" #include "net/quic/core/quic_utils.h" #include "net/quic/platform/api/quic_bug_tracker.h" +#include "net/quic/platform/api/quic_uint128.h" using std::string; @@ -49,7 +49,7 @@ bool NullDecrypter::DecryptPacket(QuicTransportVersion version, size_t max_output_length) { QuicDataReader reader(ciphertext.data(), ciphertext.length(), HOST_BYTE_ORDER); - uint128 hash; + QuicUint128 hash; if (!ReadHash(&reader, &hash)) { return false; @@ -89,20 +89,20 @@ uint32_t NullDecrypter::cipher_id() const { return 0; } -bool NullDecrypter::ReadHash(QuicDataReader* reader, uint128* hash) { +bool NullDecrypter::ReadHash(QuicDataReader* reader, QuicUint128* hash) { uint64_t lo; uint32_t hi; if (!reader->ReadUInt64(&lo) || !reader->ReadUInt32(&hi)) { return false; } - *hash = MakeUint128(hi, lo); + *hash = MakeQuicUint128(hi, lo); return true; } -uint128 NullDecrypter::ComputeHash(QuicTransportVersion version, - const QuicStringPiece data1, - const QuicStringPiece data2) const { - uint128 correct_hash; +QuicUint128 NullDecrypter::ComputeHash(QuicTransportVersion version, + const QuicStringPiece data1, + const QuicStringPiece data2) const { + QuicUint128 correct_hash; if (version > QUIC_VERSION_35) { if (perspective_ == Perspective::IS_CLIENT) { // Peer is a server. @@ -115,7 +115,7 @@ uint128 NullDecrypter::ComputeHash(QuicTransportVersion version, } else { correct_hash = QuicUtils::FNV1a_128_Hash_Two(data1, data2); } - uint128 mask = MakeUint128(UINT64_C(0x0), UINT64_C(0xffffffff)); + QuicUint128 mask = MakeQuicUint128(UINT64_C(0x0), UINT64_C(0xffffffff)); mask <<= 96; correct_hash &= ~mask; return correct_hash; diff --git a/chromium/net/quic/core/crypto/null_decrypter.h b/chromium/net/quic/core/crypto/null_decrypter.h index 0ca74fe8cc0..67743dc429c 100644 --- a/chromium/net/quic/core/crypto/null_decrypter.h +++ b/chromium/net/quic/core/crypto/null_decrypter.h @@ -8,13 +8,12 @@ #include <cstddef> #include <cstdint> -#include "base/compiler_specific.h" #include "base/macros.h" -#include "net/base/int128.h" #include "net/quic/core/crypto/quic_decrypter.h" #include "net/quic/core/quic_types.h" #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_string_piece.h" +#include "net/quic/platform/api/quic_uint128.h" namespace net { @@ -49,10 +48,10 @@ class QUIC_EXPORT_PRIVATE NullDecrypter : public QuicDecrypter { uint32_t cipher_id() const override; private: - bool ReadHash(QuicDataReader* reader, uint128* hash); - uint128 ComputeHash(QuicTransportVersion version, - QuicStringPiece data1, - QuicStringPiece data2) const; + bool ReadHash(QuicDataReader* reader, QuicUint128* hash); + QuicUint128 ComputeHash(QuicTransportVersion version, + QuicStringPiece data1, + QuicStringPiece data2) const; Perspective perspective_; diff --git a/chromium/net/quic/core/crypto/null_encrypter.cc b/chromium/net/quic/core/crypto/null_encrypter.cc index 999d717c85b..4ea40c13328 100644 --- a/chromium/net/quic/core/crypto/null_encrypter.cc +++ b/chromium/net/quic/core/crypto/null_encrypter.cc @@ -39,7 +39,7 @@ bool NullEncrypter::EncryptPacket(QuicTransportVersion version, if (max_output_length < len) { return false; } - uint128 hash; + QuicUint128 hash; if (version > QUIC_VERSION_35) { if (perspective_ == Perspective::IS_SERVER) { hash = diff --git a/chromium/net/quic/core/crypto/quic_crypto_client_config.cc b/chromium/net/quic/core/crypto/quic_crypto_client_config.cc index 6d64c19b43d..1ce64244329 100644 --- a/chromium/net/quic/core/crypto/quic_crypto_client_config.cc +++ b/chromium/net/quic/core/crypto/quic_crypto_client_config.cc @@ -32,6 +32,7 @@ #include "net/quic/platform/api/quic_text_utils.h" #include "third_party/boringssl/src/include/openssl/ssl.h" +using std::string; namespace net { @@ -184,7 +185,7 @@ QuicCryptoClientConfig::CachedState::SetServerConfig( } if (!matches_existing) { - server_config_ = server_config.as_string(); + server_config_ = string(server_config); SetProofInvalid(); scfg_ = std::move(new_scfg_storage); } @@ -224,9 +225,9 @@ void QuicCryptoClientConfig::CachedState::SetProof( // If the proof has changed then it needs to be revalidated. SetProofInvalid(); certs_ = certs; - cert_sct_ = cert_sct.as_string(); - chlo_hash_ = chlo_hash.as_string(); - server_config_sig_ = signature.as_string(); + cert_sct_ = string(cert_sct); + chlo_hash_ = string(chlo_hash); + server_config_sig_ = string(signature); } void QuicCryptoClientConfig::CachedState::Clear() { @@ -337,12 +338,12 @@ QuicCryptoClientConfig::CachedState::proof_verify_details() const { void QuicCryptoClientConfig::CachedState::set_source_address_token( QuicStringPiece token) { - source_address_token_ = token.as_string(); + source_address_token_ = string(token); } void QuicCryptoClientConfig::CachedState::set_cert_sct( QuicStringPiece cert_sct) { - cert_sct_ = cert_sct.as_string(); + cert_sct_ = string(cert_sct); } void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails( @@ -818,7 +819,7 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection( QuicStringPiece nonce; if (rej.GetStringPiece(kServerNonceTag, &nonce)) { - out_params->server_nonce = nonce.as_string(); + out_params->server_nonce = string(nonce); } if (rej.tag() == kSREJ) { @@ -830,7 +831,7 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection( connection_id = QuicEndian::NetToHost64(connection_id); cached->add_server_designated_connection_id(connection_id); if (!nonce.empty()) { - cached->add_server_nonce(nonce.as_string()); + cached->add_server_nonce(string(nonce)); } return QUIC_NO_ERROR; } diff --git a/chromium/net/quic/core/crypto/quic_crypto_server_config.cc b/chromium/net/quic/core/crypto/quic_crypto_server_config.cc index 9e677ac8094..a376ea9fae6 100644 --- a/chromium/net/quic/core/crypto/quic_crypto_server_config.cc +++ b/chromium/net/quic/core/crypto/quic_crypto_server_config.cc @@ -45,6 +45,7 @@ #include "third_party/boringssl/src/include/openssl/sha.h" #include "third_party/boringssl/src/include/openssl/ssl.h" +using std::string; namespace net { @@ -64,7 +65,7 @@ QuicString DeriveSourceAddressTokenKey( source_address_token_secret, QuicStringPiece() /* no salt */, "QUIC source address token key", CryptoSecretBoxer::GetKeySize(), 0 /* no fixed IV needed */, 0 /* no subkey secret */); - return hkdf.server_write_key().as_string(); + return string(hkdf.server_write_key()); } } // namespace @@ -707,7 +708,7 @@ void QuicCryptoServerConfig::ProcessClientHello( compressed_certs_cache, params, signed_config, total_framing_overhead, chlo_packet_size, requested_config, primary_config, std::move(done_cb))); - proof_source_->GetProof(server_address, info.sni.as_string(), + proof_source_->GetProof(server_address, string(info.sni), primary_config->serialized, version, chlo_hash, std::move(cb)); helper.DetachCallback(); @@ -918,7 +919,7 @@ void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof( return; } - params->channel_id = key.as_string(); + params->channel_id = string(key); } } @@ -952,7 +953,7 @@ void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof( std::unique_ptr<KeyExchange> forward_secure_key_exchange( key_exchange->NewKeyPair(rand)); forward_secure_public_value = - forward_secure_key_exchange->public_value().as_string(); + string(forward_secure_key_exchange->public_value()); if (!forward_secure_key_exchange->CalculateSharedKey( public_value, ¶ms->forward_secure_premaster_secret)) { helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, @@ -1004,7 +1005,7 @@ QuicCryptoServerConfig::GetConfigWithScid( configs_lock_.AssertReaderHeld(); if (!requested_scid.empty()) { - ConfigMap::const_iterator it = configs_.find(requested_scid.as_string()); + ConfigMap::const_iterator it = configs_.find((string(requested_scid))); if (it != configs_.end()) { // We'll use the config that the client requested in order to do // key-agreement. @@ -1262,7 +1263,7 @@ void QuicCryptoServerConfig::EvaluateClientHello( *this, found_error, server_address.host(), version, requested_config, primary_config, signed_config, client_hello_state, std::move(done_cb))); - proof_source_->GetProof(server_address, info->sni.as_string(), + proof_source_->GetProof(server_address, string(info->sni), serialized_config, version, chlo_hash, std::move(cb)); helper.DetachCallback(); @@ -1490,12 +1491,12 @@ void QuicCryptoServerConfig::BuildRejection( QuicStringPiece client_common_set_hashes; if (client_hello.GetStringPiece(kCCS, &client_common_set_hashes)) { - params->client_common_set_hashes = client_common_set_hashes.as_string(); + params->client_common_set_hashes = string(client_common_set_hashes); } QuicStringPiece client_cached_cert_hashes; if (client_hello.GetStringPiece(kCCRT, &client_cached_cert_hashes)) { - params->client_cached_cert_hashes = client_cached_cert_hashes.as_string(); + params->client_cached_cert_hashes = string(client_cached_cert_hashes); } else { params->client_cached_cert_hashes.clear(); } @@ -1597,7 +1598,7 @@ QuicCryptoServerConfig::ParseConfigProtobuf( QUIC_LOG(WARNING) << "Server config message is missing SCID"; return nullptr; } - config->id = scid.as_string(); + config->id = string(scid); if (msg->GetTaglist(kAEAD, &config->aead) != QUIC_NO_ERROR) { QUIC_LOG(WARNING) << "Server config message is missing AEAD"; diff --git a/chromium/net/quic/core/crypto/quic_crypto_server_config_test.cc b/chromium/net/quic/core/crypto/quic_crypto_server_config_test.cc index 94350e48099..00d5e9816e5 100644 --- a/chromium/net/quic/core/crypto/quic_crypto_server_config_test.cc +++ b/chromium/net/quic/core/crypto/quic_crypto_server_config_test.cc @@ -23,6 +23,7 @@ #include "net/quic/test_tools/mock_clock.h" #include "net/quic/test_tools/quic_crypto_server_config_peer.h" +using std::string; namespace net { namespace test { @@ -132,7 +133,7 @@ TEST_F(QuicCryptoServerConfigTest, CompressDifferentCerts) { QuicStringPiece different_common_certs( reinterpret_cast<const char*>(&set_hash), sizeof(set_hash)); QuicString compressed3 = QuicCryptoServerConfigPeer::CompressChain( - &compressed_certs_cache, chain, different_common_certs.as_string(), + &compressed_certs_cache, chain, string(different_common_certs), cached_certs, common_sets.get()); EXPECT_EQ(compressed_certs_cache.Size(), 3u); } diff --git a/chromium/net/quic/core/crypto/quic_decrypter.cc b/chromium/net/quic/core/crypto/quic_decrypter.cc index 73d2f2f59a3..83f97ccc07b 100644 --- a/chromium/net/quic/core/crypto/quic_decrypter.cc +++ b/chromium/net/quic/core/crypto/quic_decrypter.cc @@ -14,18 +14,21 @@ #include "net/quic/core/crypto/null_decrypter.h" #include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_logging.h" +#include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_string.h" #include "third_party/boringssl/src/include/openssl/tls1.h" +using std::string; + namespace net { // static std::unique_ptr<QuicDecrypter> QuicDecrypter::Create(QuicTag algorithm) { switch (algorithm) { case kAESG: - return std::make_unique<Aes128Gcm12Decrypter>(); + return QuicMakeUnique<Aes128Gcm12Decrypter>(); case kCC20: - return std::make_unique<ChaCha20Poly1305Decrypter>(); + return QuicMakeUnique<ChaCha20Poly1305Decrypter>(); default: QUIC_LOG(FATAL) << "Unsupported algorithm: " << algorithm; return nullptr; @@ -33,23 +36,19 @@ std::unique_ptr<QuicDecrypter> QuicDecrypter::Create(QuicTag algorithm) { } // static -QuicDecrypter* QuicDecrypter::CreateFromCipherSuite(uint32_t cipher_suite) { - QuicDecrypter* decrypter; +std::unique_ptr<QuicDecrypter> QuicDecrypter::CreateFromCipherSuite( + uint32_t cipher_suite) { switch (cipher_suite) { case TLS1_CK_AES_128_GCM_SHA256: - decrypter = new Aes128GcmDecrypter(); - break; + return QuicMakeUnique<Aes128GcmDecrypter>(); case TLS1_CK_AES_256_GCM_SHA384: - decrypter = new Aes256GcmDecrypter(); - break; + return QuicMakeUnique<Aes256GcmDecrypter>(); case TLS1_CK_CHACHA20_POLY1305_SHA256: - decrypter = new ChaCha20Poly1305TlsDecrypter(); - break; + return QuicMakeUnique<ChaCha20Poly1305TlsDecrypter>(); default: QUIC_BUG << "TLS cipher suite is unknown to QUIC"; return nullptr; } - return decrypter; } // static @@ -60,12 +59,12 @@ void QuicDecrypter::DiversifyPreliminaryKey(QuicStringPiece preliminary_key, size_t nonce_prefix_size, QuicString* out_key, QuicString* out_nonce_prefix) { - crypto::HKDF hkdf(preliminary_key.as_string() + nonce_prefix.as_string(), + crypto::HKDF hkdf((string(preliminary_key)) + (string(nonce_prefix)), QuicStringPiece(nonce.data(), nonce.size()), "QUIC key diversification", 0, key_size, 0, nonce_prefix_size, 0); - *out_key = hkdf.server_write_key().as_string(); - *out_nonce_prefix = hkdf.server_write_iv().as_string(); + *out_key = string(hkdf.server_write_key()); + *out_nonce_prefix = string(hkdf.server_write_iv()); } } // namespace net diff --git a/chromium/net/quic/core/crypto/quic_decrypter.h b/chromium/net/quic/core/crypto/quic_decrypter.h index 62d25d4bcda..2ffd26f6761 100644 --- a/chromium/net/quic/core/crypto/quic_decrypter.h +++ b/chromium/net/quic/core/crypto/quic_decrypter.h @@ -25,7 +25,8 @@ class QUIC_EXPORT_PRIVATE QuicDecrypter { // Creates an IETF QuicDecrypter based on |cipher_suite| which must be an id // returned by SSL_CIPHER_get_id. The caller is responsible for taking // ownership of the new QuicDecrypter. - static QuicDecrypter* CreateFromCipherSuite(uint32_t cipher_suite); + static std::unique_ptr<QuicDecrypter> CreateFromCipherSuite( + uint32_t cipher_suite); // Sets the encryption key. Returns true on success, false on failure. // diff --git a/chromium/net/quic/core/crypto/quic_encrypter.cc b/chromium/net/quic/core/crypto/quic_encrypter.cc index ef78336035e..15d84f1bc1d 100644 --- a/chromium/net/quic/core/crypto/quic_encrypter.cc +++ b/chromium/net/quic/core/crypto/quic_encrypter.cc @@ -13,6 +13,7 @@ #include "net/quic/core/crypto/null_encrypter.h" #include "net/quic/platform/api/quic_bug_tracker.h" #include "net/quic/platform/api/quic_logging.h" +#include "net/quic/platform/api/quic_ptr_util.h" #include "third_party/boringssl/src/include/openssl/tls1.h" namespace net { @@ -21,9 +22,9 @@ namespace net { std::unique_ptr<QuicEncrypter> QuicEncrypter::Create(QuicTag algorithm) { switch (algorithm) { case kAESG: - return std::make_unique<Aes128Gcm12Encrypter>(); + return QuicMakeUnique<Aes128Gcm12Encrypter>(); case kCC20: - return std::make_unique<ChaCha20Poly1305Encrypter>(); + return QuicMakeUnique<ChaCha20Poly1305Encrypter>(); default: QUIC_LOG(FATAL) << "Unsupported algorithm: " << algorithm; return nullptr; @@ -31,23 +32,19 @@ std::unique_ptr<QuicEncrypter> QuicEncrypter::Create(QuicTag algorithm) { } // static -QuicEncrypter* QuicEncrypter::CreateFromCipherSuite(uint32_t cipher_suite) { - QuicEncrypter* encrypter; +std::unique_ptr<QuicEncrypter> QuicEncrypter::CreateFromCipherSuite( + uint32_t cipher_suite) { switch (cipher_suite) { case TLS1_CK_AES_128_GCM_SHA256: - encrypter = new Aes128GcmEncrypter(); - break; + return QuicMakeUnique<Aes128GcmEncrypter>(); case TLS1_CK_AES_256_GCM_SHA384: - encrypter = new Aes256GcmEncrypter(); - break; + return QuicMakeUnique<Aes256GcmEncrypter>(); case TLS1_CK_CHACHA20_POLY1305_SHA256: - encrypter = new ChaCha20Poly1305TlsEncrypter(); - break; + return QuicMakeUnique<ChaCha20Poly1305TlsEncrypter>(); default: QUIC_BUG << "TLS cipher suite is unknown to QUIC"; return nullptr; } - return encrypter; } } // namespace net diff --git a/chromium/net/quic/core/crypto/quic_encrypter.h b/chromium/net/quic/core/crypto/quic_encrypter.h index bc32213a1eb..d84f4342e23 100644 --- a/chromium/net/quic/core/crypto/quic_encrypter.h +++ b/chromium/net/quic/core/crypto/quic_encrypter.h @@ -22,8 +22,9 @@ class QUIC_EXPORT_PRIVATE QuicEncrypter { // Creates an IETF QuicEncrypter based on |cipher_suite| which must be an id // returned by SSL_CIPHER_get_id. The caller is responsible for taking - // ownership of the new QuicEncrypter. - static QuicEncrypter* CreateFromCipherSuite(uint32_t cipher_suite); + // ownership of the nwe QuicEncrypter. + static std::unique_ptr<QuicEncrypter> CreateFromCipherSuite( + uint32_t cipher_suite); // Sets the encryption key. Returns true on success, false on failure. // diff --git a/chromium/net/quic/core/crypto/quic_random.cc b/chromium/net/quic/core/crypto/quic_random.cc index ac54517bff1..2c5e1e22a1b 100644 --- a/chromium/net/quic/core/crypto/quic_random.cc +++ b/chromium/net/quic/core/crypto/quic_random.cc @@ -8,6 +8,7 @@ #include "base/memory/singleton.h" #include "crypto/random.h" #include "net/quic/platform/api/quic_bug_tracker.h" +#include "net/quic/platform/api/quic_singleton.h" namespace net { @@ -26,12 +27,12 @@ class DefaultRandom : public QuicRandom { DefaultRandom() {} ~DefaultRandom() override {} - friend struct base::DefaultSingletonTraits<DefaultRandom>; + friend QuicSingletonFriend<DefaultRandom>; DISALLOW_COPY_AND_ASSIGN(DefaultRandom); }; DefaultRandom* DefaultRandom::GetInstance() { - return base::Singleton<DefaultRandom>::get(); + return QuicSingleton<DefaultRandom>::get(); } void DefaultRandom::RandBytes(void* data, size_t len) { diff --git a/chromium/net/quic/core/frames/quic_connection_close_frame.cc b/chromium/net/quic/core/frames/quic_connection_close_frame.cc index 4aef61dbc15..0d6062e726f 100644 --- a/chromium/net/quic/core/frames/quic_connection_close_frame.cc +++ b/chromium/net/quic/core/frames/quic_connection_close_frame.cc @@ -9,6 +9,10 @@ namespace net { QuicConnectionCloseFrame::QuicConnectionCloseFrame() : error_code(QUIC_NO_ERROR) {} +QuicConnectionCloseFrame::QuicConnectionCloseFrame(QuicErrorCode error_code, + QuicString error_details) + : error_code(error_code), error_details(error_details) {} + std::ostream& operator<<( std::ostream& os, const QuicConnectionCloseFrame& connection_close_frame) { diff --git a/chromium/net/quic/core/frames/quic_connection_close_frame.h b/chromium/net/quic/core/frames/quic_connection_close_frame.h index 31f05d1e53a..89fa51c698a 100644 --- a/chromium/net/quic/core/frames/quic_connection_close_frame.h +++ b/chromium/net/quic/core/frames/quic_connection_close_frame.h @@ -15,6 +15,7 @@ namespace net { struct QUIC_EXPORT_PRIVATE QuicConnectionCloseFrame { QuicConnectionCloseFrame(); + QuicConnectionCloseFrame(QuicErrorCode error_code, QuicString error_details); friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( std::ostream& os, diff --git a/chromium/net/quic/core/frames/quic_frame.h b/chromium/net/quic/core/frames/quic_frame.h index affa1d6d1f3..244fe3f8102 100644 --- a/chromium/net/quic/core/frames/quic_frame.h +++ b/chromium/net/quic/core/frames/quic_frame.h @@ -12,10 +12,16 @@ #include "net/quic/core/frames/quic_blocked_frame.h" #include "net/quic/core/frames/quic_connection_close_frame.h" #include "net/quic/core/frames/quic_goaway_frame.h" +#include "net/quic/core/frames/quic_ietf_blocked_frame.h" +#include "net/quic/core/frames/quic_ietf_max_stream_id_frame.h" +#include "net/quic/core/frames/quic_ietf_stream_id_blocked_frame.h" #include "net/quic/core/frames/quic_mtu_discovery_frame.h" #include "net/quic/core/frames/quic_padding_frame.h" +#include "net/quic/core/frames/quic_path_challenge_frame.h" +#include "net/quic/core/frames/quic_path_response_frame.h" #include "net/quic/core/frames/quic_ping_frame.h" #include "net/quic/core/frames/quic_rst_stream_frame.h" +#include "net/quic/core/frames/quic_stop_sending_frame.h" #include "net/quic/core/frames/quic_stop_waiting_frame.h" #include "net/quic/core/frames/quic_stream_frame.h" #include "net/quic/core/frames/quic_window_update_frame.h" diff --git a/chromium/net/quic/core/frames/quic_ietf_blocked_frame.cc b/chromium/net/quic/core/frames/quic_ietf_blocked_frame.cc new file mode 100644 index 00000000000..f31f0555a1b --- /dev/null +++ b/chromium/net/quic/core/frames/quic_ietf_blocked_frame.cc @@ -0,0 +1,21 @@ +// Copyright (c) 2016 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/core/frames/quic_ietf_blocked_frame.h" + +namespace net { + +QuicIetfBlockedFrame::QuicIetfBlockedFrame() {} + +QuicIetfBlockedFrame::QuicIetfBlockedFrame(QuicControlFrameId control_frame_id, + QuicStreamOffset offset) + : QuicControlFrame(control_frame_id), offset(offset) {} + +std::ostream& operator<<(std::ostream& os, const QuicIetfBlockedFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", offset: " << frame.offset << " }\n"; + return os; +} + +} // namespace net diff --git a/chromium/net/quic/core/frames/quic_ietf_blocked_frame.h b/chromium/net/quic/core/frames/quic_ietf_blocked_frame.h new file mode 100644 index 00000000000..b0474f2cd11 --- /dev/null +++ b/chromium/net/quic/core/frames/quic_ietf_blocked_frame.h @@ -0,0 +1,32 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_CORE_FRAMES_QUIC_IETF_BLOCKED_FRAME_H_ +#define NET_QUIC_CORE_FRAMES_QUIC_IETF_BLOCKED_FRAME_H_ + +#include <ostream> + +#include "net/quic/core/frames/quic_control_frame.h" + +namespace net { + +// IETF format BLOCKED frame. +// The sender uses the BLOCKED frame to inform the receiver that the +// sender is unable to send data because of connection-level flow control. +struct QUIC_EXPORT_PRIVATE QuicIetfBlockedFrame : public QuicControlFrame { + QuicIetfBlockedFrame(); + QuicIetfBlockedFrame(QuicControlFrameId control_frame_id, + QuicStreamOffset offset); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicIetfBlockedFrame& frame); + + // Offset at which the BLOCKED applies + QuicStreamOffset offset; +}; + +} // namespace net + +#endif // NET_QUIC_CORE_FRAMES_QUIC_IETF_BLOCKED_FRAME_H_ diff --git a/chromium/net/quic/core/frames/quic_ietf_max_stream_id_frame.cc b/chromium/net/quic/core/frames/quic_ietf_max_stream_id_frame.cc new file mode 100644 index 00000000000..bd7ef723593 --- /dev/null +++ b/chromium/net/quic/core/frames/quic_ietf_max_stream_id_frame.cc @@ -0,0 +1,23 @@ +// Copyright (c) 2016 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/core/frames/quic_ietf_max_stream_id_frame.h" + +namespace net { + +QuicIetfMaxStreamIdFrame::QuicIetfMaxStreamIdFrame() {} + +QuicIetfMaxStreamIdFrame::QuicIetfMaxStreamIdFrame( + QuicControlFrameId control_frame_id, + QuicStreamId max_stream_id) + : QuicControlFrame(control_frame_id), max_stream_id(max_stream_id) {} + +std::ostream& operator<<(std::ostream& os, + const QuicIetfMaxStreamIdFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", stream_id: " << frame.max_stream_id << " }\n"; + return os; +} + +} // namespace net diff --git a/chromium/net/quic/core/frames/quic_ietf_max_stream_id_frame.h b/chromium/net/quic/core/frames/quic_ietf_max_stream_id_frame.h new file mode 100644 index 00000000000..bfb1a97364c --- /dev/null +++ b/chromium/net/quic/core/frames/quic_ietf_max_stream_id_frame.h @@ -0,0 +1,32 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_CORE_FRAMES_QUIC_IETF_MAX_STREAM_ID_FRAME_H_ +#define NET_QUIC_CORE_FRAMES_QUIC_IETF_MAX_STREAM_ID_FRAME_H_ + +#include <ostream> + +#include "net/quic/core/frames/quic_control_frame.h" + +namespace net { + +// IETF format max-stream id frame. +// This frame is used by the sender to inform the peer of the largest +// stream id that the peer may open and that the sender will accept. +struct QUIC_EXPORT_PRIVATE QuicIetfMaxStreamIdFrame : public QuicControlFrame { + QuicIetfMaxStreamIdFrame(); + QuicIetfMaxStreamIdFrame(QuicControlFrameId control_frame_id, + QuicStreamId max_stream_id); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicIetfMaxStreamIdFrame& frame); + + // The maximum stream id to support. + QuicStreamId max_stream_id; +}; + +} // namespace net + +#endif // NET_QUIC_CORE_FRAMES_QUIC_IETF_MAX_STREAM_ID_FRAME_H_ diff --git a/chromium/net/quic/core/frames/quic_ietf_stream_id_blocked_frame.cc b/chromium/net/quic/core/frames/quic_ietf_stream_id_blocked_frame.cc new file mode 100644 index 00000000000..7cbc06ef85c --- /dev/null +++ b/chromium/net/quic/core/frames/quic_ietf_stream_id_blocked_frame.cc @@ -0,0 +1,23 @@ +// Copyright (c) 2016 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/core/frames/quic_ietf_stream_id_blocked_frame.h" + +namespace net { + +QuicIetfStreamIdBlockedFrame::QuicIetfStreamIdBlockedFrame() {} + +QuicIetfStreamIdBlockedFrame::QuicIetfStreamIdBlockedFrame( + QuicControlFrameId control_frame_id, + QuicStreamId stream_id) + : QuicControlFrame(control_frame_id), stream_id(stream_id) {} + +std::ostream& operator<<(std::ostream& os, + const QuicIetfStreamIdBlockedFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", stream id: " << frame.stream_id << " }\n"; + return os; +} + +} // namespace net diff --git a/chromium/net/quic/core/frames/quic_ietf_stream_id_blocked_frame.h b/chromium/net/quic/core/frames/quic_ietf_stream_id_blocked_frame.h new file mode 100644 index 00000000000..91ad6f0eb7d --- /dev/null +++ b/chromium/net/quic/core/frames/quic_ietf_stream_id_blocked_frame.h @@ -0,0 +1,33 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_CORE_FRAMES_QUIC_IETF_STREAM_ID_BLOCKED_FRAME_H_ +#define NET_QUIC_CORE_FRAMES_QUIC_IETF_STREAM_ID_BLOCKED_FRAME_H_ + +#include <ostream> + +#include "net/quic/core/frames/quic_control_frame.h" + +namespace net { + +// IETF format STREAM ID BLOCKED frame. +// The sender uses this to inform the peer that the sender wished to +// open a new stream but was blocked from doing so due due to the +// maximum stream ID limit set by the peer (via a MAX_STREAM_ID frame) +struct QUIC_EXPORT_PRIVATE QuicIetfStreamIdBlockedFrame + : public QuicControlFrame { + QuicIetfStreamIdBlockedFrame(); + QuicIetfStreamIdBlockedFrame(QuicControlFrameId control_frame_id, + QuicStreamId stream_id); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicIetfStreamIdBlockedFrame& frame); + + QuicStreamId stream_id; +}; + +} // namespace net + +#endif // NET_QUIC_CORE_FRAMES_QUIC_IETF_STREAM_ID_BLOCKED_FRAME_H_ diff --git a/chromium/net/quic/core/frames/quic_path_challenge_frame.cc b/chromium/net/quic/core/frames/quic_path_challenge_frame.cc new file mode 100644 index 00000000000..a7463e5b4ba --- /dev/null +++ b/chromium/net/quic/core/frames/quic_path_challenge_frame.cc @@ -0,0 +1,35 @@ +// Copyright (c) 2018 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/core/frames/quic_path_challenge_frame.h" +#include "net/quic/platform/api/quic_bug_tracker.h" + +namespace net { + +QuicPathChallengeFrame::QuicPathChallengeFrame() : QuicControlFrame(0) {} + +QuicPathChallengeFrame::QuicPathChallengeFrame( + QuicControlFrameId control_frame_id, + const QuicPathFrameBuffer& data_buff) + : QuicControlFrame(control_frame_id) { + memcpy(data_buffer.data(), data_buff.data(), data_buffer.size()); +} + +QuicPathChallengeFrame::~QuicPathChallengeFrame() {} + +std::ostream& operator<<(std::ostream& os, + const QuicPathChallengeFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", data: " << static_cast<unsigned>(frame.data_buffer[0]) << " " + << static_cast<unsigned>(frame.data_buffer[1]) << " " + << static_cast<unsigned>(frame.data_buffer[2]) << " " + << static_cast<unsigned>(frame.data_buffer[3]) << " " + << static_cast<unsigned>(frame.data_buffer[4]) << " " + << static_cast<unsigned>(frame.data_buffer[5]) << " " + << static_cast<unsigned>(frame.data_buffer[6]) << " " + << static_cast<unsigned>(frame.data_buffer[7]) << " }\n"; + return os; +} + +} // namespace net diff --git a/chromium/net/quic/core/frames/quic_path_challenge_frame.h b/chromium/net/quic/core/frames/quic_path_challenge_frame.h new file mode 100644 index 00000000000..3fabb7b58a9 --- /dev/null +++ b/chromium/net/quic/core/frames/quic_path_challenge_frame.h @@ -0,0 +1,37 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_CORE_FRAMES_QUIC_PATH_CHALLENGE_FRAME_H_ +#define NET_QUIC_CORE_FRAMES_QUIC_PATH_CHALLENGE_FRAME_H_ + +#include <memory> +#include <ostream> + +#include "net/quic/core/frames/quic_control_frame.h" +#include "net/quic/core/quic_types.h" + +namespace net { + +// Size of the entire IETF Quic Path Challenge frame, including +// type byte. +const size_t kQuicPathChallengeFrameSize = (kQuicPathFrameBufferSize + 1); + +struct QUIC_EXPORT_PRIVATE QuicPathChallengeFrame : public QuicControlFrame { + QuicPathChallengeFrame(); + QuicPathChallengeFrame(QuicControlFrameId control_frame_id, + const QuicPathFrameBuffer& data_buff); + ~QuicPathChallengeFrame(); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicPathChallengeFrame& frame); + + QuicPathFrameBuffer data_buffer; + + private: + DISALLOW_COPY_AND_ASSIGN(QuicPathChallengeFrame); +}; +} // namespace net + +#endif // NET_QUIC_CORE_FRAMES_QUIC_PATH_CHALLENGE_FRAME_H_ diff --git a/chromium/net/quic/core/frames/quic_path_response_frame.cc b/chromium/net/quic/core/frames/quic_path_response_frame.cc new file mode 100644 index 00000000000..2d0068a7354 --- /dev/null +++ b/chromium/net/quic/core/frames/quic_path_response_frame.cc @@ -0,0 +1,34 @@ +// Copyright (c) 2018 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/core/frames/quic_path_response_frame.h" +#include "net/quic/platform/api/quic_bug_tracker.h" + +namespace net { + +QuicPathResponseFrame::QuicPathResponseFrame() : QuicControlFrame(0) {} + +QuicPathResponseFrame::QuicPathResponseFrame( + QuicControlFrameId control_frame_id, + const QuicPathFrameBuffer& data_buff) + : QuicControlFrame(control_frame_id) { + memcpy(data_buffer.data(), data_buff.data(), data_buffer.size()); +} + +QuicPathResponseFrame::~QuicPathResponseFrame() {} + +std::ostream& operator<<(std::ostream& os, const QuicPathResponseFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", data: " << static_cast<unsigned>(frame.data_buffer[0]) << " " + << static_cast<unsigned>(frame.data_buffer[1]) << " " + << static_cast<unsigned>(frame.data_buffer[2]) << " " + << static_cast<unsigned>(frame.data_buffer[3]) << " " + << static_cast<unsigned>(frame.data_buffer[4]) << " " + << static_cast<unsigned>(frame.data_buffer[5]) << " " + << static_cast<unsigned>(frame.data_buffer[6]) << " " + << static_cast<unsigned>(frame.data_buffer[7]) << " }\n"; + return os; +} + +} // namespace net diff --git a/chromium/net/quic/core/frames/quic_path_response_frame.h b/chromium/net/quic/core/frames/quic_path_response_frame.h new file mode 100644 index 00000000000..c56dc6779d2 --- /dev/null +++ b/chromium/net/quic/core/frames/quic_path_response_frame.h @@ -0,0 +1,37 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_CORE_FRAMES_QUIC_PATH_RESPONSE_FRAME_H_ +#define NET_QUIC_CORE_FRAMES_QUIC_PATH_RESPONSE_FRAME_H_ + +#include <memory> +#include <ostream> + +#include "net/quic/core/frames/quic_control_frame.h" +#include "net/quic/core/quic_types.h" + +namespace net { + +// Size of the entire IETF Quic Path Response frame, including +// type byte. +const size_t kQuicPathResponseFrameSize = (kQuicPathFrameBufferSize + 1); + +struct QUIC_EXPORT_PRIVATE QuicPathResponseFrame : public QuicControlFrame { + QuicPathResponseFrame(); + QuicPathResponseFrame(QuicControlFrameId control_frame_id, + const QuicPathFrameBuffer& data_buff); + ~QuicPathResponseFrame(); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicPathResponseFrame& frame); + + QuicPathFrameBuffer data_buffer; + + private: + DISALLOW_COPY_AND_ASSIGN(QuicPathResponseFrame); +}; +} // namespace net + +#endif // NET_QUIC_CORE_FRAMES_QUIC_PATH_RESPONSE_FRAME_H_ diff --git a/chromium/net/quic/core/frames/quic_stop_sending_frame.cc b/chromium/net/quic/core/frames/quic_stop_sending_frame.cc new file mode 100644 index 00000000000..203baeb6076 --- /dev/null +++ b/chromium/net/quic/core/frames/quic_stop_sending_frame.cc @@ -0,0 +1,27 @@ +// Copyright (c) 2018 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/core/frames/quic_stop_sending_frame.h" + +namespace net { + +QuicStopSendingFrame::QuicStopSendingFrame() + : stream_id(0), application_error_code(0) {} + +QuicStopSendingFrame::QuicStopSendingFrame( + QuicControlFrameId control_frame_id, + QuicStreamId stream_id, + QuicApplicationErrorCode application_error_code) + : QuicControlFrame(control_frame_id), + stream_id(stream_id), + application_error_code(application_error_code) {} + +std::ostream& operator<<(std::ostream& os, const QuicStopSendingFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", stream_id: " << frame.stream_id + << ", application_error_code: " << frame.application_error_code << " }\n"; + return os; +} + +} // namespace net diff --git a/chromium/net/quic/core/frames/quic_stop_sending_frame.h b/chromium/net/quic/core/frames/quic_stop_sending_frame.h new file mode 100644 index 00000000000..0cc2c55192e --- /dev/null +++ b/chromium/net/quic/core/frames/quic_stop_sending_frame.h @@ -0,0 +1,31 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_CORE_FRAMES_QUIC_STOP_SENDING_FRAME_H_ +#define NET_QUIC_CORE_FRAMES_QUIC_STOP_SENDING_FRAME_H_ + +#include <ostream> + +#include "net/quic/core/frames/quic_control_frame.h" +#include "net/quic/core/quic_error_codes.h" + +namespace net { + +struct QUIC_EXPORT_PRIVATE QuicStopSendingFrame : public QuicControlFrame { + QuicStopSendingFrame(); + QuicStopSendingFrame(QuicControlFrameId control_frame_id, + QuicStreamId stream_id, + uint16_t application_error_code); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicStopSendingFrame& frame); + + QuicStreamId stream_id; + QuicApplicationErrorCode application_error_code; +}; + +} // namespace net + +#endif // NET_QUIC_CORE_FRAMES_QUIC_STOP_SENDING_FRAME_H_ diff --git a/chromium/net/quic/core/frames/quic_window_update_frame.h b/chromium/net/quic/core/frames/quic_window_update_frame.h index e94496658e7..fa2f973e66f 100644 --- a/chromium/net/quic/core/frames/quic_window_update_frame.h +++ b/chromium/net/quic/core/frames/quic_window_update_frame.h @@ -32,6 +32,10 @@ struct QUIC_EXPORT_PRIVATE QuicWindowUpdateFrame : public QuicControlFrame { // Byte offset in the stream or connection. The receiver of this frame must // not send data which would result in this offset being exceeded. + // + // TODO(fkastenholz): Rename this to max_data and change the type to + // QuicByteCount because the IETF defines this as the "maximum + // amount of data that can be sent". QuicStreamOffset byte_offset; }; diff --git a/chromium/net/quic/core/quic_buffered_packet_store.cc b/chromium/net/quic/core/quic_buffered_packet_store.cc index 8dc6dd069cb..40429da6ec3 100644 --- a/chromium/net/quic/core/quic_buffered_packet_store.cc +++ b/chromium/net/quic/core/quic_buffered_packet_store.cc @@ -54,7 +54,8 @@ BufferedPacket& BufferedPacket::operator=(BufferedPacket&& other) = default; BufferedPacket::~BufferedPacket() {} -BufferedPacketList::BufferedPacketList() : creation_time(QuicTime::Zero()) {} +BufferedPacketList::BufferedPacketList() + : creation_time(QuicTime::Zero()), ietf_quic(false) {} BufferedPacketList::BufferedPacketList(BufferedPacketList&& other) = default; @@ -78,6 +79,7 @@ QuicBufferedPacketStore::~QuicBufferedPacketStore() {} EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket( QuicConnectionId connection_id, + bool ietf_quic, const QuicReceivedPacket& packet, QuicSocketAddress server_address, QuicSocketAddress client_address, @@ -98,6 +100,7 @@ EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket( } else if (!QuicContainsKey(undecryptable_packets_, connection_id)) { undecryptable_packets_.emplace( std::make_pair(connection_id, BufferedPacketList())); + undecryptable_packets_.back().second.ietf_quic = ietf_quic; } CHECK(QuicContainsKey(undecryptable_packets_, connection_id)); BufferedPacketList& queue = diff --git a/chromium/net/quic/core/quic_buffered_packet_store.h b/chromium/net/quic/core/quic_buffered_packet_store.h index 42e22feebda..b2271640cee 100644 --- a/chromium/net/quic/core/quic_buffered_packet_store.h +++ b/chromium/net/quic/core/quic_buffered_packet_store.h @@ -69,6 +69,8 @@ class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore { QuicTime creation_time; // The alpn from the CHLO, if one was found. QuicString alpn; + // Indicating whether this is an IETF QUIC connection. + bool ietf_quic; }; typedef QuicLinkedHashMap<QuicConnectionId, BufferedPacketList> @@ -95,6 +97,7 @@ class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore { // Adds a copy of packet into packet queue for given connection. EnqueuePacketResult EnqueuePacket(QuicConnectionId connection_id, + bool ietf_quic, const QuicReceivedPacket& packet, QuicSocketAddress server_address, QuicSocketAddress client_address, diff --git a/chromium/net/quic/core/quic_buffered_packet_store_test.cc b/chromium/net/quic/core/quic_buffered_packet_store_test.cc index f7dc69dbb14..aaa29ce2b19 100644 --- a/chromium/net/quic/core/quic_buffered_packet_store_test.cc +++ b/chromium/net/quic/core/quic_buffered_packet_store_test.cc @@ -69,8 +69,8 @@ class QuicBufferedPacketStoreTest : public QuicTest { TEST_F(QuicBufferedPacketStoreTest, SimpleEnqueueAndDeliverPacket) { QuicConnectionId connection_id = 1; - store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_, - false, ""); + store_.EnqueuePacket(connection_id, false, packet_, server_address_, + client_address_, false, ""); EXPECT_TRUE(store_.HasBufferedPackets(connection_id)); auto packets = store_.DeliverPackets(connection_id); const std::list<BufferedPacket>& queue = packets.buffered_packets; @@ -90,9 +90,9 @@ TEST_F(QuicBufferedPacketStoreTest, SimpleEnqueueAndDeliverPacket) { TEST_F(QuicBufferedPacketStoreTest, DifferentPacketAddressOnOneConnection) { QuicSocketAddress addr_with_new_port(QuicIpAddress::Any4(), 256); QuicConnectionId connection_id = 1; - store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_, - false, ""); - store_.EnqueuePacket(connection_id, packet_, server_address_, + store_.EnqueuePacket(connection_id, false, packet_, server_address_, + client_address_, false, ""); + store_.EnqueuePacket(connection_id, false, packet_, server_address_, addr_with_new_port, false, ""); std::list<BufferedPacket> queue = store_.DeliverPackets(connection_id).buffered_packets; @@ -107,9 +107,9 @@ TEST_F(QuicBufferedPacketStoreTest, size_t num_connections = 10; for (QuicConnectionId connection_id = 1; connection_id <= num_connections; ++connection_id) { - store_.EnqueuePacket(connection_id, packet_, server_address_, + store_.EnqueuePacket(connection_id, false, packet_, server_address_, client_address_, false, ""); - store_.EnqueuePacket(connection_id, packet_, server_address_, + store_.EnqueuePacket(connection_id, false, packet_, server_address_, client_address_, false, ""); } @@ -131,12 +131,13 @@ TEST_F(QuicBufferedPacketStoreTest, // Arrived CHLO packet shouldn't affect how many non-CHLO pacekts store can // keep. EXPECT_EQ(QuicBufferedPacketStore::SUCCESS, - store_.EnqueuePacket(connection_id, packet_, server_address_, + store_.EnqueuePacket(connection_id, false, packet_, server_address_, client_address_, true, "")); for (size_t i = 1; i <= num_packets; ++i) { // Only first |kDefaultMaxUndecryptablePackets packets| will be buffered. - EnqueuePacketResult result = store_.EnqueuePacket( - connection_id, packet_, server_address_, client_address_, false, ""); + EnqueuePacketResult result = + store_.EnqueuePacket(connection_id, false, packet_, server_address_, + client_address_, false, ""); if (i <= kDefaultMaxUndecryptablePackets) { EXPECT_EQ(EnqueuePacketResult::SUCCESS, result); } else { @@ -156,8 +157,9 @@ TEST_F(QuicBufferedPacketStoreTest, ReachNonChloConnectionUpperLimit) { const size_t kNumConnections = kMaxConnectionsWithoutCHLO + 1; for (size_t connection_id = 1; connection_id <= kNumConnections; ++connection_id) { - EnqueuePacketResult result = store_.EnqueuePacket( - connection_id, packet_, server_address_, client_address_, false, ""); + EnqueuePacketResult result = + store_.EnqueuePacket(connection_id, false, packet_, server_address_, + client_address_, false, ""); if (connection_id <= kMaxConnectionsWithoutCHLO) { EXPECT_EQ(EnqueuePacketResult::SUCCESS, result); } else { @@ -185,8 +187,8 @@ TEST_F(QuicBufferedPacketStoreTest, kDefaultMaxConnectionsInStore - kMaxConnectionsWithoutCHLO + 1; for (size_t connection_id = 1; connection_id <= num_chlos; ++connection_id) { EXPECT_EQ(EnqueuePacketResult::SUCCESS, - store_.EnqueuePacket(connection_id, packet_, server_address_, - client_address_, true, "")); + store_.EnqueuePacket(connection_id, false, packet_, + server_address_, client_address_, true, "")); } // Send data packets on another |kMaxConnectionsWithoutCHLO| connections. @@ -194,7 +196,7 @@ TEST_F(QuicBufferedPacketStoreTest, for (size_t conn_id = num_chlos + 1; conn_id <= (kDefaultMaxConnectionsInStore + 1); ++conn_id) { EnqueuePacketResult result = store_.EnqueuePacket( - conn_id, packet_, server_address_, client_address_, true, ""); + conn_id, false, packet_, server_address_, client_address_, true, ""); if (conn_id <= kDefaultMaxConnectionsInStore) { EXPECT_EQ(EnqueuePacketResult::SUCCESS, result); } else { @@ -208,7 +210,7 @@ TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) { for (QuicConnectionId conn_id = 1; conn_id <= kMaxConnectionsWithoutCHLO; ++conn_id) { EXPECT_EQ(EnqueuePacketResult::SUCCESS, - store_.EnqueuePacket(conn_id, packet_, server_address_, + store_.EnqueuePacket(conn_id, false, packet_, server_address_, client_address_, false, "")); } @@ -216,8 +218,8 @@ TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) { for (size_t i = kMaxConnectionsWithoutCHLO + 1; i <= kDefaultMaxConnectionsInStore + 1; ++i) { EnqueuePacketResult rs = store_.EnqueuePacket( - /*connection_id=*/i, packet_, server_address_, client_address_, true, - ""); + /*connection_id=*/i, false, packet_, server_address_, client_address_, + true, ""); if (i <= kDefaultMaxConnectionsInStore) { EXPECT_EQ(EnqueuePacketResult::SUCCESS, rs); EXPECT_TRUE(store_.HasChloForConnection(/*connection_id=*/i)); @@ -232,8 +234,8 @@ TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) { // buffered in the store should success. This is the connection should be // delivered at last. EXPECT_EQ(EnqueuePacketResult::SUCCESS, - store_.EnqueuePacket(/*connection_id=*/1, packet_, server_address_, - client_address_, true, "")); + store_.EnqueuePacket(/*connection_id=*/1, false, packet_, + server_address_, client_address_, true, "")); EXPECT_TRUE(store_.HasChloForConnection(/*connection_id=*/1)); QuicConnectionId delivered_conn_id; @@ -258,15 +260,15 @@ TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) { // connections both with and without CHLOs. TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) { QuicConnectionId connection_id = 1; - store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_, - false, ""); + store_.EnqueuePacket(connection_id, false, packet_, server_address_, + client_address_, false, ""); EXPECT_EQ(EnqueuePacketResult::SUCCESS, - store_.EnqueuePacket(connection_id, packet_, server_address_, + store_.EnqueuePacket(connection_id, false, packet_, server_address_, client_address_, true, "")); QuicConnectionId connection_id2 = 2; EXPECT_EQ(EnqueuePacketResult::SUCCESS, - store_.EnqueuePacket(connection_id2, packet_, server_address_, - client_address_, false, "")); + store_.EnqueuePacket(connection_id2, false, packet_, + server_address_, client_address_, false, "")); // CHLO on connection 3 arrives 1ms later. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); @@ -274,7 +276,7 @@ TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) { // Use different client address to differetiate packets from different // connections. QuicSocketAddress another_client_address(QuicIpAddress::Any4(), 255); - store_.EnqueuePacket(connection_id3, packet_, server_address_, + store_.EnqueuePacket(connection_id3, false, packet_, server_address_, another_client_address, true, ""); // Advance clock to the time when connection 1 and 2 expires. @@ -306,9 +308,9 @@ TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) { // Test the alarm is reset by enqueueing 2 packets for 4th connection and wait // for them to expire. QuicConnectionId connection_id4 = 4; - store_.EnqueuePacket(connection_id4, packet_, server_address_, + store_.EnqueuePacket(connection_id4, false, packet_, server_address_, client_address_, false, ""); - store_.EnqueuePacket(connection_id4, packet_, server_address_, + store_.EnqueuePacket(connection_id4, false, packet_, server_address_, client_address_, false, ""); clock_.AdvanceTime( QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() - @@ -323,10 +325,10 @@ TEST_F(QuicBufferedPacketStoreTest, SimpleDiscardPackets) { QuicConnectionId connection_id = 1; // Enqueue some packets - store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_, - false, ""); - store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_, - false, ""); + store_.EnqueuePacket(connection_id, false, packet_, server_address_, + client_address_, false, ""); + store_.EnqueuePacket(connection_id, false, packet_, server_address_, + client_address_, false, ""); EXPECT_TRUE(store_.HasBufferedPackets(connection_id)); EXPECT_FALSE(store_.HasChlosBuffered()); @@ -349,12 +351,12 @@ TEST_F(QuicBufferedPacketStoreTest, DiscardWithCHLOs) { QuicConnectionId connection_id = 1; // Enqueue some packets, which include a CHLO - store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_, - false, ""); - store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_, - true, ""); - store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_, - false, ""); + store_.EnqueuePacket(connection_id, false, packet_, server_address_, + client_address_, false, ""); + store_.EnqueuePacket(connection_id, false, packet_, server_address_, + client_address_, true, ""); + store_.EnqueuePacket(connection_id, false, packet_, server_address_, + client_address_, false, ""); EXPECT_TRUE(store_.HasBufferedPackets(connection_id)); EXPECT_TRUE(store_.HasChlosBuffered()); @@ -378,11 +380,11 @@ TEST_F(QuicBufferedPacketStoreTest, MultipleDiscardPackets) { QuicConnectionId connection_id_2 = 2; // Enqueue some packets for two connection IDs - store_.EnqueuePacket(connection_id_1, packet_, server_address_, + store_.EnqueuePacket(connection_id_1, false, packet_, server_address_, client_address_, false, ""); - store_.EnqueuePacket(connection_id_1, packet_, server_address_, + store_.EnqueuePacket(connection_id_1, false, packet_, server_address_, client_address_, false, ""); - store_.EnqueuePacket(connection_id_2, packet_, server_address_, + store_.EnqueuePacket(connection_id_2, false, packet_, server_address_, client_address_, true, "h3"); EXPECT_TRUE(store_.HasBufferedPackets(connection_id_1)); EXPECT_TRUE(store_.HasBufferedPackets(connection_id_2)); diff --git a/chromium/net/quic/core/quic_client_promised_info_test.cc b/chromium/net/quic/core/quic_client_promised_info_test.cc index 54a4c919f16..3fae76e470c 100644 --- a/chromium/net/quic/core/quic_client_promised_info_test.cc +++ b/chromium/net/quic/core/quic_client_promised_info_test.cc @@ -138,14 +138,9 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseCleanupAlarm) { ASSERT_NE(promised, nullptr); // Fire the alarm that will cancel the promised stream. - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(promise_id_, QUIC_PUSH_STREAM_TIMED_OUT)); - } else { - EXPECT_CALL(*connection_, - SendRstStream(promise_id_, QUIC_PUSH_STREAM_TIMED_OUT, 0)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_PUSH_STREAM_TIMED_OUT)); alarm_factory_.FireAlarm(QuicClientPromisedInfoPeer::GetAlarm(promised)); // Verify that the promise is gone after the alarm fires. @@ -157,14 +152,9 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseInvalidMethod) { // Promise with an unsafe method push_promise_[":method"] = "PUT"; - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(promise_id_, QUIC_INVALID_PROMISE_METHOD)); - } else { - EXPECT_CALL(*connection_, - SendRstStream(promise_id_, QUIC_INVALID_PROMISE_METHOD, 0)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_INVALID_PROMISE_METHOD)); ReceivePromise(promise_id_); // Verify that the promise headers were ignored @@ -176,14 +166,9 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseMissingMethod) { // Promise with a missing method push_promise_.erase(":method"); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(promise_id_, QUIC_INVALID_PROMISE_METHOD)); - } else { - EXPECT_CALL(*connection_, - SendRstStream(promise_id_, QUIC_INVALID_PROMISE_METHOD, 0)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_INVALID_PROMISE_METHOD)); ReceivePromise(promise_id_); // Verify that the promise headers were ignored @@ -195,14 +180,9 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseInvalidUrl) { // Remove required header field to make URL invalid push_promise_.erase(":authority"); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(promise_id_, QUIC_INVALID_PROMISE_URL)); - } else { - EXPECT_CALL(*connection_, - SendRstStream(promise_id_, QUIC_INVALID_PROMISE_URL, 0)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_INVALID_PROMISE_URL)); ReceivePromise(promise_id_); // Verify that the promise headers were ignored @@ -213,14 +193,9 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseInvalidUrl) { TEST_F(QuicClientPromisedInfoTest, PushPromiseUnauthorizedUrl) { session_.set_authorized(false); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(promise_id_, QUIC_UNAUTHORIZED_PROMISE_URL)); - } else { - EXPECT_CALL(*connection_, - SendRstStream(promise_id_, QUIC_UNAUTHORIZED_PROMISE_URL, 0)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_UNAUTHORIZED_PROMISE_URL)); ReceivePromise(promise_id_); @@ -243,14 +218,9 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseMismatch) { headers); TestPushPromiseDelegate delegate(/*match=*/false); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(promise_id_, QUIC_PROMISE_VARY_MISMATCH)); - } else { - EXPECT_CALL(*connection_, - SendRstStream(promise_id_, QUIC_PROMISE_VARY_MISMATCH, 0)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_PROMISE_VARY_MISMATCH)); EXPECT_CALL(session_, CloseStream(promise_id_)); promised->HandleClientRequest(client_request_, &delegate); @@ -328,14 +298,8 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseWaitCancels) { // Cancel the promised stream. EXPECT_CALL(session_, CloseStream(promise_id_)); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(promise_id_, QUIC_STREAM_CANCELLED)); - } else { - EXPECT_CALL(*connection_, - SendRstStream(promise_id_, QUIC_STREAM_CANCELLED, 0)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(promise_id_, QUIC_STREAM_CANCELLED)); promised->Cancel(); // Promise is gone @@ -358,14 +322,9 @@ TEST_F(QuicClientPromisedInfoTest, PushPromiseDataClosed) { headers); EXPECT_CALL(session_, CloseStream(promise_id_)); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(promise_id_, QUIC_STREAM_PEER_GOING_AWAY)); - } else { - EXPECT_CALL(*connection_, - SendRstStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_STREAM_PEER_GOING_AWAY)); session_.SendRstStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0); // Now initiate rendezvous. diff --git a/chromium/net/quic/core/quic_config.cc b/chromium/net/quic/core/quic_config.cc index 4a3d18f810f..0a89a756ee6 100644 --- a/chromium/net/quic/core/quic_config.cc +++ b/chromium/net/quic/core/quic_config.cc @@ -17,7 +17,6 @@ #include "net/quic/platform/api/quic_string.h" #include "net/quic/platform/api/quic_string_piece.h" - namespace net { // Reads the value corresponding to |name_| from |msg| into |out|. If the @@ -190,13 +189,13 @@ bool QuicFixedUint128::HasSendValue() const { return has_send_value_; } -uint128 QuicFixedUint128::GetSendValue() const { +QuicUint128 QuicFixedUint128::GetSendValue() const { QUIC_BUG_IF(!has_send_value_) << "No send value to get for tag:" << QuicTagToString(tag_); return send_value_; } -void QuicFixedUint128::SetSendValue(uint128 value) { +void QuicFixedUint128::SetSendValue(QuicUint128 value) { has_send_value_ = true; send_value_ = value; } @@ -205,13 +204,13 @@ bool QuicFixedUint128::HasReceivedValue() const { return has_receive_value_; } -uint128 QuicFixedUint128::GetReceivedValue() const { +QuicUint128 QuicFixedUint128::GetReceivedValue() const { QUIC_BUG_IF(!has_receive_value_) << "No receive value to get for tag:" << QuicTagToString(tag_); return receive_value_; } -void QuicFixedUint128::SetReceivedValue(uint128 value) { +void QuicFixedUint128::SetReceivedValue(QuicUint128 value) { has_receive_value_ = true; receive_value_ = value; } @@ -399,7 +398,6 @@ QuicConfig::QuicConfig() initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL), initial_stream_flow_control_window_bytes_(kSFCW, PRESENCE_OPTIONAL), initial_session_flow_control_window_bytes_(kCFCW, PRESENCE_OPTIONAL), - socket_receive_buffer_(kSRBF, PRESENCE_OPTIONAL), connection_migration_disabled_(kNCMR, PRESENCE_OPTIONAL), alternate_server_address_(kASAD, PRESENCE_OPTIONAL), support_max_header_list_size_(kSMHL, PRESENCE_OPTIONAL), @@ -633,7 +631,8 @@ bool QuicConfig::SupportMaxHeaderListSize() const { return support_max_header_list_size_.HasReceivedValue(); } -void QuicConfig::SetStatelessResetTokenToSend(uint128 stateless_reset_token) { +void QuicConfig::SetStatelessResetTokenToSend( + QuicUint128 stateless_reset_token) { stateless_reset_token_.SetSendValue(stateless_reset_token); } @@ -641,7 +640,7 @@ bool QuicConfig::HasReceivedStatelessResetToken() const { return stateless_reset_token_.HasReceivedValue(); } -uint128 QuicConfig::ReceivedStatelessResetToken() const { +QuicUint128 QuicConfig::ReceivedStatelessResetToken() const { return stateless_reset_token_.GetReceivedValue(); } diff --git a/chromium/net/quic/core/quic_config.h b/chromium/net/quic/core/quic_config.h index 3f2be56636d..c421198f3f9 100644 --- a/chromium/net/quic/core/quic_config.h +++ b/chromium/net/quic/core/quic_config.h @@ -8,11 +8,11 @@ #include <cstddef> #include <cstdint> -#include "net/base/int128.h" #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_time.h" #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_string.h" +#include "net/quic/platform/api/quic_uint128.h" namespace net { @@ -155,15 +155,15 @@ class QUIC_EXPORT_PRIVATE QuicFixedUint128 : public QuicConfigValue { bool HasSendValue() const; - uint128 GetSendValue() const; + QuicUint128 GetSendValue() const; - void SetSendValue(uint128 value); + void SetSendValue(QuicUint128 value); bool HasReceivedValue() const; - uint128 GetReceivedValue() const; + QuicUint128 GetReceivedValue() const; - void SetReceivedValue(uint128 value); + void SetReceivedValue(QuicUint128 value); // If has_send_value is true, serialises |tag_| and |send_value_| to |out|. void ToHandshakeMessage(CryptoHandshakeMessage* out) const override; @@ -174,9 +174,9 @@ class QUIC_EXPORT_PRIVATE QuicFixedUint128 : public QuicConfigValue { QuicString* error_details) override; private: - uint128 send_value_; + QuicUint128 send_value_; bool has_send_value_; - uint128 receive_value_; + QuicUint128 receive_value_; bool has_receive_value_; }; @@ -393,11 +393,11 @@ class QUIC_EXPORT_PRIVATE QuicConfig { bool SupportMaxHeaderListSize() const; - void SetStatelessResetTokenToSend(uint128 stateless_reset_token); + void SetStatelessResetTokenToSend(QuicUint128 stateless_reset_token); bool HasReceivedStatelessResetToken() const; - uint128 ReceivedStatelessResetToken() const; + QuicUint128 ReceivedStatelessResetToken() const; bool negotiated() const; @@ -453,10 +453,6 @@ class QUIC_EXPORT_PRIVATE QuicConfig { // Initial session flow control receive window in bytes. QuicFixedUint32 initial_session_flow_control_window_bytes_; - // Socket receive buffer in bytes. - // TODO(ianswett): Deprecate once QUIC_VERSION_34 is deprecated. - QuicFixedUint32 socket_receive_buffer_; - // Whether tell peer not to attempt connection migration. QuicFixedUint32 connection_migration_disabled_; diff --git a/chromium/net/quic/core/quic_config_test.cc b/chromium/net/quic/core/quic_config_test.cc index 630f631d653..6b1f620e855 100644 --- a/chromium/net/quic/core/quic_config_test.cc +++ b/chromium/net/quic/core/quic_config_test.cc @@ -11,11 +11,11 @@ #include "net/quic/core/quic_utils.h" #include "net/quic/platform/api/quic_string.h" #include "net/quic/platform/api/quic_test.h" +#include "net/quic/platform/api/quic_uint128.h" #include "net/quic/test_tools/quic_config_peer.h" #include "net/quic/test_tools/quic_test_utils.h" #include "net/test/gtest_util.h" - namespace net { namespace test { namespace { @@ -107,7 +107,7 @@ TEST_F(QuicConfigTest, ProcessServerHello) { QuicIpAddress host; host.FromString("127.0.3.1"); const QuicSocketAddress kTestServerAddress = QuicSocketAddress(host, 1234); - const uint128 kTestResetToken = MakeUint128(0, 10111100001); + const QuicUint128 kTestResetToken = MakeQuicUint128(0, 10111100001); QuicConfig server_config; QuicTagVector cgst; cgst.push_back(kQBIC); diff --git a/chromium/net/quic/core/quic_connection.cc b/chromium/net/quic/core/quic_connection.cc index d7127b07efd..77ca7bd1eec 100644 --- a/chromium/net/quic/core/quic_connection.cc +++ b/chromium/net/quic/core/quic_connection.cc @@ -126,6 +126,19 @@ class SendAlarmDelegate : public QuicAlarm::Delegate { DISALLOW_COPY_AND_ASSIGN(SendAlarmDelegate); }; +class PathDegradingAlarmDelegate : public QuicAlarm::Delegate { + public: + explicit PathDegradingAlarmDelegate(QuicConnection* connection) + : connection_(connection) {} + + void OnAlarm() override { connection_->OnPathDegradingTimeout(); } + + private: + QuicConnection* connection_; + + DISALLOW_COPY_AND_ASSIGN(PathDegradingAlarmDelegate); +}; + class TimeoutAlarmDelegate : public QuicAlarm::Delegate { public: explicit TimeoutAlarmDelegate(QuicConnection* connection) @@ -165,6 +178,19 @@ class MtuDiscoveryAlarmDelegate : public QuicAlarm::Delegate { DISALLOW_COPY_AND_ASSIGN(MtuDiscoveryAlarmDelegate); }; +class RetransmittableOnWireAlarmDelegate : public QuicAlarm::Delegate { + public: + explicit RetransmittableOnWireAlarmDelegate(QuicConnection* connection) + : connection_(connection) {} + + void OnAlarm() override { connection_->OnPingTimeout(); } + + private: + QuicConnection* connection_; + + DISALLOW_COPY_AND_ASSIGN(RetransmittableOnWireAlarmDelegate); +}; + } // namespace #define ENDPOINT \ @@ -184,6 +210,7 @@ QuicConnection::QuicConnection( perspective), current_packet_content_(NO_FRAMES_RECEIVED), current_peer_migration_type_(NO_CHANGE), + current_effective_peer_migration_type_(NO_CHANGE), helper_(helper), alarm_factory_(alarm_factory), per_packet_options_(nullptr), @@ -194,8 +221,11 @@ QuicConnection::QuicConnection( random_generator_(helper->GetRandomGenerator()), connection_id_(connection_id), peer_address_(initial_peer_address), + direct_peer_address_(initial_peer_address), active_peer_migration_type_(NO_CHANGE), highest_packet_sent_before_peer_migration_(0), + active_effective_peer_migration_type_(NO_CHANGE), + highest_packet_sent_before_effective_peer_migration_(0), last_packet_decrypted_(false), last_size_(0), current_packet_data_(nullptr), @@ -225,6 +255,7 @@ QuicConnection::QuicConnection( pending_retransmission_alarm_(false), defer_send_in_response_to_packets_(false), ping_timeout_(QuicTime::Delta::FromSeconds(kPingTimeoutSecs)), + retransmittable_on_wire_timeout_(QuicTime::Delta::Infinite()), arena_(), ack_alarm_(alarm_factory_->CreateAlarm(arena_.New<AckAlarmDelegate>(this), &arena_)), @@ -246,6 +277,12 @@ QuicConnection::QuicConnection( mtu_discovery_alarm_(alarm_factory_->CreateAlarm( arena_.New<MtuDiscoveryAlarmDelegate>(this), &arena_)), + retransmittable_on_wire_alarm_(alarm_factory_->CreateAlarm( + arena_.New<RetransmittableOnWireAlarmDelegate>(this), + &arena_)), + path_degrading_alarm_(alarm_factory_->CreateAlarm( + arena_.New<PathDegradingAlarmDelegate>(this), + &arena_)), visitor_(nullptr), debug_visitor_(nullptr), packet_generator_(connection_id_, &framer_, random_generator_, this), @@ -273,9 +310,18 @@ QuicConnection::QuicConnection( consecutive_num_packets_with_no_retransmittable_frames_(0), fill_up_link_during_probing_(false), probing_retransmission_pending_(false), + stateless_reset_token_received_(false), + received_stateless_reset_token_(0), last_control_frame_id_(kInvalidControlFrameId), - use_control_frame_manager_( - GetQuicReloadableFlag(quic_use_control_frame_manager)) { + negotiate_version_early_( + GetQuicReloadableFlag(quic_server_early_version_negotiation)), + always_discard_packets_after_close_( + GetQuicReloadableFlag(quic_always_discard_packets_after_close)), + handle_write_results_for_connectivity_probe_(GetQuicReloadableFlag( + quic_handle_write_results_for_connectivity_probe)), + use_path_degrading_alarm_( + GetQuicReloadableFlag(quic_path_degrading_alarm)), + enable_server_proxy_(GetQuicReloadableFlag(quic_enable_server_proxy)) { QUIC_DLOG(INFO) << ENDPOINT << "Created connection with connection_id: " << connection_id << " and version: " @@ -372,6 +418,10 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { config.HasClientSentConnectionOption(kNSTP, perspective_)) { no_stop_waiting_frames_ = true; } + if (config.HasReceivedStatelessResetToken()) { + stateless_reset_token_received_ = true; + received_stateless_reset_token_ = config.ReceivedStatelessResetToken(); + } } void QuicConnection::OnSendConnectionState( @@ -468,7 +518,7 @@ bool QuicConnection::OnProtocolVersionMismatch( QUIC_BUG << ENDPOINT << error_details; TearDownLocalConnectionState(QUIC_INTERNAL_ERROR, error_details, ConnectionCloseSource::FROM_SELF); - RecordInternalErrorLocation(QUIC_CONNECTION_1); + RecordInternalErrorLocation(QUIC_CONNECTION_PROTOCOL_VERSION_MISMATCH); return false; } DCHECK_NE(version(), received_version); @@ -505,6 +555,7 @@ bool QuicConnection::OnProtocolVersionMismatch( const bool set_version_early = GetQuicReloadableFlag(quic_store_version_before_signalling); if (set_version_early) { + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_store_version_before_signalling); // Store the new version. framer_.set_version(received_version); } @@ -512,8 +563,7 @@ bool QuicConnection::OnProtocolVersionMismatch( version_negotiation_state_ = NEGOTIATED_VERSION; visitor_->OnSuccessfulVersionNegotiation(received_version); if (debug_visitor_ != nullptr) { - debug_visitor_->OnSuccessfulVersionNegotiation( - received_version.transport_version); + debug_visitor_->OnSuccessfulVersionNegotiation(received_version); } QUIC_DLOG(INFO) << ENDPOINT << "version negotiated " << ParsedQuicVersionToString(received_version); @@ -544,7 +594,7 @@ void QuicConnection::OnVersionNegotiationPacket( QUIC_BUG << error_details; TearDownLocalConnectionState(QUIC_INTERNAL_ERROR, error_details, ConnectionCloseSource::FROM_SELF); - RecordInternalErrorLocation(QUIC_CONNECTION_2); + RecordInternalErrorLocation(QUIC_CONNECTION_VERSION_NEGOTIATION_PACKET); return; } if (debug_visitor_ != nullptr) { @@ -625,7 +675,7 @@ bool QuicConnection::OnUnauthenticatedHeader(const QuicPacketHeader& header) { QUIC_BUG << error_details; CloseConnection(QUIC_INTERNAL_ERROR, error_details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - RecordInternalErrorLocation(QUIC_CONNECTION_3); + RecordInternalErrorLocation(QUIC_CONNECTION_UNAUTHENTICATED_HEADER); return false; } @@ -641,6 +691,31 @@ bool QuicConnection::OnUnauthenticatedHeader(const QuicPacketHeader& header) { return false; } + if (negotiate_version_early_ && + version_negotiation_state_ != NEGOTIATED_VERSION && + perspective_ == Perspective::IS_SERVER) { + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_server_early_version_negotiation); + if (!header.version_flag) { + // Packets should have the version flag till version negotiation is + // done. + QuicString error_details = + QuicStrCat(ENDPOINT, "Packet ", header.packet_number, + " without version flag before version negotiated."); + QUIC_DLOG(WARNING) << error_details; + CloseConnection(QUIC_INVALID_VERSION, error_details, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; + } else { + DCHECK_EQ(header.version, version()); + version_negotiation_state_ = NEGOTIATED_VERSION; + visitor_->OnSuccessfulVersionNegotiation(version()); + if (debug_visitor_ != nullptr) { + debug_visitor_->OnSuccessfulVersionNegotiation(version()); + } + } + DCHECK_EQ(NEGOTIATED_VERSION, version_negotiation_state_); + } + return true; } @@ -656,6 +731,14 @@ void QuicConnection::OnDecryptedPacket(EncryptionLevel level) { } } +QuicSocketAddress QuicConnection::GetEffectivePeerAddressFromCurrentPacket() + const { + DCHECK(enable_server_proxy_); + // By default, the connection is not proxied, and the effective peer address + // is the packet's source address, i.e. the direct peer address. + return last_packet_source_address_; +} + bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { if (debug_visitor_ != nullptr) { debug_visitor_->OnPacketHeader(header); @@ -670,26 +753,68 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { // Initialize the current packet content stats. current_packet_content_ = NO_FRAMES_RECEIVED; - current_peer_migration_type_ = NO_CHANGE; - AddressChangeType peer_migration_type = QuicUtils::DetermineAddressChangeType( - peer_address_, last_packet_source_address_); - - // Initiate connection migration if a non-reordered packet is received from a - // new address. - if (header.packet_number > received_packet_manager_.GetLargestObserved() && - peer_migration_type != NO_CHANGE) { - QUIC_DLOG(INFO) << ENDPOINT << "Peer's ip:port changed from " - << peer_address_.ToString() << " to " - << last_packet_source_address_.ToString(); - if (perspective_ == Perspective::IS_CLIENT) { - peer_address_ = last_packet_source_address_; - } else if (active_peer_migration_type_ == NO_CHANGE) { - // Only migrate connection to a new peer address if there is no - // pending change underway. - // Cache the current migration change type, which will start peer - // migration immediately if this packet is not a connectivity probing - // packet. - current_peer_migration_type_ = peer_migration_type; + is_current_packet_connectivity_probing_ = false; + + if (!enable_server_proxy_) { + current_peer_migration_type_ = NO_CHANGE; + + AddressChangeType peer_migration_type = + QuicUtils::DetermineAddressChangeType(peer_address_, + last_packet_source_address_); + // Initiate connection migration if a non-reordered packet is received from + // a new address. + if (header.packet_number > received_packet_manager_.GetLargestObserved() && + peer_migration_type != NO_CHANGE) { + QUIC_DLOG(INFO) << ENDPOINT << "Peer's ip:port changed from " + << peer_address_.ToString() << " to " + << last_packet_source_address_.ToString(); + if (perspective_ == Perspective::IS_CLIENT) { + peer_address_ = last_packet_source_address_; + } else if (active_peer_migration_type_ == NO_CHANGE) { + // Only migrate connection to a new peer address if there is no + // pending change underway. + // Cache the current migration change type, which will start peer + // migration immediately if this packet is not a connectivity probing + // packet. + current_peer_migration_type_ = peer_migration_type; + } + } + } else { + current_effective_peer_migration_type_ = NO_CHANGE; + // Initiate connection migration if a non-reordered packet is received from + // a new address. + if (header.packet_number > received_packet_manager_.GetLargestObserved()) { + if (perspective_ == Perspective::IS_CLIENT) { + // Update peer_address_ and effective_peer_address_ immediately for + // client connections. + direct_peer_address_ = last_packet_source_address_; + effective_peer_address_ = GetEffectivePeerAddressFromCurrentPacket(); + } else { + // At server, direct_peer_address_ and effective_peer_address_ will be + // updated once the current packet is confirmed to be not a connectivity + // probing packet. + AddressChangeType effective_peer_migration_type = + QuicUtils::DetermineAddressChangeType( + effective_peer_address_, + GetEffectivePeerAddressFromCurrentPacket()); + + if (effective_peer_migration_type != NO_CHANGE) { + QUIC_DLOG(INFO) + << ENDPOINT << "Effective peer's ip:port changed from " + << effective_peer_address_.ToString() << " to " + << GetEffectivePeerAddressFromCurrentPacket().ToString() + << ", active_effective_peer_migration_type is " + << active_effective_peer_migration_type_; + if (active_effective_peer_migration_type_ == NO_CHANGE) { + // Only migrate connection to a new effective peer address if there + // is no pending change underway. Cache the current migration change + // type, which will start effective peer migration immediately if + // this packet is not a connectivity probing packet. + current_effective_peer_migration_type_ = + effective_peer_migration_type; + } + } + } } } @@ -772,9 +897,14 @@ bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) { if (send_alarm_->IsSet()) { send_alarm_->Cancel(); } + + if (LargestAcked(incoming_ack) > sent_packet_manager_.GetLargestObserved()) { + visitor_->OnForwardProgressConfirmed(); + } + largest_seen_packet_with_ack_ = last_header_.packet_number; - sent_packet_manager_.OnIncomingAck(incoming_ack, - time_of_last_received_packet_); + bool acked_new_packet = sent_packet_manager_.OnIncomingAck( + incoming_ack, time_of_last_received_packet_); // If the incoming ack's packets set expresses missing packets: peer is still // waiting for a packet lower than a packet that we are no longer planning to // send. @@ -782,7 +912,8 @@ bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) { // acking packets which we never care about. // Send an ack to raise the high water mark. PostProcessAfterAckFrame(!incoming_ack.packets.Empty() && - GetLeastUnacked() > incoming_ack.packets.Min()); + GetLeastUnacked() > incoming_ack.packets.Min(), + acked_new_packet); return connected_; } @@ -814,7 +945,9 @@ bool QuicConnection::OnAckFrameStart(QuicPacketNumber largest_acked, return false; } - if (largest_acked < sent_packet_manager_.GetLargestObserved()) { + if (largest_acked > sent_packet_manager_.GetLargestObserved()) { + visitor_->OnForwardProgressConfirmed(); + } else if (largest_acked < sent_packet_manager_.GetLargestObserved()) { QUIC_LOG(INFO) << ENDPOINT << "Peer's largest_observed packet decreased:" << largest_acked << " vs " << sent_packet_manager_.GetLargestObserved() @@ -828,7 +961,8 @@ bool QuicConnection::OnAckFrameStart(QuicPacketNumber largest_acked, return false; } - sent_packet_manager_.OnAckFrameStart(largest_acked, ack_delay_time); + sent_packet_manager_.OnAckFrameStart(largest_acked, ack_delay_time, + time_of_last_received_packet_); return true; } @@ -845,11 +979,12 @@ bool QuicConnection::OnAckRange(QuicPacketNumber start, return true; } - sent_packet_manager_.OnAckRange(start, end, last_range, - time_of_last_received_packet_); + sent_packet_manager_.OnAckRange(start, end); if (!last_range) { return true; } + bool acked_new_packet = + sent_packet_manager_.OnAckFrameEnd(time_of_last_received_packet_); if (send_alarm_->IsSet()) { send_alarm_->Cancel(); } @@ -860,7 +995,7 @@ bool QuicConnection::OnAckRange(QuicPacketNumber start, // If the incoming ack's packets set expresses received packets: peer is still // acking packets which we never care about. // Send an ack to raise the high water mark. - PostProcessAfterAckFrame(GetLeastUnacked() > start); + PostProcessAfterAckFrame(GetLeastUnacked() > start, acked_new_packet); return connected_; } @@ -1109,10 +1244,27 @@ void QuicConnection::OnPacketComplete() { << last_packet_destination_address_.ToString(); visitor_->OnConnectivityProbeReceived(last_packet_destination_address_, last_packet_source_address_); - } else if (current_peer_migration_type_ != NO_CHANGE) { - StartPeerMigration(current_peer_migration_type_); + } else { + if (!enable_server_proxy_) { + if (current_peer_migration_type_ != NO_CHANGE) { + StartPeerMigration(current_peer_migration_type_); + } + } else { + if (last_header_.packet_number == + received_packet_manager_.GetLargestObserved()) { + direct_peer_address_ = last_packet_source_address_; + } + if (current_effective_peer_migration_type_ != NO_CHANGE) { + StartEffectivePeerMigration(current_effective_peer_migration_type_); + } + } + } + + if (!enable_server_proxy_) { + current_peer_migration_type_ = NO_CHANGE; + } else { + current_effective_peer_migration_type_ = NO_CHANGE; } - current_peer_migration_type_ = NO_CHANGE; // An ack will be sent if a missing retransmittable packet was received; const bool was_missing = @@ -1128,6 +1280,20 @@ void QuicConnection::OnPacketComplete() { CloseIfTooManyOutstandingSentPackets(); } +bool QuicConnection::IsValidStatelessResetToken(uint128 token) const { + return stateless_reset_token_received_ && + token == received_stateless_reset_token_; +} + +void QuicConnection::OnAuthenticatedIetfStatelessResetPacket( + const QuicIetfStatelessResetPacket& packet) { + // TODO(fayang): Add OnAuthenticatedIetfStatelessResetPacket to + // debug_visitor_. + const std::string error_details = "Received stateless reset."; + TearDownLocalConnectionState(QUIC_PUBLIC_RESET, error_details, + ConnectionCloseSource::FROM_PEER); +} + void QuicConnection::MaybeQueueAck(bool was_missing) { ++num_packets_received_since_last_ack_sent_; // Always send an ack every 20 packets in order to allow the peer to discard @@ -1202,11 +1368,6 @@ void QuicConnection::ClearLastFrames() { } void QuicConnection::CloseIfTooManyOutstandingSentPackets() { - if (!GetQuicReloadableFlag( - quic_close_session_on_too_many_outstanding_sent_packets)) { - return; - } - // This occurs if we don't discard old packets we've seen fast enough. It's // possible largest observed is less than leaset unacked. if (sent_packet_manager_.GetLargestObserved() > @@ -1253,15 +1414,15 @@ void QuicConnection::SendVersionNegotiationPacket() { QUIC_DLOG(INFO) << ENDPOINT << "Sending version negotiation packet: {" << ParsedQuicVersionVectorToString( framer_.supported_versions()) - << "}"; + << "}, ietf_quic: " << framer_.last_packet_is_ietf_quic(); std::unique_ptr<QuicEncryptedPacket> version_packet( packet_generator_.SerializeVersionNegotiationPacket( - framer_.supported_versions())); + framer_.last_packet_is_ietf_quic(), framer_.supported_versions())); WriteResult result = writer_->WritePacket( version_packet->data(), version_packet->length(), self_address().host(), peer_address(), per_packet_options_); - if (result.status == WRITE_STATUS_ERROR) { + if (IsWriteError(result.status)) { OnWriteError(result.error_code); return; } @@ -1296,7 +1457,6 @@ QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id, } bool QuicConnection::SendControlFrame(const QuicFrame& frame) { - DCHECK(use_control_frame_manager_); if (!CanWrite(HAS_RETRANSMITTABLE_DATA) && frame.type != PING_FRAME) { QUIC_DVLOG(1) << ENDPOINT << "Failed to send control frame: " << frame; // Do not check congestion window for ping. @@ -1317,18 +1477,6 @@ bool QuicConnection::SendControlFrame(const QuicFrame& frame) { return true; } -void QuicConnection::SendRstStream(QuicStreamId id, - QuicRstStreamErrorCode error, - QuicStreamOffset bytes_written) { - DCHECK(!use_control_frame_manager_); - // Opportunistically bundle an ack with this outgoing packet. - ScopedPacketFlusher flusher(this, SEND_ACK_IF_PENDING); - packet_generator_.AddControlFrame(QuicFrame(new QuicRstStreamFrame( - ++last_control_frame_id_, id, error, bytes_written))); - - OnStreamReset(id, error); -} - void QuicConnection::OnStreamReset(QuicStreamId id, QuicRstStreamErrorCode error) { if (error == QUIC_STREAM_NO_ERROR) { @@ -1366,24 +1514,6 @@ void QuicConnection::OnStreamReset(QuicStreamId id, // cancelled as well. } -void QuicConnection::SendWindowUpdate(QuicStreamId id, - QuicStreamOffset byte_offset) { - DCHECK(!use_control_frame_manager_); - // Opportunistically bundle an ack with this outgoing packet. - ScopedPacketFlusher flusher(this, SEND_ACK_IF_PENDING); - packet_generator_.AddControlFrame(QuicFrame( - new QuicWindowUpdateFrame(++last_control_frame_id_, id, byte_offset))); -} - -void QuicConnection::SendBlocked(QuicStreamId id) { - DCHECK(!use_control_frame_manager_); - // Opportunistically bundle an ack with this outgoing packet. - ScopedPacketFlusher flusher(this, SEND_ACK_IF_PENDING); - packet_generator_.AddControlFrame( - QuicFrame(new QuicBlockedFrame(++last_control_frame_id_, id))); - stats_.blocked_frames_sent++; -} - const QuicConnectionStats& QuicConnection::GetStats() { const RttStats* rtt_stats = sent_packet_manager_.GetRttStats(); @@ -1421,14 +1551,34 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address, if (!self_address_.IsInitialized()) { self_address_ = last_packet_destination_address_; } - if (!peer_address_.IsInitialized()) { - peer_address_ = last_packet_source_address_; + + if (!enable_server_proxy_) { + if (!peer_address_.IsInitialized()) { + peer_address_ = last_packet_source_address_; + } + } else { + if (!direct_peer_address_.IsInitialized()) { + direct_peer_address_ = last_packet_source_address_; + } + + if (!effective_peer_address_.IsInitialized()) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_enable_server_proxy, 1, 3); + const QuicSocketAddress effective_peer_addr = + GetEffectivePeerAddressFromCurrentPacket(); + + // effective_peer_address_ must be initialized at the beginning of the + // first packet processed(here). If effective_peer_addr is uninitialized, + // just set effective_peer_address_ to the direct peer address. + effective_peer_address_ = effective_peer_addr.IsInitialized() + ? effective_peer_addr + : direct_peer_address_; + } } stats_.bytes_received += packet.length(); ++stats_.packets_received; - // Ensure the time coming from the packet reader is within a minute of now. + // Ensure the time coming from the packet reader is within 2 minutes of now. if (std::abs((packet.receipt_time() - clock_->ApproximateNow()).ToSeconds()) > 2 * 60) { QUIC_BUG << "Packet receipt time:" @@ -1460,11 +1610,26 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address, } ++stats_.packets_processed; - if (active_peer_migration_type_ != NO_CHANGE && - sent_packet_manager_.GetLargestObserved() > - highest_packet_sent_before_peer_migration_) { - if (perspective_ == Perspective::IS_SERVER) { - OnPeerMigrationValidated(); + if (!enable_server_proxy_) { + if (active_peer_migration_type_ != NO_CHANGE && + sent_packet_manager_.GetLargestObserved() > + highest_packet_sent_before_peer_migration_) { + if (perspective_ == Perspective::IS_SERVER) { + OnPeerMigrationValidated(); + } + } + } else { + QUIC_DLOG_IF(INFO, active_effective_peer_migration_type_ != NO_CHANGE) + << "sent_packet_manager_.GetLargestObserved() = " + << sent_packet_manager_.GetLargestObserved() + << ", highest_packet_sent_before_effective_peer_migration_ = " + << highest_packet_sent_before_effective_peer_migration_; + if (active_effective_peer_migration_type_ != NO_CHANGE && + sent_packet_manager_.GetLargestObserved() > + highest_packet_sent_before_effective_peer_migration_) { + if (perspective_ == Perspective::IS_SERVER) { + OnEffectivePeerMigrationValidated(); + } } } MaybeProcessUndecryptablePackets(); @@ -1480,6 +1645,14 @@ void QuicConnection::OnBlockedWriterCanWrite() { void QuicConnection::OnCanWrite() { DCHECK(!writer_->IsWriteBlocked()); + // TODO(wub): Deprecate this histogram once crbug.com/818040 is fixed. + if (!queued_packets_.empty() && + queued_packets_.front().packet_number < + sent_packet_manager_.GetLargestSentPacket()) { + UMA_HISTOGRAM_BOOLEAN( + "Net.QuicSession.WriteOutOfOrderQueuedPacketAfterClose", !connected_); + } + WriteQueuedPackets(); if (!session_decides_what_to_write()) { WritePendingRetransmissions(); @@ -1519,7 +1692,14 @@ void QuicConnection::WriteIfNotBlocked() { void QuicConnection::WriteAndBundleAcksIfNotBlocked() { if (!writer_->IsWriteBlocked()) { ScopedPacketFlusher flusher(this, SEND_ACK_IF_QUEUED); - OnCanWrite(); + if (GetQuicReloadableFlag(quic_is_write_blocked)) { + // TODO(ianswett): Merge OnCanWrite and WriteIfNotBlocked when deprecating + // this flag. + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_is_write_blocked); + WriteIfNotBlocked(); + } else { + OnCanWrite(); + } } } @@ -1592,7 +1772,17 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { } if (version_negotiation_state_ != NEGOTIATED_VERSION) { - if (perspective_ == Perspective::IS_SERVER) { + if (perspective_ == Perspective::IS_CLIENT) { + DCHECK(!header.version_flag); + // If the client gets a packet without the version flag from the server + // it should stop sending version since the version negotiation is done. + packet_generator_.StopSendingVersion(); + version_negotiation_state_ = NEGOTIATED_VERSION; + visitor_->OnSuccessfulVersionNegotiation(version()); + if (debug_visitor_ != nullptr) { + debug_visitor_->OnSuccessfulVersionNegotiation(version()); + } + } else if (!negotiate_version_early_) { if (!header.version_flag) { // Packets should have the version flag till version negotiation is // done. @@ -1608,24 +1798,12 @@ bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { version_negotiation_state_ = NEGOTIATED_VERSION; visitor_->OnSuccessfulVersionNegotiation(version()); if (debug_visitor_ != nullptr) { - debug_visitor_->OnSuccessfulVersionNegotiation(transport_version()); + debug_visitor_->OnSuccessfulVersionNegotiation(version()); } } - } else { - DCHECK(!header.version_flag); - // If the client gets a packet without the version flag from the server - // it should stop sending version since the version negotiation is done. - packet_generator_.StopSendingVersion(); - version_negotiation_state_ = NEGOTIATED_VERSION; - visitor_->OnSuccessfulVersionNegotiation(version()); - if (debug_visitor_ != nullptr) { - debug_visitor_->OnSuccessfulVersionNegotiation(transport_version()); - } } } - DCHECK_EQ(NEGOTIATED_VERSION, version_negotiation_state_); - if (last_size_ > largest_received_packet_size_) { largest_received_packet_size_ = last_size_; } @@ -1647,12 +1825,42 @@ void QuicConnection::WriteQueuedPackets() { UMA_HISTOGRAM_COUNTS_1000("Net.QuicSession.NumQueuedPacketsBeforeWrite", queued_packets_.size()); - QueuedPacketList::iterator packet_iterator = queued_packets_.begin(); - while (packet_iterator != queued_packets_.end() && - WritePacket(&(*packet_iterator))) { - delete[] packet_iterator->encrypted_buffer; - ClearSerializedPacket(&(*packet_iterator)); - packet_iterator = queued_packets_.erase(packet_iterator); + if (GetQuicReloadableFlag(quic_fix_write_out_of_order_queued_packet_crash)) { + while (!queued_packets_.empty()) { + QUIC_FLAG_COUNT( + quic_reloadable_flag_quic_fix_write_out_of_order_queued_packet_crash); + // WritePacket() can potentially clear all queued packets, so we need to + // save the first queued packet to a local variable before calling it. + SerializedPacket packet(std::move(queued_packets_.front())); + queued_packets_.pop_front(); + + const bool write_result = WritePacket(&packet); + + if (connected_ && !write_result) { + // Write failed but connection is open, re-insert |packet| into the + // front of the queue, it will be retried later. + queued_packets_.emplace_front(std::move(packet)); + break; + } + + delete[] packet.encrypted_buffer; + ClearSerializedPacket(&packet); + if (!connected_) { + DCHECK(queued_packets_.empty()) << "Queued packets should have been " + "cleared while closing connection"; + break; + } + + // Continue to send the next packet in queue. + } + } else { + QueuedPacketList::iterator packet_iterator = queued_packets_.begin(); + while (packet_iterator != queued_packets_.end() && + WritePacket(&(*packet_iterator))) { + delete[] packet_iterator->encrypted_buffer; + ClearSerializedPacket(&(*packet_iterator)); + packet_iterator = queued_packets_.erase(packet_iterator); + } } } @@ -1771,19 +1979,23 @@ bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) { } bool QuicConnection::WritePacket(SerializedPacket* packet) { + if (always_discard_packets_after_close_ && ShouldDiscardPacket(*packet)) { + QUIC_FLAG_COUNT_N( + quic_reloadable_flag_quic_always_discard_packets_after_close, 1, 2); + ++stats_.packets_discarded; + return true; + } if (packet->packet_number < sent_packet_manager_.GetLargestSentPacket()) { QUIC_BUG << "Attempt to write packet:" << packet->packet_number << " after:" << sent_packet_manager_.GetLargestSentPacket(); - CloseConnection(QUIC_INTERNAL_ERROR, "Packet written out of order.", - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - UMA_HISTOGRAM_COUNTS_1000("Net.QuicSession.NumQueuedPacketsAtOutOfOrder", queued_packets_.size()); - - RecordInternalErrorLocation(QUIC_CONNECTION_4); + CloseConnection(QUIC_INTERNAL_ERROR, "Packet written out of order.", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + RecordInternalErrorLocation(QUIC_CONNECTION_WRITE_PACKET); return true; } - if (ShouldDiscardPacket(*packet)) { + if (!always_discard_packets_after_close_ && ShouldDiscardPacket(*packet)) { ++stats_.packets_discarded; return true; } @@ -1805,8 +2017,8 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { } // Copy the buffer so it's owned in the future. char* buffer_copy = CopyBuffer(*packet); - termination_packets_->push_back(std::unique_ptr<QuicEncryptedPacket>( - new QuicEncryptedPacket(buffer_copy, encrypted_length, true))); + termination_packets_->emplace_back( + new QuicEncryptedPacket(buffer_copy, encrypted_length, true)); // This assures we won't try to write *forced* packets when blocked. // Return true to stop processing. if (writer_->IsWriteBlocked()) { @@ -1855,9 +2067,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { // In some cases, an MTU probe can cause EMSGSIZE. This indicates that the // MTU discovery is permanently unsuccessful. - if (result.status == WRITE_STATUS_ERROR && - result.error_code == kMessageTooBigErrorCode && - packet->retransmittable_frames.empty() && + if (IsMsgTooBig(result) && packet->retransmittable_frames.empty() && packet->encrypted_length > long_term_mtu_) { mtu_discovery_target_ = 0; mtu_discovery_alarm_->Cancel(); @@ -1865,7 +2075,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { return true; } - if (result.status == WRITE_STATUS_ERROR) { + if (IsWriteError(result.status)) { OnWriteError(result.error_code); QUIC_LOG_FIRST_N(ERROR, 10) << ENDPOINT << "failed writing " << encrypted_length @@ -1875,18 +2085,30 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { return false; } - if (result.status != WRITE_STATUS_ERROR && debug_visitor_ != nullptr) { + if (debug_visitor_ != nullptr) { // Pass the write result to the visitor. debug_visitor_->OnPacketSent(*packet, packet->original_packet_number, packet->transmission_type, packet_send_time); } - // Only adjust the last sent time (for the purpose of tracking the idle - // timeout) if this is the first retransmittable packet sent after a - // packet is received. If it were updated on every sent packet, then - // sending into a black hole might never timeout. - if (IsRetransmittable(*packet) == HAS_RETRANSMITTABLE_DATA && - last_send_for_timeout_ <= time_of_last_received_packet_) { - last_send_for_timeout_ = packet_send_time; + if (IsRetransmittable(*packet) == HAS_RETRANSMITTABLE_DATA) { + // A retransmittable packet has been put on the wire, so no need for the + // |retransmittable_on_wire_alarm_| to possibly send a PING. + retransmittable_on_wire_alarm_->Cancel(); + if (use_path_degrading_alarm_) { + if (!path_degrading_alarm_->IsSet()) { + // This is the first retransmittable packet on the wire after having + // none on the wire. Start the path degrading alarm. + SetPathDegradingAlarm(); + } + } + + // Only adjust the last sent time (for the purpose of tracking the idle + // timeout) if this is the first retransmittable packet sent after a + // packet is received. If it were updated on every sent packet, then + // sending into a black hole might never timeout. + if (last_send_for_timeout_ <= time_of_last_received_packet_) { + last_send_for_timeout_ = packet_send_time; + } } SetPingAlarm(); MaybeSetMtuAlarm(packet_number); @@ -1917,6 +2139,12 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { return true; } +bool QuicConnection::IsMsgTooBig(const WriteResult& result) { + return (result.status == WRITE_STATUS_MSG_TOO_BIG) || + (IsWriteError(result.status) && + result.error_code == kMessageTooBigErrorCode); +} + bool QuicConnection::ShouldDiscardPacket(const SerializedPacket& packet) { if (!connected_) { QUIC_DLOG(INFO) << ENDPOINT @@ -2010,7 +2238,10 @@ void QuicConnection::OnCongestionChange() { } } +// TODO(b/77267845): remove this method once +// FLAGS_quic_reloadable_flag_quic_path_degrading_alarm is deprecated. void QuicConnection::OnPathDegrading() { + DCHECK(!use_path_degrading_alarm_); visitor_->OnPathDegrading(); } @@ -2050,23 +2281,7 @@ void QuicConnection::SendOrQueuePacket(SerializedPacket* packet) { void QuicConnection::OnPingTimeout() { if (!retransmission_alarm_->IsSet()) { - if (use_control_frame_manager_) { - visitor_->SendPing(); - } else { - SendPing(); - } - } -} - -void QuicConnection::SendPing() { - DCHECK(!use_control_frame_manager_); - ScopedPacketFlusher flusher(this, SEND_ACK_IF_QUEUED); - packet_generator_.AddControlFrame( - QuicFrame(QuicPingFrame(++last_control_frame_id_))); - // Send PING frame immediately, without checking for congestion window bounds. - packet_generator_.FlushAllQueuedFrames(); - if (debug_visitor_ != nullptr) { - debug_visitor_->OnPingSent(); + visitor_->SendPing(); } } @@ -2090,13 +2305,11 @@ void QuicConnection::SendAck() { } visitor_->OnAckNeedsRetransmittableFrame(); - if (!use_control_frame_manager_) { - if (!packet_generator_.HasRetransmittableFrames()) { - // Visitor did not add a retransmittable frame, add a ping frame. - packet_generator_.AddControlFrame( - QuicFrame(QuicPingFrame(++last_control_frame_id_))); - } - } +} + +void QuicConnection::OnPathDegradingTimeout() { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_path_degrading_alarm, 2, 4); + visitor_->OnPathDegrading(); } void QuicConnection::OnRetransmissionTimeout() { @@ -2144,8 +2357,8 @@ void QuicConnection::OnRetransmissionTimeout() { } void QuicConnection::SetEncrypter(EncryptionLevel level, - QuicEncrypter* encrypter) { - packet_generator_.SetEncrypter(level, encrypter); + std::unique_ptr<QuicEncrypter> encrypter) { + packet_generator_.SetEncrypter(level, std::move(encrypter)); } void QuicConnection::SetDiversificationNonce( @@ -2165,14 +2378,15 @@ void QuicConnection::SetDefaultEncryptionLevel(EncryptionLevel level) { } void QuicConnection::SetDecrypter(EncryptionLevel level, - QuicDecrypter* decrypter) { - framer_.SetDecrypter(level, decrypter); + std::unique_ptr<QuicDecrypter> decrypter) { + framer_.SetDecrypter(level, std::move(decrypter)); } -void QuicConnection::SetAlternativeDecrypter(EncryptionLevel level, - QuicDecrypter* decrypter, - bool latch_once_used) { - framer_.SetAlternativeDecrypter(level, decrypter, latch_once_used); +void QuicConnection::SetAlternativeDecrypter( + EncryptionLevel level, + std::unique_ptr<QuicDecrypter> decrypter, + bool latch_once_used) { + framer_.SetAlternativeDecrypter(level, std::move(decrypter), latch_once_used); } const QuicDecrypter* QuicConnection::decrypter() const { @@ -2297,19 +2511,11 @@ void QuicConnection::CancelAllAlarms() { send_alarm_->Cancel(); timeout_alarm_->Cancel(); mtu_discovery_alarm_->Cancel(); -} - -void QuicConnection::SendGoAway(QuicErrorCode error, - QuicStreamId last_good_stream_id, - const QuicString& reason) { - DCHECK(!use_control_frame_manager_); - QUIC_DLOG(INFO) << ENDPOINT << "Going away with error " - << QuicErrorCodeToString(error) << " (" << error << ")"; - - // Opportunistically bundle an ack with this outgoing packet. - ScopedPacketFlusher flusher(this, SEND_ACK_IF_PENDING); - packet_generator_.AddControlFrame(QuicFrame(new QuicGoAwayFrame( - ++last_control_frame_id_, error, last_good_stream_id, reason))); + retransmittable_on_wire_alarm_->Cancel(); + if (use_path_degrading_alarm_) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_path_degrading_alarm, 4, 4); + path_degrading_alarm_->Cancel(); + } } QuicByteCount QuicConnection::max_packet_length() const { @@ -2449,6 +2655,14 @@ void QuicConnection::SetRetransmissionAlarm() { QuicTime::Delta::FromMilliseconds(1)); } +void QuicConnection::SetPathDegradingAlarm() { + DCHECK(use_path_degrading_alarm_); + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_path_degrading_alarm, 1, 4); + const QuicTime::Delta delay = sent_packet_manager_.GetPathDegradingDelay(); + path_degrading_alarm_->Update(clock_->ApproximateNow() + delay, + QuicTime::Delta::FromMilliseconds(1)); +} + void QuicConnection::MaybeSetMtuAlarm(QuicPacketNumber sent_packet_number) { // Do not set the alarm if the target size is less than the current size. // This covers the case when |mtu_discovery_target_| is at its default value, @@ -2637,9 +2851,13 @@ bool QuicConnection::SendConnectivityProbingPacket( QuicPacketWriter* probing_writer, const QuicSocketAddress& peer_address) { DCHECK(peer_address.IsInitialized()); - // TODO(zhongyi): remove this histogram once the cause of the INTERNAL_ERROR - // increase is determined. - UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.SentConnectivityProbe", true); + if (always_discard_packets_after_close_ && !connected_) { + QUIC_FLAG_COUNT_N( + quic_reloadable_flag_quic_always_discard_packets_after_close, 2, 2); + QUIC_BUG << "Not sending connectivity probing packet as connection is " + << "disconnected."; + return false; + } if (perspective_ == Perspective::IS_SERVER && probing_writer == nullptr) { // Server can use default packet writer to write probing packet. probing_writer = writer_; @@ -2647,10 +2865,31 @@ bool QuicConnection::SendConnectivityProbingPacket( DCHECK(probing_writer); if (probing_writer->IsWriteBlocked()) { - QUIC_DLOG(INFO) << "Writer blocked when send connectivity probing packet"; + QUIC_DLOG(INFO) << ENDPOINT + << "Writer blocked when send connectivity probing packet."; + if (!handle_write_results_for_connectivity_probe_) { + visitor_->OnWriteBlocked(); + } else { + QUIC_FLAG_COUNT_N( + quic_reloadable_flag_quic_handle_write_results_for_connectivity_probe, + 1, 3); + if (probing_writer == writer_) { + // Visitor should not be write blocked if the probing writer is not the + // default packet writer. + visitor_->OnWriteBlocked(); + } + } return true; } + if (GetQuicReloadableFlag(quic_fix_write_out_of_order_queued_packet_crash) && + GetQuicReloadableFlag( + quic_clear_queued_packets_before_sending_connectivity_probing)) { + QUIC_FLAG_COUNT( + quic_reloadable_flag_quic_clear_queued_packets_before_sending_connectivity_probing); // NOLINT + ClearQueuedPackets(); + } + QUIC_DLOG(INFO) << ENDPOINT << "Sending connectivity probing packet for " << "connection_id = " << connection_id_; @@ -2663,23 +2902,42 @@ bool QuicConnection::SendConnectivityProbingPacket( probing_packet->encrypted_buffer, probing_packet->encrypted_length, self_address().host(), peer_address, per_packet_options_); - if (result.status == WRITE_STATUS_ERROR) { - QUIC_DLOG(INFO) << "Write probing packet not finished with error = " + if (IsWriteError(result.status)) { + if (!handle_write_results_for_connectivity_probe_) { + OnWriteError(result.error_code); + } else { + QUIC_FLAG_COUNT_N( + quic_reloadable_flag_quic_handle_write_results_for_connectivity_probe, + 2, 3); + // Write error for any connectivity probe should not affect the connection + // as it is sent on a different path. + } + QUIC_DLOG(INFO) << ENDPOINT << "Write probing packet failed with error = " << result.error_code; return false; } - // Call OnPacketSent regardless of the write result. This treats a blocked - // write the same as a packet loss. + // Call OnPacketSent regardless of the write result. sent_packet_manager_.OnPacketSent( probing_packet.get(), probing_packet->original_packet_number, packet_send_time, probing_packet->transmission_type, NO_RETRANSMITTABLE_DATA); if (result.status == WRITE_STATUS_BLOCKED) { - visitor_->OnWriteBlocked(); + if (!handle_write_results_for_connectivity_probe_) { + visitor_->OnWriteBlocked(); + } else { + QUIC_FLAG_COUNT_N( + quic_reloadable_flag_quic_handle_write_results_for_connectivity_probe, + 3, 3); + if (probing_writer == writer_) { + // Visitor should not be write blocked if the probing writer is not the + // default packet writer. + visitor_->OnWriteBlocked(); + } + } if (probing_writer->IsWriteBlockedDataBuffered()) { - QUIC_BUG << "Write probing packet blocked"; + QUIC_DLOG(INFO) << ENDPOINT << "Write probing packet blocked"; } } @@ -2710,6 +2968,7 @@ void QuicConnection::DiscoverMtu() { } void QuicConnection::OnPeerMigrationValidated() { + DCHECK(!enable_server_proxy_); if (active_peer_migration_type_ == NO_CHANGE) { QUIC_BUG << "No migration underway."; return; @@ -2723,6 +2982,7 @@ void QuicConnection::OnPeerMigrationValidated() { // migration. This should happen even if a migration is underway, since the // most recent migration is the one that we should pay attention to. void QuicConnection::StartPeerMigration(AddressChangeType peer_migration_type) { + DCHECK(!enable_server_proxy_); // TODO(fayang): Currently, all peer address change type are allowed. Need to // add a method ShouldAllowPeerAddressChange(PeerAddressChangeType type) to // determine whether |type| is allowed. @@ -2746,12 +3006,55 @@ void QuicConnection::StartPeerMigration(AddressChangeType peer_migration_type) { OnConnectionMigration(peer_migration_type); } +void QuicConnection::OnEffectivePeerMigrationValidated() { + DCHECK(enable_server_proxy_); + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_enable_server_proxy, 3, 3); + if (active_effective_peer_migration_type_ == NO_CHANGE) { + QUIC_BUG << "No migration underway."; + return; + } + highest_packet_sent_before_effective_peer_migration_ = 0; + active_effective_peer_migration_type_ = NO_CHANGE; +} + +// TODO(wub): Modify method to start migration whenever a new IP address is seen +// from a packet with sequence number > the one that triggered the previous +// migration. This should happen even if a migration is underway, since the +// most recent migration is the one that we should pay attention to. +void QuicConnection::StartEffectivePeerMigration(AddressChangeType type) { + DCHECK(enable_server_proxy_); + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_enable_server_proxy, 2, 3); + // TODO(fayang): Currently, all peer address change type are allowed. Need to + // add a method ShouldAllowPeerAddressChange(PeerAddressChangeType type) to + // determine whether |type| is allowed. + if (active_effective_peer_migration_type_ != NO_CHANGE || type == NO_CHANGE) { + QUIC_BUG << "Migration underway or no new migration started."; + return; + } + QUIC_DLOG(INFO) << ENDPOINT << "Effective peer's ip:port changed from " + << effective_peer_address_.ToString() << " to " + << GetEffectivePeerAddressFromCurrentPacket().ToString() + << ", migrating connection."; + + highest_packet_sent_before_effective_peer_migration_ = + sent_packet_manager_.GetLargestSentPacket(); + effective_peer_address_ = GetEffectivePeerAddressFromCurrentPacket(); + active_effective_peer_migration_type_ = type; + + // TODO(wub): Move these calls to OnEffectivePeerMigrationValidated. + OnConnectionMigration(type); +} + void QuicConnection::OnConnectionMigration(AddressChangeType addr_change_type) { visitor_->OnConnectionMigration(addr_change_type); sent_packet_manager_.OnConnectionMigration(addr_change_type); } bool QuicConnection::IsCurrentPacketConnectivityProbing() const { + if (enable_server_proxy_) { + return is_current_packet_connectivity_probing_; + } + if (current_packet_content_ != SECOND_FRAME_IS_PADDING) { return false; } @@ -2798,7 +3101,8 @@ bool QuicConnection::MaybeConsiderAsMemoryCorruption( void QuicConnection::MaybeSendProbingRetransmissions() { DCHECK(fill_up_link_during_probing_); - if (!sent_packet_manager_.handshake_confirmed()) { + if (!sent_packet_manager_.handshake_confirmed() || + sent_packet_manager().HasUnackedCryptoPackets()) { return; } @@ -2863,35 +3167,59 @@ void QuicConnection::UpdatePacketContent(PacketContent type) { if (type == SECOND_FRAME_IS_PADDING) { if (current_packet_content_ == FIRST_FRAME_IS_PING) { current_packet_content_ = SECOND_FRAME_IS_PADDING; + if (enable_server_proxy_) { + if (perspective_ == Perspective::IS_SERVER) { + is_current_packet_connectivity_probing_ = + current_effective_peer_migration_type_ != NO_CHANGE; + } else { + is_current_packet_connectivity_probing_ = + (last_packet_source_address_ != peer_address_) || + (last_packet_destination_address_ != self_address_); + } + } return; } } current_packet_content_ = NOT_PADDED_PING; - if (current_peer_migration_type_ == NO_CHANGE) { - return; - } + if (!enable_server_proxy_) { + if (current_peer_migration_type_ == NO_CHANGE) { + return; + } + + // Start peer migration immediately when the current packet is confirmed not + // a connectivity probing packet. + StartPeerMigration(current_peer_migration_type_); + current_peer_migration_type_ = NO_CHANGE; + } else { + if (last_header_.packet_number == + received_packet_manager_.GetLargestObserved()) { + direct_peer_address_ = last_packet_source_address_; + } + if (current_effective_peer_migration_type_ == NO_CHANGE) { + return; + } - // Start peer migration immediately when the current packet is confirmed not - // a connectivity probing packet. - StartPeerMigration(current_peer_migration_type_); - current_peer_migration_type_ = NO_CHANGE; + // Start effective peer migration immediately when the current packet is + // confirmed not a connectivity probing packet. + StartEffectivePeerMigration(current_effective_peer_migration_type_); + current_effective_peer_migration_type_ = NO_CHANGE; + } } void QuicConnection::MaybeEnableSessionDecidesWhatToWrite() { // Only enable session decides what to write code path for version 42+, // because it needs the receiver to allow receiving overlapping stream data. const bool enable_session_decides_what_to_write = - transport_version() > QUIC_VERSION_41 && - GetQuicReloadableFlag(quic_streams_unblocked_by_session2) && - use_control_frame_manager_; + transport_version() > QUIC_VERSION_41; sent_packet_manager_.SetSessionDecideWhatToWrite( enable_session_decides_what_to_write); packet_generator_.SetCanSetTransmissionType( enable_session_decides_what_to_write); } -void QuicConnection::PostProcessAfterAckFrame(bool send_stop_waiting) { +void QuicConnection::PostProcessAfterAckFrame(bool send_stop_waiting, + bool acked_new_packet) { if (no_stop_waiting_frames_) { received_packet_manager_.DontWaitForPacketsBefore( sent_packet_manager_.largest_packet_peer_knows_is_acked()); @@ -2900,6 +3228,26 @@ void QuicConnection::PostProcessAfterAckFrame(bool send_stop_waiting) { // have a better estimate of the current rtt than when it was set. SetRetransmissionAlarm(); + if (!sent_packet_manager_.HasUnackedPackets()) { + // There are no retransmittable packets on the wire, so it may be + // necessary to send a PING to keep a retransmittable packet on the wire. + if (!retransmittable_on_wire_alarm_->IsSet()) { + SetRetransmittableOnWireAlarm(); + } + // There are no retransmittable packets on the wire, so it's impossible to + // say if the connection has degraded. + if (use_path_degrading_alarm_) { + QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_path_degrading_alarm, 3, 4); + path_degrading_alarm_->Cancel(); + } + } else if (acked_new_packet) { + // A previously-unacked packet has been acked, which means forward progress + // has been made. Push back the path degrading alarm. + if (use_path_degrading_alarm_) { + SetPathDegradingAlarm(); + } + } + if (send_stop_waiting) { ++stop_waiting_count_; } else { @@ -2925,4 +3273,22 @@ bool QuicConnection::session_decides_what_to_write() const { return sent_packet_manager_.session_decides_what_to_write(); } +void QuicConnection::SetRetransmittableOnWireAlarm() { + if (perspective_ == Perspective::IS_SERVER) { + // Only clients send pings. + return; + } + if (retransmittable_on_wire_timeout_.IsInfinite()) { + return; + } + if (!visitor_->HasOpenDynamicStreams()) { + retransmittable_on_wire_alarm_->Cancel(); + // Don't send a ping unless there are open streams. + return; + } + retransmittable_on_wire_alarm_->Update( + clock_->ApproximateNow() + retransmittable_on_wire_timeout_, + QuicTime::Delta::Zero()); +} + } // namespace net diff --git a/chromium/net/quic/core/quic_connection.h b/chromium/net/quic/core/quic_connection.h index c07480af19c..e62454ee720 100644 --- a/chromium/net/quic/core/quic_connection.h +++ b/chromium/net/quic/core/quic_connection.h @@ -25,6 +25,7 @@ #include "base/macros.h" #include "net/quic/core/crypto/quic_decrypter.h" +#include "net/quic/core/crypto/quic_encrypter.h" #include "net/quic/core/proto/cached_network_parameters.pb.h" #include "net/quic/core/quic_alarm.h" #include "net/quic/core/quic_alarm_factory.h" @@ -51,8 +52,6 @@ namespace net { class QuicClock; class QuicConfig; class QuicConnection; -class QuicDecrypter; -class QuicEncrypter; class QuicRandom; namespace test { @@ -172,6 +171,10 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface { // Called when a self address change is observed. Returns true if self address // change is allowed. virtual bool AllowSelfAddressChange() const = 0; + + // Called when an ACK is received with a larger |largest_acked| than + // previously observed. + virtual void OnForwardProgressConfirmed() = 0; }; // Interface which gets callbacks from the QuicConnection at interesting @@ -262,7 +265,7 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor // Called when the version negotiation is successful. virtual void OnSuccessfulVersionNegotiation( - const QuicTransportVersion& version) {} + const ParsedQuicVersion& version) {} // Called when a CachedNetworkParameters is sent to the client. virtual void OnSendConnectionState( @@ -356,7 +359,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection void AdjustNetworkParameters(QuicBandwidth bandwidth, QuicTime::Delta rtt); // Returns the max pacing rate for the connection. - QuicBandwidth MaxPacingRate() const; + virtual QuicBandwidth MaxPacingRate() const; // Sets the number of active streams on the connection for congestion control. void SetNumOpenStreams(size_t num_streams); @@ -375,20 +378,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection // otherwise. virtual bool SendControlFrame(const QuicFrame& frame); - // Send a RST_STREAM frame to the peer. - virtual void SendRstStream(QuicStreamId id, - QuicRstStreamErrorCode error, - QuicStreamOffset bytes_written); - // Called when stream |id| is reset because of |error|. virtual void OnStreamReset(QuicStreamId id, QuicRstStreamErrorCode error); - // Send a BLOCKED frame to the peer. - virtual void SendBlocked(QuicStreamId id); - - // Send a WINDOW_UPDATE frame to the peer. - virtual void SendWindowUpdate(QuicStreamId id, QuicStreamOffset byte_offset); - // Closes the connection. // |connection_close_behavior| determines whether or not a connection close // packet is sent to the peer. @@ -397,11 +389,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection const QuicString& details, ConnectionCloseBehavior connection_close_behavior); - // Sends a GOAWAY frame. - virtual void SendGoAway(QuicErrorCode error, - QuicStreamId last_good_stream_id, - const QuicString& reason); - // Returns statistics tracked for this connection. const QuicConnectionStats& GetStats(); @@ -425,6 +412,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection // network. void OnWriteError(int error_code); + // Whether |result| represents a MSG TOO BIG write error. + bool IsMsgTooBig(const WriteResult& result); + // If the socket is not blocked, writes queued packets. void WriteIfNotBlocked(); @@ -484,6 +474,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override; bool OnBlockedFrame(const QuicBlockedFrame& frame) override; void OnPacketComplete() override; + bool IsValidStatelessResetToken(uint128 token) const override; + void OnAuthenticatedIetfStatelessResetPacket( + const QuicIetfStatelessResetPacket& packet) override; // QuicConnectionCloseDelegateInterface void OnUnrecoverableError(QuicErrorCode error, @@ -501,6 +494,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection // QuicSentPacketManager::NetworkChangeVisitor void OnCongestionChange() override; + // TODO(b/76462614): remove OnPathDegrading() once + // FLAGS_quic_reloadable_flag_quic_path_degrading_alarm is deprecated. void OnPathDegrading() override; void OnPathMtuIncreased(QuicPacketLength packet_size) override; @@ -525,11 +520,34 @@ class QUIC_EXPORT_PRIVATE QuicConnection } const QuicTime::Delta ping_timeout() { return ping_timeout_; } // Used in Chromium, but not internally. + // Must only be called before retransmittable_on_wire_alarm_ is set. + void set_retransmittable_on_wire_timeout( + QuicTime::Delta retransmittable_on_wire_timeout) { + DCHECK(!retransmittable_on_wire_alarm_->IsSet()); + retransmittable_on_wire_timeout_ = retransmittable_on_wire_timeout; + } + const QuicTime::Delta retransmittable_on_wire_timeout() { + return retransmittable_on_wire_timeout_; + } + // Used in Chromium, but not internally. void set_creator_debug_delegate(QuicPacketCreator::DebugDelegate* visitor) { packet_generator_.set_debug_delegate(visitor); } const QuicSocketAddress& self_address() const { return self_address_; } - const QuicSocketAddress& peer_address() const { return peer_address_; } + const QuicSocketAddress& peer_address() const { + if (enable_server_proxy_) { + return direct_peer_address_; + } + return peer_address_; + } + const QuicSocketAddress& effective_peer_address() const { + if (enable_server_proxy_) { + return effective_peer_address_; + } + QUIC_BUG << "effective_peer_address() should only be called when " + "enable_server_proxy_ is true."; + return peer_address_; + } QuicConnectionId connection_id() const { return connection_id_; } const QuicClock* clock() const { return clock_; } QuicRandom* random_generator() const { return random_generator_; } @@ -573,12 +591,12 @@ class QUIC_EXPORT_PRIVATE QuicConnection // if the retransmission alarm is not running. void OnPingTimeout(); - // Sends a ping frame. - void SendPing(); - // Sets up a packet with an QuicAckFrame and sends it out. void SendAck(); + // Called when the path degrading alarm fires. + void OnPathDegradingTimeout(); + // Called when an RTO fires. Resets the retransmission alarm if there are // remaining unacked packets. void OnRetransmissionTimeout(); @@ -594,9 +612,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection // connection becomes forward secure and hasn't received acks for all packets. void NeuterUnencryptedPackets(); - // Changes the encrypter used for level |level| to |encrypter|. The function - // takes ownership of |encrypter|. - void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter); + // Changes the encrypter used for level |level| to |encrypter|. + void SetEncrypter(EncryptionLevel level, + std::unique_ptr<QuicEncrypter> encrypter); // SetNonceForPublicHeader sets the nonce that will be transmitted in the // header of each packet encrypted at the initial encryption level decrypted. @@ -607,21 +625,22 @@ class QUIC_EXPORT_PRIVATE QuicConnection // to new packets. void SetDefaultEncryptionLevel(EncryptionLevel level); - // SetDecrypter sets the primary decrypter, replacing any that already exists, - // and takes ownership. If an alternative decrypter is in place then the - // function DCHECKs. This is intended for cases where one knows that future - // packets will be using the new decrypter and the previous decrypter is now - // obsolete. |level| indicates the encryption level of the new decrypter. - void SetDecrypter(EncryptionLevel level, QuicDecrypter* decrypter); + // SetDecrypter sets the primary decrypter, replacing any that already exists. + // If an alternative decrypter is in place then the function DCHECKs. This is + // intended for cases where one knows that future packets will be using the + // new decrypter and the previous decrypter is now obsolete. |level| indicates + // the encryption level of the new decrypter. + void SetDecrypter(EncryptionLevel level, + std::unique_ptr<QuicDecrypter> decrypter); // SetAlternativeDecrypter sets a decrypter that may be used to decrypt - // future packets and takes ownership of it. |level| indicates the encryption - // level of the decrypter. If |latch_once_used| is true, then the first time - // that the decrypter is successful it will replace the primary decrypter. - // Otherwise both decrypters will remain active and the primary decrypter - // will be the one last used. + // future packets. |level| indicates the encryption level of the decrypter. If + // |latch_once_used| is true, then the first time that the decrypter is + // successful it will replace the primary decrypter. Otherwise both + // decrypters will remain active and the primary decrypter will be the one + // last used. void SetAlternativeDecrypter(EncryptionLevel level, - QuicDecrypter* decrypter, + std::unique_ptr<QuicDecrypter> decrypter, bool latch_once_used); const QuicDecrypter* decrypter() const; @@ -748,10 +767,19 @@ class QUIC_EXPORT_PRIVATE QuicConnection defer_send_in_response_to_packets_ = defer; } - bool use_control_frame_manager() const { return use_control_frame_manager_; } - bool session_decides_what_to_write() const; + void SetRetransmittableOnWireAlarm(); + + // Sets the current per-packet options for the connection. The QuicConnection + // does not take ownership of |options|; |options| must live for as long as + // the QuicConnection is in use. + void set_per_packet_options(PerPacketOptions* options) { + per_packet_options_ = options; + } + + bool IsServerProxyEnabled() const { return enable_server_proxy_; } + protected: // Calls cancel() on all the alarms owned by this connection. void CancelAllAlarms(); @@ -767,6 +795,33 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Called when a peer address migration is validated. virtual void OnPeerMigrationValidated(); + // Called after a packet is received from a new effective peer address and is + // decrypted. Starts validation of effective peer's address change. Calls + // OnConnectionMigration as soon as the address changed. + void StartEffectivePeerMigration(AddressChangeType type); + + // Called when a effective peer address migration is validated. + virtual void OnEffectivePeerMigrationValidated(); + + // Get the effective peer address from the packet being processed. For proxied + // connections, effective peer address is the address of the endpoint behind + // the proxy. For non-proxied connections, effective peer address is the same + // as peer address. + // + // Notes for implementations in subclasses: + // - If the connection is not proxied, the overridden method should use the + // base implementation: + // + // return QuicConnection::GetEffectivePeerAddressFromCurrentPacket(); + // + // - If the connection is proxied, the overridden method may return either of + // the following: + // a) The address of the endpoint behind the proxy. The address is used to + // drive effective peer migration. + // b) An uninitialized address, meaning the effective peer address does not + // change. + virtual QuicSocketAddress GetEffectivePeerAddressFromCurrentPacket() const; + // Selects and updates the version of the protocol being used by selecting a // version from |available_versions| which is also supported. Returns true if // such a version exists, false otherwise. @@ -774,17 +829,15 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Returns the current per-packet options for the connection. PerPacketOptions* per_packet_options() { return per_packet_options_; } - // Sets the current per-packet options for the connection. The QuicConnection - // does not take ownership of |options|; |options| must live for as long as - // the QuicConnection is in use. - void set_per_packet_options(PerPacketOptions* options) { - per_packet_options_ = options; - } AddressChangeType active_peer_migration_type() { return active_peer_migration_type_; } + AddressChangeType active_effective_peer_migration_type() const { + return active_effective_peer_migration_type_; + } + // Sends the connection close packet to the peer. |ack_mode| determines // whether ack frame will be bundled with the connection close packet. virtual void SendConnectionClosePacket(QuicErrorCode error, @@ -803,7 +856,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Notify various components(SendPacketManager, Session etc.) that this // connection has been migrated. - void OnConnectionMigration(AddressChangeType addr_change_type); + virtual void OnConnectionMigration(AddressChangeType addr_change_type); // Return whether the packet being processed is a connectivity probing. // A packet is a connectivity probing if it is a padded ping packet with self @@ -894,6 +947,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Sets the retransmission alarm based on SentPacketManager. void SetRetransmissionAlarm(); + // Sets the path degrading alarm. + void SetPathDegradingAlarm(); + // Sets the MTU discovery alarm if necessary. // |sent_packet_number| is the recently sent packet number. void MaybeSetMtuAlarm(QuicPacketNumber sent_packet_number); @@ -922,8 +978,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection void CheckIfApplicationLimited(); // Sets |current_packet_content_| to |type| if applicable. And - // starts peer miration if current packet is confirmed not a connectivity - // probe and |current_peer_migration_type_| indicates peer address change. + // starts effective peer miration if current packet is confirmed not a + // connectivity probe and |current_effective_peer_migration_type_| indicates + // effective peer address change. void UpdatePacketContent(PacketContent type); // Enables session decide what to write based on version and flags. @@ -931,17 +988,29 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Called when last received ack frame has been processed. // |send_stop_waiting| indicates whether a stop waiting needs to be sent. - void PostProcessAfterAckFrame(bool send_stop_waiting); + // |acked_new_packet| is true if a previously-unacked packet was acked. + void PostProcessAfterAckFrame(bool send_stop_waiting, bool acked_new_packet); QuicFramer framer_; // Contents received in the current packet, especially used to identify // whether the current packet is a padded PING packet. PacketContent current_packet_content_; + // True if the packet currently being processed is a connectivity probing + // packet. Is set to false when a new packet is received, and will be set to + // true as soon as |current_packet_content_| is set to + // SECOND_FRAME_IS_PADDING. + bool is_current_packet_connectivity_probing_; // Caches the current peer migration type if a peer migration might be // initiated. As soon as the current packet is confirmed not a connectivity // probe, peer migration will start. + // TODO(wub): Remove once quic_reloadable_flag_quic_enable_server_proxy is + // deprecated. AddressChangeType current_peer_migration_type_; + // Caches the current effective peer migration type if a effective peer + // migration might be initiated. As soon as the current packet is confirmed + // not a connectivity probe, effective peer migration will start. + AddressChangeType current_effective_peer_migration_type_; QuicConnectionHelperInterface* helper_; // Not owned. QuicAlarmFactory* alarm_factory_; // Not owned. PerPacketOptions* per_packet_options_; // Not owned. @@ -955,17 +1024,38 @@ class QUIC_EXPORT_PRIVATE QuicConnection const QuicConnectionId connection_id_; // Address on the last successfully processed packet received from the - // client. + // direct peer. QuicSocketAddress self_address_; QuicSocketAddress peer_address_; + QuicSocketAddress direct_peer_address_; + // Address of the endpoint behind the proxy if the connection is proxied. + // Otherwise it is the same as |peer_address_|. + // NOTE: Currently |effective_peer_address_| and |peer_address_| are always + // the same(the address of the direct peer), but soon we'll change + // |effective_peer_address_| to be the address of the endpoint behind the + // proxy if the connection is proxied. + QuicSocketAddress effective_peer_address_; + // Records change type when the peer initiates migration to a new peer // address. Reset to NO_CHANGE after peer migration is validated. + // TODO(wub): Remove once quic_reloadable_flag_quic_enable_server_proxy is + // deprecated. AddressChangeType active_peer_migration_type_; // Records highest sent packet number when peer migration is started. + // TODO(wub): Remove once quic_reloadable_flag_quic_enable_server_proxy is + // deprecated. QuicPacketNumber highest_packet_sent_before_peer_migration_; + // Records change type when the effective peer initiates migration to a new + // address. Reset to NO_CHANGE after effective peer migration is validated. + AddressChangeType active_effective_peer_migration_type_; + + // Records highest sent packet number when effective peer migration is + // started. + QuicPacketNumber highest_packet_sent_before_effective_peer_migration_; + // True if the last packet has gotten far enough in the framer to be // decrypted. bool last_packet_decrypted_; @@ -1063,6 +1153,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection // The timeout for PING. QuicTime::Delta ping_timeout_; + // Timeout for how long the wire can have no retransmittable packets. + QuicTime::Delta retransmittable_on_wire_timeout_; + // Arena to store class implementations within the QuicConnection. QuicConnectionArena arena_; @@ -1084,6 +1177,11 @@ class QUIC_EXPORT_PRIVATE QuicConnection QuicArenaScopedPtr<QuicAlarm> ping_alarm_; // An alarm that fires when an MTU probe should be sent. QuicArenaScopedPtr<QuicAlarm> mtu_discovery_alarm_; + // An alarm that fires when there have been no retransmittable packets on the + // wire for some period. + QuicArenaScopedPtr<QuicAlarm> retransmittable_on_wire_alarm_; + // An alarm that fires when this connection is considered degrading. + QuicArenaScopedPtr<QuicAlarm> path_degrading_alarm_; // Neither visitor is owned by this class. QuicConnectionVisitorInterface* visitor_; @@ -1194,11 +1292,32 @@ class QUIC_EXPORT_PRIVATE QuicConnection // retransmission code. bool probing_retransmission_pending_; + // Indicates whether a stateless reset token has been received from peer. + bool stateless_reset_token_received_; + // Stores received stateless reset token from peer. Used to verify whether a + // packet is a stateless reset packet. + uint128 received_stateless_reset_token_; + // Id of latest sent control frame. 0 if no control frame has been sent. QuicControlFrameId last_control_frame_id_; - // Latched value of quic_reloadable_flag_quic_use_control_frame_manager. - const bool use_control_frame_manager_; + // Latched value of + // quic_reloadable_flag_quic_server_early_version_negotiation. + const bool negotiate_version_early_; + + // Latched value of + // quic_reloadable_flag_quic_always_discard_packets_after_close. + const bool always_discard_packets_after_close_; + // Latched valure of + // quic_reloadable_flag_quic_handle_write_results_for_connectivity_probe. + const bool handle_write_results_for_connectivity_probe_; + + // Latched value of + // quic_reloadable_flag_quic_path_degrading_alarm + const bool use_path_degrading_alarm_; + + // Latched value of quic_reloadable_flag_quic_enable_server_proxy. + const bool enable_server_proxy_; DISALLOW_COPY_AND_ASSIGN(QuicConnection); }; diff --git a/chromium/net/quic/core/quic_connection_test.cc b/chromium/net/quic/core/quic_connection_test.cc index eb05baccaee..69430cb9d03 100644 --- a/chromium/net/quic/core/quic_connection_test.cc +++ b/chromium/net/quic/core/quic_connection_test.cc @@ -48,6 +48,7 @@ using testing::_; using testing::AnyNumber; using testing::AtLeast; using testing::DoAll; +using testing::Exactly; using testing::Ge; using testing::InSequence; using testing::Invoke; @@ -317,7 +318,8 @@ class TestPacketWriter : public QuicPacketWriter { } if (use_tagging_decrypter_) { - framer_.framer()->SetDecrypter(ENCRYPTION_NONE, new TaggingDecrypter); + framer_.framer()->SetDecrypter(ENCRYPTION_NONE, + QuicMakeUnique<TaggingDecrypter>()); } EXPECT_TRUE(framer_.ProcessPacket(packet)); if (block_on_next_write_) { @@ -502,7 +504,8 @@ class TestConnection : public QuicConnection { SupportedVersions(version)), notifier_(nullptr) { writer->set_perspective(perspective); - SetEncrypter(ENCRYPTION_FORWARD_SECURE, new NullEncrypter(perspective)); + SetEncrypter(ENCRYPTION_FORWARD_SECURE, + QuicMakeUnique<NullEncrypter>(perspective)); SetDataProducer(&producer_); } @@ -528,7 +531,7 @@ class TestConnection : public QuicConnection { ENCRYPTION_NONE, packet_number, *packet, buffer, kMaxPacketSize); delete packet; SerializedPacket serialized_packet( - packet_number, PACKET_6BYTE_PACKET_NUMBER, buffer, encrypted_length, + packet_number, PACKET_4BYTE_PACKET_NUMBER, buffer, encrypted_length, has_ack, has_pending_frames); if (retransmittable == HAS_RETRANSMITTABLE_DATA) { serialized_packet.retransmittable_frames.push_back( @@ -655,6 +658,16 @@ class TestConnection : public QuicConnection { QuicConnectionPeer::GetMtuDiscoveryAlarm(this)); } + TestAlarmFactory::TestAlarm* GetRetransmittableOnWireAlarm() { + return reinterpret_cast<TestAlarmFactory::TestAlarm*>( + QuicConnectionPeer::GetRetransmittableOnWireAlarm(this)); + } + + TestAlarmFactory::TestAlarm* GetPathDegradingAlarm() { + return reinterpret_cast<TestAlarmFactory::TestAlarm*>( + QuicConnectionPeer::GetPathDegradingAlarm(this)); + } + void SetMaxTailLossProbes(size_t max_tail_loss_probes) { QuicSentPacketManagerPeer::SetMaxTailLossProbes( QuicConnectionPeer::GetSentPacketManager(this), max_tail_loss_probes); @@ -667,10 +680,23 @@ class TestConnection : public QuicConnection { void set_notifier(SimpleSessionNotifier* notifier) { notifier_ = notifier; } + void ReturnEffectivePeerAddressForNextPacket(const QuicSocketAddress& addr) { + next_effective_peer_addr_ = QuicMakeUnique<QuicSocketAddress>(addr); + } + + using QuicConnection::IsCurrentPacketConnectivityProbing; using QuicConnection::SelectMutualVersion; using QuicConnection::SendProbingRetransmissions; using QuicConnection::set_defer_send_in_response_to_packets; + protected: + QuicSocketAddress GetEffectivePeerAddressFromCurrentPacket() const override { + if (next_effective_peer_addr_) { + return *std::move(next_effective_peer_addr_); + } + return QuicConnection::GetEffectivePeerAddressFromCurrentPacket(); + } + private: TestPacketWriter* writer() { return static_cast<TestPacketWriter*>(QuicConnection::writer()); @@ -680,6 +706,8 @@ class TestConnection : public QuicConnection { SimpleSessionNotifier* notifier_; + std::unique_ptr<QuicSocketAddress> next_effective_peer_addr_; + DISALLOW_COPY_AND_ASSIGN(TestConnection); }; @@ -709,6 +737,8 @@ struct TestParams { // Constructs various test permutations. std::vector<TestParams> GetTestParams() { + QuicFlagSaver flags; + SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); std::vector<TestParams> params; ParsedQuicVersionVector all_supported_versions = AllSupportedVersions(); for (size_t i = 0; i < all_supported_versions.size(); ++i) { @@ -753,9 +783,12 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { manager_(QuicConnectionPeer::GetSentPacketManager(&connection_)), frame1_(1, false, 0, QuicStringPiece(data1)), frame2_(1, false, 3, QuicStringPiece(data2)), - packet_number_length_(PACKET_6BYTE_PACKET_NUMBER), + packet_number_length_(PACKET_4BYTE_PACKET_NUMBER), connection_id_length_(PACKET_8BYTE_CONNECTION_ID), - notifier_(&connection_) { + notifier_(&connection_), + use_path_degrading_alarm_( + GetQuicReloadableFlag(quic_path_degrading_alarm)) { + SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); connection_.set_defer_send_in_response_to_packets(GetParam().ack_response == AckResponse::kDefer); QuicConnectionPeer::SetNoStopWaitingFrames(&connection_, @@ -796,6 +829,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { .WillRepeatedly(Return(false)); EXPECT_CALL(visitor_, OnCongestionWindowChange(_)).Times(AnyNumber()); EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(AnyNumber()); + EXPECT_CALL(visitor_, OnForwardProgressConfirmed()).Times(AnyNumber()); EXPECT_CALL(*loss_algorithm_, GetLossTimeout()) .WillRepeatedly(Return(QuicTime::Zero())); @@ -981,16 +1015,12 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { connection_.OnStreamReset(id, error); return; } - if (connection_.use_control_frame_manager()) { - std::unique_ptr<QuicRstStreamFrame> rst_stream = - QuicMakeUnique<QuicRstStreamFrame>(1, id, error, bytes_written); - if (connection_.SendControlFrame(QuicFrame(rst_stream.get()))) { - rst_stream.release(); - } - connection_.OnStreamReset(id, error); - return; + std::unique_ptr<QuicRstStreamFrame> rst_stream = + QuicMakeUnique<QuicRstStreamFrame>(1, id, error, bytes_written); + if (connection_.SendControlFrame(QuicFrame(rst_stream.get()))) { + rst_stream.release(); } - connection_.SendRstStream(id, error, bytes_written); + connection_.OnStreamReset(id, error); } void ProcessAckPacket(QuicPacketNumber packet_number, QuicAckFrame* frame) { @@ -1168,6 +1198,10 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { SimpleSessionNotifier notifier_; + // Latched value of + // quic_reloadable_flag_quic_path_degrading_alarm + bool use_path_degrading_alarm_; + private: DISALLOW_COPY_AND_ASSIGN(QuicConnectionTest); }; @@ -1255,8 +1289,17 @@ TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); - // Clear peer address. - QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + } else { + // Clear peer_address. + QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); + } QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5); QuicStreamFrame stream_frame(1u, false, 0u, QuicStringPiece()); @@ -1266,6 +1309,10 @@ TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) { /*port=*/23456); ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, kNewPeerAddress); + EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); + } // Decrease packet number to simulate out-of-order packets. QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 4); @@ -1273,6 +1320,10 @@ TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) { EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, kPeerAddress); + EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); + } } TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) { @@ -1281,15 +1332,28 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) { QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); - // Clear peer address. - QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); - EXPECT_FALSE(connection_.peer_address().IsInitialized()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + } else { + // Clear peer_address. + QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); + EXPECT_FALSE(connection_.peer_address().IsInitialized()); + } QuicStreamFrame stream_frame(1u, false, 0u, QuicStringPiece()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + } // Process another packet with a different peer address on server side will // start connection migration. @@ -1299,6 +1363,78 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) { ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); + } +} + +TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) { + if (!GetQuicReloadableFlag(quic_enable_server_proxy)) { + return; + } + + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + set_perspective(Perspective::IS_SERVER); + QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); + EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); + + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is different from direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + const QuicSocketAddress kEffectivePeerAddress = + QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/43210); + connection_.ReturnEffectivePeerAddressForNextPacket(kEffectivePeerAddress); + + QuicStreamFrame stream_frame(1u, false, 0u, QuicStringPiece()); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, + kPeerAddress); + EXPECT_EQ(kPeerAddress, connection_.peer_address()); + EXPECT_EQ(kEffectivePeerAddress, connection_.effective_peer_address()); + + // Process another packet with the same direct peer address and different + // effective peer address on server side will start connection migration. + const QuicSocketAddress kNewEffectivePeerAddress = + QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/54321); + connection_.ReturnEffectivePeerAddressForNextPacket(kNewEffectivePeerAddress); + EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); + ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, + kPeerAddress); + EXPECT_EQ(kPeerAddress, connection_.peer_address()); + EXPECT_EQ(kNewEffectivePeerAddress, connection_.effective_peer_address()); + + // Process another packet with a different direct peer address and the same + // effective peer address on server side will not start connection migration. + const QuicSocketAddress kNewPeerAddress = + QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); + connection_.ReturnEffectivePeerAddressForNextPacket(kNewEffectivePeerAddress); + EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); + // ack_frame is used to complete the migration started by the last packet, it + // is required to complete the last migration such that the next migration can + // start. + QuicAckFrame ack_frame = InitAckFrame(1); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _)); + ProcessFramePacketWithAddresses(QuicFrame(&ack_frame), kSelfAddress, + kNewPeerAddress); + EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); + EXPECT_EQ(kNewEffectivePeerAddress, connection_.effective_peer_address()); + + // Process another packet with different direct peer address and different + // effective peer address on server side will start connection migration. + const QuicSocketAddress kFinalEffectivePeerAddress = + QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/65432); + const QuicSocketAddress kFinalPeerAddress = + QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/34567); + connection_.ReturnEffectivePeerAddressForNextPacket( + kFinalEffectivePeerAddress); + EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); + ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, + kFinalPeerAddress); + EXPECT_EQ(kFinalPeerAddress, connection_.peer_address()); + EXPECT_EQ(kFinalEffectivePeerAddress, connection_.effective_peer_address()); } TEST_P(QuicConnectionTest, ReceivePaddedPingAtServer) { @@ -1307,15 +1443,28 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtServer) { QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); - // Clear peer address. - QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); - EXPECT_FALSE(connection_.peer_address().IsInitialized()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + } else { + // Clear peer_address. + QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); + EXPECT_FALSE(connection_.peer_address().IsInitialized()); + } QuicStreamFrame stream_frame(1u, false, 0u, QuicStringPiece()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + } EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(0); @@ -1331,7 +1480,77 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtServer) { clock_.Now())); ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received); + + EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing()); EXPECT_EQ(kPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + } +} + +TEST_P(QuicConnectionTest, WriteOutOfOrderQueuedPackets) { + // When the flag is false, this test will trigger a use-after-free, which + // often means crashes, but not always, i.e. it can't be reliably tested. + SetQuicReloadableFlag(quic_fix_write_out_of_order_queued_packet_crash, true); + set_perspective(Perspective::IS_CLIENT); + + BlockOnNextWrite(); + + QuicStreamId stream_id = 2; + connection_.SendStreamDataWithString(stream_id, "foo", 0, NO_FIN); + + EXPECT_EQ(1u, connection_.NumQueuedPackets()); + + writer_->SetWritable(); + connection_.SendConnectivityProbingPacket(writer_.get(), + connection_.peer_address()); + + if (GetQuicReloadableFlag( + quic_clear_queued_packets_before_sending_connectivity_probing)) { + EXPECT_EQ(0u, connection_.NumQueuedPackets()); + connection_.OnCanWrite(); + EXPECT_TRUE(connection_.connected()); + } else { + EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INTERNAL_ERROR, + "Packet written out of order.", + ConnectionCloseSource::FROM_SELF)); + EXPECT_QUIC_BUG(connection_.OnCanWrite(), + "Attempt to write packet:1 after:2"); + EXPECT_FALSE(connection_.connected()); + } +} + +TEST_P(QuicConnectionTest, DiscardQueuedPacketsAfterConnectionClose) { + // Regression test for b/74073386. + // When the flag is false, this test will trigger a use-after-free, which + // often means crashes, but not always, i.e. it can't be reliably tested. + SetQuicReloadableFlag(quic_fix_write_out_of_order_queued_packet_crash, true); + { + InSequence seq; + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(1); + } + + set_perspective(Perspective::IS_CLIENT); + + writer_->SimulateNextPacketTooLarge(); + + // This packet write should fail, which should cause the connection to close + // after sending a connection close packet, then the failed packet should be + // queued. + connection_.SendStreamDataWithString(/*id=*/2, "foo", 0, NO_FIN); + + EXPECT_FALSE(connection_.connected()); + EXPECT_EQ(1u, connection_.NumQueuedPackets()); + + if (GetQuicReloadableFlag(quic_always_discard_packets_after_close)) { + EXPECT_EQ(0u, connection_.GetStats().packets_discarded); + connection_.OnCanWrite(); + EXPECT_EQ(1u, connection_.GetStats().packets_discarded); + } else { + EXPECT_QUIC_BUG(connection_.OnCanWrite(), + "Attempt to write packet:1 after:2"); + } } TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtServer) { @@ -1340,15 +1559,28 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtServer) { QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); - // Clear peer address. - QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); - EXPECT_FALSE(connection_.peer_address().IsInitialized()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + } else { + // Clear peer_address. + QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); + EXPECT_FALSE(connection_.peer_address().IsInitialized()); + } QuicStreamFrame stream_frame(1u, false, 0u, QuicStringPiece()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + } EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(1); @@ -1367,13 +1599,22 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtServer) { clock_.Now())); ProcessReceivedPacket(kSelfAddress, kNewPeerAddress, *received); + + EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing()); EXPECT_EQ(kPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + } // Process another packet with the old peer address on server side will not // start peer migration. EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, kPeerAddress); + EXPECT_EQ(kPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + } } TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { @@ -1382,15 +1623,28 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); - // Clear peer address. - QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); - EXPECT_FALSE(connection_.peer_address().IsInitialized()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + } else { + // Clear peer_address. + QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); + EXPECT_FALSE(connection_.peer_address().IsInitialized()); + } QuicStreamFrame stream_frame(1u, false, 0u, QuicStringPiece()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + } EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(1); @@ -1409,6 +1663,9 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { clock_.Now())); ProcessReceivedPacket(kSelfAddress, kNewPeerAddress, *received); EXPECT_EQ(kPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + } // Process another non-probing packet with the new peer address on server // side will start peer migration. @@ -1417,6 +1674,9 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); + } } TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) { @@ -1424,15 +1684,28 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) { set_perspective(Perspective::IS_CLIENT); EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); - // Clear peer address. - QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); - EXPECT_FALSE(connection_.peer_address().IsInitialized()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + } else { + // Clear peer_address. + QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); + EXPECT_FALSE(connection_.peer_address().IsInitialized()); + } QuicStreamFrame stream_frame(1u, false, 0u, QuicStringPiece()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + } // Client takes all padded PING packet as speculative connectivity // probing packet, and reports to visitor. @@ -1448,7 +1721,11 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) { clock_.Now())); ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received); + EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing()); EXPECT_EQ(kPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + } } TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtClient) { @@ -1456,15 +1733,28 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtClient) { set_perspective(Perspective::IS_CLIENT); EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); - // Clear peer address. - QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); - EXPECT_FALSE(connection_.peer_address().IsInitialized()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + } else { + // Clear peer_address. + QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); + EXPECT_FALSE(connection_.peer_address().IsInitialized()); + } QuicStreamFrame stream_frame(1u, false, 0u, QuicStringPiece()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + } // Process a padded PING packet with a different self address on client side // is effectively receiving a connectivity probing. @@ -1483,7 +1773,11 @@ TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtClient) { clock_.Now())); ProcessReceivedPacket(kNewSelfAddress, kPeerAddress, *received); + EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing()); EXPECT_EQ(kPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + } } TEST_P(QuicConnectionTest, PeerAddressChangeAtClient) { @@ -1491,15 +1785,28 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtClient) { set_perspective(Perspective::IS_CLIENT); EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); - // Clear peer address. - QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); - EXPECT_FALSE(connection_.peer_address().IsInitialized()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + } else { + // Clear peer_address. + QuicConnectionPeer::SetPeerAddress(&connection_, QuicSocketAddress()); + EXPECT_FALSE(connection_.peer_address().IsInitialized()); + } QuicStreamFrame stream_frame(1u, false, 0u, QuicStringPiece()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + } // Process another packet with a different peer address on client side will // only update peer address. @@ -1509,6 +1816,9 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtClient) { ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress, kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); + if (GetQuicReloadableFlag(quic_enable_server_proxy)) { + EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); + } } TEST_P(QuicConnectionTest, MaxPacketSize) { @@ -1858,16 +2168,11 @@ TEST_P(QuicConnectionTest, AckNeedsRetransmittableFrames) { } // Receiving Packet 40 causes 20th ack to send. Session is informed and adds // WINDOW_UPDATE. - if (connection_.use_control_frame_manager()) { - EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()) - .WillOnce(Invoke([this]() { - connection_.SendControlFrame( - QuicFrame(new QuicWindowUpdateFrame(1, 0, 0))); - })); - } else { - EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()) - .WillOnce(Invoke([this]() { connection_.SendWindowUpdate(0, 0); })); - } + EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()) + .WillOnce(Invoke([this]() { + connection_.SendControlFrame( + QuicFrame(new QuicWindowUpdateFrame(1, 0, 0))); + })); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); EXPECT_EQ(0u, writer_->window_update_frames().size()); ProcessDataPacket(40); @@ -1888,14 +2193,10 @@ TEST_P(QuicConnectionTest, AckNeedsRetransmittableFrames) { EXPECT_EQ(0u, writer_->window_update_frames().size()); } // Session does not add a retransmittable frame. - if (connection_.use_control_frame_manager()) { - EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()) - .WillOnce(Invoke([this]() { - connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); - })); - } else { - EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(1); - } + EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()) + .WillOnce(Invoke([this]() { + connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); + })); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); EXPECT_EQ(0u, writer_->ping_frames().size()); ProcessDataPacket(99); @@ -1940,8 +2241,6 @@ TEST_P(QuicConnectionTest, LeastUnackedLower) { } TEST_P(QuicConnectionTest, TooManySentPackets) { - SetQuicReloadableFlag(quic_close_session_on_too_many_outstanding_sent_packets, - true); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); QuicPacketCount max_tracked_packets = 50; @@ -2403,8 +2702,7 @@ TEST_P(QuicConnectionTest, DoNotSendQueuedPacketForResetStream) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); writer_->SetWritable(); connection_.OnCanWrite(); - if (connection_.use_control_frame_manager() && - !connection_.session_decides_what_to_write()) { + if (!connection_.session_decides_what_to_write()) { // OnCanWrite will cause RST_STREAM be sent again. connection_.SendControlFrame(QuicFrame(new QuicRstStreamFrame( 1, stream_id, QUIC_ERROR_PROCESSING_STREAM, 14))); @@ -2428,8 +2726,7 @@ TEST_P(QuicConnectionTest, SendQueuedPacketForQuicRstStreamNoError) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(2)); writer_->SetWritable(); connection_.OnCanWrite(); - if (connection_.use_control_frame_manager() && - !connection_.session_decides_what_to_write()) { + if (!connection_.session_decides_what_to_write()) { // OnCanWrite will cause RST_STREAM be sent again. connection_.SendControlFrame(QuicFrame( new QuicRstStreamFrame(1, stream_id, QUIC_STREAM_NO_ERROR, 14))); @@ -2566,8 +2863,7 @@ TEST_P(QuicConnectionTest, DoNotSendPendingRetransmissionForResetStream) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); writer_->SetWritable(); connection_.OnCanWrite(); - if (connection_.use_control_frame_manager() && - !connection_.session_decides_what_to_write()) { + if (!connection_.session_decides_what_to_write()) { // OnCanWrite will cause this RST_STREAM_FRAME be sent again. connection_.SendControlFrame(QuicFrame(new QuicRstStreamFrame( 1, stream_id, QUIC_ERROR_PROCESSING_STREAM, 14))); @@ -2603,17 +2899,12 @@ TEST_P(QuicConnectionTest, SendPendingRetransmissionForQuicRstStreamNoError) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(2)); writer_->SetWritable(); connection_.OnCanWrite(); - if (connection_.use_control_frame_manager()) { - // The RST_STREAM_FRAME is sent after queued packets and pending - // retransmission. - connection_.SendControlFrame(QuicFrame( - new QuicRstStreamFrame(1, stream_id, QUIC_STREAM_NO_ERROR, 14))); - EXPECT_EQ(1u, writer_->frame_count()); - EXPECT_EQ(1u, writer_->rst_stream_frames().size()); - } else { - EXPECT_EQ(1u, writer_->frame_count()); - EXPECT_EQ(0u, writer_->rst_stream_frames().size()); - } + // The RST_STREAM_FRAME is sent after queued packets and pending + // retransmission. + connection_.SendControlFrame(QuicFrame( + new QuicRstStreamFrame(1, stream_id, QUIC_STREAM_NO_ERROR, 14))); + EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_EQ(1u, writer_->rst_stream_frames().size()); } TEST_P(QuicConnectionTest, RetransmitAckedPacket) { @@ -2640,6 +2931,9 @@ TEST_P(QuicConnectionTest, RetransmitAckedPacket) { // Now, ack the previous transmission. EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _)); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(false, _, _, _, _)); + } QuicAckFrame ack_all = InitAckFrame(3); ProcessAckPacket(&ack_all); @@ -2940,11 +3234,13 @@ TEST_P(QuicConnectionTest, RetransmitWithSameEncryptionLevel) { // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at // the end of the packet. We can test this to check which encrypter was used. - connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01)); + connection_.SetEncrypter(ENCRYPTION_NONE, + QuicMakeUnique<TaggingEncrypter>(0x01)); SendStreamDataToPeer(kCryptoStreamId, "foo", 0, NO_FIN, nullptr); EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet()); - connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02)); + connection_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(0x02)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); SendStreamDataToPeer(3, "foo", 0, NO_FIN, nullptr); EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet()); @@ -2969,7 +3265,8 @@ TEST_P(QuicConnectionTest, SendHandshakeMessages) { use_tagging_decrypter(); // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at // the end of the packet. We can test this to check which encrypter was used. - connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01)); + connection_.SetEncrypter(ENCRYPTION_NONE, + QuicMakeUnique<TaggingEncrypter>(0x01)); // Attempt to send a handshake message and have the socket block. EXPECT_CALL(*send_algorithm_, CanSend(_)).WillRepeatedly(Return(true)); @@ -2979,7 +3276,8 @@ TEST_P(QuicConnectionTest, SendHandshakeMessages) { EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Switch to the new encrypter. - connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02)); + connection_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(0x02)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); // Now become writeable and flush the packets. @@ -2995,7 +3293,8 @@ TEST_P(QuicConnectionTest, SendHandshakeMessages) { TEST_P(QuicConnectionTest, DropRetransmitsForNullEncryptedPacketAfterForwardSecure) { use_tagging_decrypter(); - connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01)); + connection_.SetEncrypter(ENCRYPTION_NONE, + QuicMakeUnique<TaggingEncrypter>(0x01)); QuicPacketNumber packet_number; SendStreamDataToPeer(kCryptoStreamId, "foo", 0, NO_FIN, &packet_number); @@ -3006,7 +3305,7 @@ TEST_P(QuicConnectionTest, // Go forward secure. connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, - new TaggingEncrypter(0x02)); + QuicMakeUnique<TaggingEncrypter>(0x02)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); notifier_.NeuterUnencryptedData(); connection_.NeuterUnencryptedPackets(); @@ -3020,12 +3319,14 @@ TEST_P(QuicConnectionTest, TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) { use_tagging_decrypter(); - connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01)); + connection_.SetEncrypter(ENCRYPTION_NONE, + QuicMakeUnique<TaggingEncrypter>(0x01)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_NONE); SendStreamDataToPeer(1, "foo", 0, NO_FIN, nullptr); - connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02)); + connection_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(0x02)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); SendStreamDataToPeer(2, "bar", 0, NO_FIN, nullptr); @@ -3043,7 +3344,8 @@ TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) { use_tagging_decrypter(); const uint8_t tag = 0x07; - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(tag)); // Process an encrypted packet which can not yet be decrypted which should // result in the packet being buffered. @@ -3051,9 +3353,11 @@ TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) { // Transition to the new encryption state and process another encrypted packet // which should result in the original packet being processed. - connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag)); + connection_.SetDecrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<StrictTaggingDecrypter>(tag)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); - connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + connection_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(tag)); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(2); ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_INITIAL); @@ -3073,7 +3377,8 @@ TEST_P(QuicConnectionTest, Buffer100NonDecryptablePackets) { use_tagging_decrypter(); const uint8_t tag = 0x07; - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(tag)); // Process an encrypted packet which can not yet be decrypted which should // result in the packet being buffered. @@ -3083,9 +3388,11 @@ TEST_P(QuicConnectionTest, Buffer100NonDecryptablePackets) { // Transition to the new encryption state and process another encrypted packet // which should result in the original packets being processed. - connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag)); + connection_.SetDecrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<StrictTaggingDecrypter>(tag)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); - connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + connection_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(tag)); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(101); ProcessDataPacketAtLevel(101, !kHasStopWaiting, ENCRYPTION_INITIAL); @@ -3121,7 +3428,9 @@ TEST_P(QuicConnectionTest, TestRetransmitOrder) { clock_.AdvanceTime(QuicTime::Delta::FromSeconds(20)); { InSequence s; - EXPECT_CALL(visitor_, OnPathDegrading()); + if (!use_path_degrading_alarm_) { + EXPECT_CALL(visitor_, OnPathDegrading()); + } EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, first_packet_size, _)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, second_packet_size, _)); } @@ -3227,6 +3536,7 @@ TEST_P(QuicConnectionTest, InitialTimeout) { EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_FALSE(connection_.GetSendAlarm()->IsSet()); EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet()); + EXPECT_FALSE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); } TEST_P(QuicConnectionTest, HandshakeTimeout) { @@ -3285,7 +3595,7 @@ TEST_P(QuicConnectionTest, PingAfterSend) { EXPECT_EQ(clock_.ApproximateNow() + QuicTime::Delta::FromSeconds(15), connection_.GetPingAlarm()->deadline()); - // Now recevie and ACK of the previous packet, which will move the + // Now recevie an ACK of the previous packet, which will move the // ping alarm forward. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); QuicAckFrame frame = InitAckFrame(1); @@ -3301,11 +3611,9 @@ TEST_P(QuicConnectionTest, PingAfterSend) { writer_->Reset(); clock_.AdvanceTime(QuicTime::Delta::FromSeconds(15)); - if (connection_.use_control_frame_manager()) { - EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { - connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); - })); - } + EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { + connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); + })); connection_.GetPingAlarm()->Fire(); EXPECT_EQ(1u, writer_->frame_count()); ASSERT_EQ(1u, writer_->ping_frames().size()); @@ -3335,7 +3643,7 @@ TEST_P(QuicConnectionTest, ReducedPingTimeout) { EXPECT_EQ(clock_.ApproximateNow() + QuicTime::Delta::FromSeconds(10), connection_.GetPingAlarm()->deadline()); - // Now recevie and ACK of the previous packet, which will move the + // Now recevie an ACK of the previous packet, which will move the // ping alarm forward. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); QuicAckFrame frame = InitAckFrame(1); @@ -3351,11 +3659,9 @@ TEST_P(QuicConnectionTest, ReducedPingTimeout) { writer_->Reset(); clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10)); - if (connection_.use_control_frame_manager()) { - EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { - connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); - })); - } + EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { + connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); + })); connection_.GetPingAlarm()->Fire(); EXPECT_EQ(1u, writer_->frame_count()); ASSERT_EQ(1u, writer_->ping_frames().size()); @@ -4067,7 +4373,9 @@ TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) { // Send stream data. SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, FIN, nullptr); - EXPECT_CALL(visitor_, OnPathDegrading()); + if (!use_path_degrading_alarm_) { + EXPECT_CALL(visitor_, OnPathDegrading()); + } // Fire the retransmission alarm 6 times, twice for TLP and 4 times for RTO. for (int i = 0; i < 6; ++i) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); @@ -4101,7 +4409,9 @@ TEST_P(QuicConnectionTest, TimeoutAfter3ClientRTOs) { // Send stream data. SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, FIN, nullptr); - EXPECT_CALL(visitor_, OnPathDegrading()); + if (!use_path_degrading_alarm_) { + EXPECT_CALL(visitor_, OnPathDegrading()); + } // Fire the retransmission alarm 4 times, twice for TLP and 2 times for RTO. for (int i = 0; i < 4; ++i) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); @@ -4224,8 +4534,10 @@ TEST_P(QuicConnectionTest, SendDelayedAck) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + connection_.SetDecrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<StrictTaggingDecrypter>(tag)); + peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -4266,8 +4578,10 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + connection_.SetDecrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<StrictTaggingDecrypter>(tag)); + peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -4329,8 +4643,10 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + connection_.SetDecrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<StrictTaggingDecrypter>(tag)); + peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -4380,8 +4696,10 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + connection_.SetDecrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<StrictTaggingDecrypter>(tag)); + peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -4437,8 +4755,10 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + connection_.SetDecrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<StrictTaggingDecrypter>(tag)); + peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -4502,8 +4822,10 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + connection_.SetDecrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<StrictTaggingDecrypter>(tag)); + peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -4585,8 +4907,10 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + connection_.SetDecrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<StrictTaggingDecrypter>(tag)); + peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -4652,8 +4976,10 @@ TEST_P(QuicConnectionTest, EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + connection_.SetDecrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<StrictTaggingDecrypter>(tag)); + peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -4954,6 +5280,102 @@ TEST_P(QuicConnectionTest, SendWhenDisconnected) { false, false); } +TEST_P(QuicConnectionTest, SendConnectivityProbingWhenDisconnected) { + EXPECT_TRUE(connection_.connected()); + EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _, + ConnectionCloseSource::FROM_SELF)); + connection_.CloseConnection(QUIC_PEER_GOING_AWAY, "no reason", + ConnectionCloseBehavior::SILENT_CLOSE); + EXPECT_FALSE(connection_.connected()); + EXPECT_FALSE(connection_.CanWriteStreamData()); + + int num_packets_sent = + GetQuicReloadableFlag(quic_always_discard_packets_after_close) ? 0 : 1; + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)) + .Times(num_packets_sent); + + if (GetQuicReloadableFlag(quic_always_discard_packets_after_close)) { + EXPECT_QUIC_BUG(connection_.SendConnectivityProbingPacket( + writer_.get(), connection_.peer_address()), + "Not sending connectivity probing packet as connection is " + "disconnected."); + } else { + connection_.SendConnectivityProbingPacket(writer_.get(), + connection_.peer_address()); + } +} + +TEST_P(QuicConnectionTest, WriteBlockedAfterClientSendsConnectivityProbe) { + EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); + TestPacketWriter probing_writer(version(), &clock_); + // Block next write so that sending connectivity probe will encounter a + // blocked write when send a connectivity probe to the peer. + probing_writer.BlockOnNextWrite(); + if (GetQuicReloadableFlag(quic_handle_write_results_for_connectivity_probe)) { + // Connection will not be marked as write blocked as connectivity probe only + // affects the probing_writer which is not the default. + EXPECT_CALL(visitor_, OnWriteBlocked()).Times(0); + } else { + EXPECT_CALL(visitor_, OnWriteBlocked()).Times(1); + } + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(1); + connection_.SendConnectivityProbingPacket(&probing_writer, + connection_.peer_address()); +} + +TEST_P(QuicConnectionTest, WriterBlockedAfterServerSendsConnectivityProbe) { + set_perspective(Perspective::IS_SERVER); + QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); + + // Block next write so that sending connectivity probe will encounter a + // blocked write when send a connectivity probe to the peer. + writer_->BlockOnNextWrite(); + // Connection will be marked as write blocked as server uses the default + // writer to send connectivity probes. + EXPECT_CALL(visitor_, OnWriteBlocked()).Times(1); + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(1); + connection_.SendConnectivityProbingPacket(writer_.get(), + connection_.peer_address()); +} + +TEST_P(QuicConnectionTest, WriterErrorWhenClientSendsConnectivityProbe) { + EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); + TestPacketWriter probing_writer(version(), &clock_); + probing_writer.SetShouldWriteFail(); + + if (GetQuicReloadableFlag(quic_handle_write_results_for_connectivity_probe)) { + // Connection should not be closed if a connectivity probe is failed to be + // sent. + EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(0); + } else { + EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(1); + } + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0); + connection_.SendConnectivityProbingPacket(&probing_writer, + connection_.peer_address()); +} + +TEST_P(QuicConnectionTest, WriterErrorWhenServerSendsConnectivityProbe) { + set_perspective(Perspective::IS_SERVER); + QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); + + writer_->SetShouldWriteFail(); + if (GetQuicReloadableFlag(quic_handle_write_results_for_connectivity_probe)) { + // Connection should not be closed if a connectivity probe is failed to be + // sent. + EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(0); + } else { + EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(1); + } + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0); + connection_.SendConnectivityProbingPacket(writer_.get(), + connection_.peer_address()); +} + TEST_P(QuicConnectionTest, PublicReset) { QuicPublicResetPacket header; // Public reset packet in only built by server. @@ -5131,7 +5553,7 @@ TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) { // Send a version negotiation packet. std::unique_ptr<QuicEncryptedPacket> encrypted( - peer_framer_.BuildVersionNegotiationPacket(connection_id_, + peer_framer_.BuildVersionNegotiationPacket(connection_id_, false, AllSupportedVersions())); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*encrypted, QuicTime::Zero())); @@ -5166,7 +5588,7 @@ TEST_P(QuicConnectionTest, BadVersionNegotiation) { OnConnectionClosed(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, _, ConnectionCloseSource::FROM_SELF)); std::unique_ptr<QuicEncryptedPacket> encrypted( - framer_.BuildVersionNegotiationPacket(connection_id_, + framer_.BuildVersionNegotiationPacket(connection_id_, false, AllSupportedVersions())); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*encrypted, QuicTime::Zero())); @@ -5415,11 +5837,7 @@ TEST_P(QuicConnectionTest, SendPingImmediately) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _)).Times(1); EXPECT_CALL(debug_visitor, OnPingSent()).Times(1); - if (connection_.use_control_frame_manager()) { - connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); - } else { - connection_.SendPing(); - } + connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); EXPECT_FALSE(connection_.HasQueuedData()); } @@ -5430,11 +5848,7 @@ TEST_P(QuicConnectionTest, SendBlockedImmediately) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _)).Times(1); EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent); - if (connection_.use_control_frame_manager()) { - connection_.SendControlFrame(QuicFrame(new QuicBlockedFrame(1, 3))); - } else { - connection_.SendBlocked(3); - } + connection_.SendControlFrame(QuicFrame(new QuicBlockedFrame(1, 3))); EXPECT_EQ(1u, connection_.GetStats().blocked_frames_sent); EXPECT_FALSE(connection_.HasQueuedData()); } @@ -5451,6 +5865,10 @@ TEST_P(QuicConnectionTest, SendingUnencryptedStreamDataFails) { } TEST_P(QuicConnectionTest, OnPathDegrading) { + if (use_path_degrading_alarm_) { + return; + } + QuicByteCount packet_size; const size_t kMinTimeoutsBeforePathDegrading = 2; @@ -5478,6 +5896,140 @@ TEST_P(QuicConnectionTest, OnPathDegrading) { connection_.GetRetransmissionAlarm()->Fire(); } +// Includes regression test for https://b.corp.google.com/issues/69979024. +TEST_P(QuicConnectionTest, PathDegradingAlarm) { + if (!use_path_degrading_alarm_) { + return; + } + + EXPECT_TRUE(connection_.connected()); + EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet()); + + const char data[] = "data"; + size_t data_size = strlen(data); + QuicStreamOffset offset = 0; + + for (int i = 0; i < 2; ++i) { + // Send a packet. Now there's a retransmittable packet on the wire, so the + // path degrading alarm should be set. + connection_.SendStreamDataWithString(1, data, offset, NO_FIN); + offset += data_size; + EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet()); + // Check the deadline of the path degrading alarm. + QuicTime::Delta delay = + QuicConnectionPeer::GetSentPacketManager(&connection_) + ->GetPathDegradingDelay(); + EXPECT_EQ(clock_.ApproximateNow() + delay, + connection_.GetPathDegradingAlarm()->deadline()); + + // Send a second packet. The path degrading alarm's deadline should remain + // the same. + // Regression test for https://b.corp.google.com/issues/69979024. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + QuicTime prev_deadline = connection_.GetPathDegradingAlarm()->deadline(); + connection_.SendStreamDataWithString(1, data, offset, NO_FIN); + offset += data_size; + EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet()); + EXPECT_EQ(prev_deadline, connection_.GetPathDegradingAlarm()->deadline()); + + // Now receive an ACK of the first packet. This should advance the path + // degrading alarm's deadline since forward progress has been made. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + if (i == 0) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + } + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); + QuicAckFrame frame = InitAckFrame({{1u + 2u * i, 2u + 2u * i}}); + ProcessAckPacket(&frame); + EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet()); + // Check the deadline of the path degrading alarm. + delay = QuicConnectionPeer::GetSentPacketManager(&connection_) + ->GetPathDegradingDelay(); + EXPECT_EQ(clock_.ApproximateNow() + delay, + connection_.GetPathDegradingAlarm()->deadline()); + + if (i == 0) { + // Now receive an ACK of the second packet. Since there are no more + // retransmittable packets on the wire, this should cancel the path + // degrading alarm. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); + frame = InitAckFrame({{2, 3}}); + ProcessAckPacket(&frame); + EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet()); + } else { + // Advance time to the path degrading alarm's deadline and simulate + // firing the alarm. + clock_.AdvanceTime(delay); + EXPECT_CALL(visitor_, OnPathDegrading()); + connection_.GetPathDegradingAlarm()->Fire(); + EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet()); + } + } +} + +TEST_P(QuicConnectionTest, RetransmittableOnWireSetsPathDegradingAlarm) { + if (!use_path_degrading_alarm_) { + return; + } + const QuicTime::Delta retransmittable_on_wire_timeout = + QuicTime::Delta::FromMilliseconds(50); + connection_.set_retransmittable_on_wire_timeout( + retransmittable_on_wire_timeout); + + EXPECT_TRUE(connection_.connected()); + EXPECT_CALL(visitor_, HasOpenDynamicStreams()).WillRepeatedly(Return(true)); + + EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet()); + EXPECT_FALSE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + + const char data[] = "data"; + size_t data_size = strlen(data); + QuicStreamOffset offset = 0; + + // Send a packet. + connection_.SendStreamDataWithString(1, data, offset, NO_FIN); + offset += data_size; + // Now there's a retransmittable packet on the wire, so the path degrading + // alarm should be set. + // The retransmittable-on-wire alarm should not be set. + EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet()); + QuicTime::Delta delay = QuicConnectionPeer::GetSentPacketManager(&connection_) + ->GetPathDegradingDelay(); + EXPECT_EQ(clock_.ApproximateNow() + delay, + connection_.GetPathDegradingAlarm()->deadline()); + EXPECT_FALSE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + + // Now receive an ACK of the packet. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); + QuicAckFrame frame = InitAckFrame({{1, 2}}); + ProcessAckPacket(&frame); + // No more retransmittable packets on the wire, so the path degrading alarm + // should be cancelled, and the retransmittable-on-wire alarm should be set + // since a PING might be needed. + EXPECT_FALSE(connection_.GetPathDegradingAlarm()->IsSet()); + EXPECT_TRUE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout, + connection_.GetRetransmittableOnWireAlarm()->deadline()); + + // Simulate firing the retransmittable-on-wire alarm and sending a PING. + clock_.AdvanceTime(retransmittable_on_wire_timeout); + EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { + connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); + })); + connection_.GetRetransmittableOnWireAlarm()->Fire(); + + // Now there's a retransmittable packet (PING) on the wire, so the path + // degrading alarm should be set. + EXPECT_TRUE(connection_.GetPathDegradingAlarm()->IsSet()); + delay = QuicConnectionPeer::GetSentPacketManager(&connection_) + ->GetPathDegradingDelay(); + EXPECT_EQ(clock_.ApproximateNow() + delay, + connection_.GetPathDegradingAlarm()->deadline()); +} + TEST_P(QuicConnectionTest, MultipleCallsToCloseConnection) { // Verifies that multiple calls to CloseConnection do not // result in multiple attempts to close the connection - it will be marked as @@ -5741,53 +6293,195 @@ TEST_P(QuicConnectionTest, connection_.SendProbingRetransmissions(); } -TEST_P(QuicConnectionTest, HasPendingControlFramesWhenRetransmittingPackets) { - if (connection_.use_control_frame_manager()) { - // When use_control_frame_manager is true, the control frame will be - // buffered in the control frame manager. - return; - } - // This test mimics this scenario: writer get blocked when generator tries to - // add a control frame, which will be pending. When writer get unblocked, this - // pending control frame is sent in a packet before retransmissions. +TEST_P(QuicConnectionTest, PingAfterLastRetransmittablePacketAcked) { + const QuicTime::Delta retransmittable_on_wire_timeout = + QuicTime::Delta::FromMilliseconds(50); + connection_.set_retransmittable_on_wire_timeout( + retransmittable_on_wire_timeout); + + EXPECT_TRUE(connection_.connected()); + EXPECT_CALL(visitor_, HasOpenDynamicStreams()).WillRepeatedly(Return(true)); + + const char data[] = "data"; + size_t data_size = strlen(data); + QuicStreamOffset offset = 0; + + // Advance 5ms, send a retransmittable packet to the peer. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_FALSE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + connection_.SendStreamDataWithString(1, data, offset, NO_FIN); + offset += data_size; + EXPECT_FALSE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + + // Advance 5ms, send a second retransmittable packet to the peer. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_FALSE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + connection_.SendStreamDataWithString(1, data, offset, NO_FIN); + offset += data_size; + EXPECT_FALSE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + + // Now receive an ACK of the first packet. This should not set the + // retransmittable-on-wire alarm since packet 2 is still on the wire. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - QuicPacketNumber last_packet; - SendStreamDataToPeer(1, "foo", 0, NO_FIN, &last_packet); // Packet 1 - SendStreamDataToPeer(1, "foos", 3, NO_FIN, &last_packet); // Packet 2 - SendStreamDataToPeer(1, "foos", 7, NO_FIN, &last_packet); // Packet 3 - SendStreamDataToPeer(1, "foos", 11, NO_FIN, &last_packet); // Packet 4 - BlockOnNextWrite(); - connection_.SendStreamDataWithString(1, "foos", 15, NO_FIN); // Packet 5 - EXPECT_EQ(1u, connection_.NumQueuedPackets()); - EXPECT_TRUE(connection_.HasQueuedData()); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); + QuicAckFrame frame = InitAckFrame({{1, 2}}); + ProcessAckPacket(&frame); + EXPECT_FALSE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); - // This window update frame will be pending in the generator as writer is - // blocked. - connection_.SendWindowUpdate(1, 100); - // Ack 4, nack 1-3. - QuicAckFrame nack = InitAckFrame({{4, 5}}); - // 3 packets have been NACK'd and lost. - LostPacketVector lost_packets; - lost_packets.push_back(LostPacket(1, kMaxPacketSize)); - lost_packets.push_back(LostPacket(2, kMaxPacketSize)); - lost_packets.push_back(LostPacket(3, kMaxPacketSize)); + // Now receive an ACK of the second packet. This should set the + // retransmittable-on-wire alarm now that no retransmittable packets are on + // the wire. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); + frame = InitAckFrame({{2, 3}}); + ProcessAckPacket(&frame); + EXPECT_TRUE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout, + connection_.GetRetransmittableOnWireAlarm()->deadline()); + + // Now receive a duplicate ACK of the second packet. This should not update + // the retransmittable-on-wire alarm. + QuicTime prev_deadline = + connection_.GetRetransmittableOnWireAlarm()->deadline(); + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + frame = InitAckFrame({{2, 3}}); + ProcessAckPacket(&frame); + EXPECT_TRUE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + EXPECT_EQ(prev_deadline, + connection_.GetRetransmittableOnWireAlarm()->deadline()); - EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _)) - .WillOnce(SetArgPointee<4>(lost_packets)); + // Simulate the alarm firing and check that a PING is sent. + EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { + connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); + })); + connection_.GetRetransmittableOnWireAlarm()->Fire(); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(2u, writer_->frame_count()); + } else { + EXPECT_EQ(3u, writer_->frame_count()); + } + ASSERT_EQ(1u, writer_->ping_frames().size()); +} + +TEST_P(QuicConnectionTest, NoPingIfRetransmittablePacketSent) { + const QuicTime::Delta retransmittable_on_wire_timeout = + QuicTime::Delta::FromMilliseconds(50); + connection_.set_retransmittable_on_wire_timeout( + retransmittable_on_wire_timeout); + + EXPECT_TRUE(connection_.connected()); + EXPECT_CALL(visitor_, HasOpenDynamicStreams()).WillRepeatedly(Return(true)); + + const char data[] = "data"; + size_t data_size = strlen(data); + QuicStreamOffset offset = 0; + + // Advance 5ms, send a retransmittable packet to the peer. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_FALSE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + connection_.SendStreamDataWithString(1, data, offset, NO_FIN); + offset += data_size; + EXPECT_FALSE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + + // Now receive an ACK of the first packet. This should set the + // retransmittable-on-wire alarm now that no retransmittable packets are on + // the wire. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); - ProcessAckPacket(&nack); + QuicAckFrame frame = InitAckFrame({{1, 2}}); + ProcessAckPacket(&frame); + EXPECT_TRUE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout, + connection_.GetRetransmittableOnWireAlarm()->deadline()); + + // Before the alarm fires, send another retransmittable packet. This should + // cancel the retransmittable-on-wire alarm since now there's a + // retransmittable packet on the wire. + connection_.SendStreamDataWithString(1, data, offset, NO_FIN); + offset += data_size; + EXPECT_FALSE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + + // Now receive an ACK of the second packet. This should set the + // retransmittable-on-wire alarm now that no retransmittable packets are on + // the wire. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); + frame = InitAckFrame({{2, 3}}); + ProcessAckPacket(&frame); + EXPECT_TRUE(connection_.GetRetransmittableOnWireAlarm()->IsSet()); + EXPECT_EQ(clock_.ApproximateNow() + retransmittable_on_wire_timeout, + connection_.GetRetransmittableOnWireAlarm()->deadline()); - // Unblock the writer, packet 5 will be sent first, then the window update - // frame is flushed in a single packet. Finally, packets 1 - 3 are - // retransmitted. - writer_->SetWritable(); - if (connection_.session_decides_what_to_write()) { - // Stream frames 1, 2 and 3 are retransmitted in the same packet. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(3); + // Simulate the alarm firing and check that a PING is sent. + writer_->Reset(); + EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { + connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); + })); + connection_.GetRetransmittableOnWireAlarm()->Fire(); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(2u, writer_->frame_count()); } else { - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(5); + EXPECT_EQ(3u, writer_->frame_count()); } - connection_.OnCanWrite(); + ASSERT_EQ(1u, writer_->ping_frames().size()); +} + +TEST_P(QuicConnectionTest, OnForwardProgressConfirmed) { + EXPECT_CALL(visitor_, OnForwardProgressConfirmed()).Times(Exactly(0)); + EXPECT_TRUE(connection_.connected()); + + const char data[] = "data"; + size_t data_size = strlen(data); + QuicStreamOffset offset = 0; + + // Send two packets. + connection_.SendStreamDataWithString(1, data, offset, NO_FIN); + offset += data_size; + connection_.SendStreamDataWithString(1, data, offset, NO_FIN); + offset += data_size; + + // Ack packet 1. This increases the largest_acked to 1, so + // OnForwardProgressConfirmed() should be called + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); + EXPECT_CALL(visitor_, OnForwardProgressConfirmed()); + QuicAckFrame frame = InitAckFrame({{1, 2}}); + ProcessAckPacket(&frame); + + // Ack packet 1 again. largest_acked remains at 1, so + // OnForwardProgressConfirmed() should not be called. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + frame = InitAckFrame({{1, 2}}); + ProcessAckPacket(&frame); + + // Ack packet 2. This increases the largest_acked to 2, so + // OnForwardProgressConfirmed() should be called. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); + EXPECT_CALL(visitor_, OnForwardProgressConfirmed()); + frame = InitAckFrame({{2, 3}}); + ProcessAckPacket(&frame); +} + +TEST_P(QuicConnectionTest, ValidStatelessResetToken) { + const uint128 kTestToken = 1010101; + const uint128 kWrongTestToken = 1010100; + QuicConfig config; + // No token has been received. + EXPECT_FALSE(connection_.IsValidStatelessResetToken(kTestToken)); + + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(2); + // Token is different from received token. + QuicConfigPeer::SetReceivedStatelessResetToken(&config, kTestToken); + connection_.SetFromConfig(config); + EXPECT_FALSE(connection_.IsValidStatelessResetToken(kWrongTestToken)); + + QuicConfigPeer::SetReceivedStatelessResetToken(&config, kTestToken); + connection_.SetFromConfig(config); + EXPECT_TRUE(connection_.IsValidStatelessResetToken(kTestToken)); } } // namespace diff --git a/chromium/net/quic/core/quic_constants.h b/chromium/net/quic/core/quic_constants.h index 4de2bd66b45..e61b4d3d729 100644 --- a/chromium/net/quic/core/quic_constants.h +++ b/chromium/net/quic/core/quic_constants.h @@ -115,14 +115,6 @@ const int64_t kMaximumIdleTimeoutSecs = 60 * 10; // 10 minutes. // The default timeout for a connection until the crypto handshake succeeds. const int64_t kMaxTimeForCryptoHandshakeSecs = 10; // 10 secs. -// The default maximum time QUIC session could be on non-default network before -// migrate back to default network. -const int64_t kMaxTimeOnNonDefaultNetworkSecs = 128; - -// The default maximum number of migrations to non default network on path -// degrading per network. -const int64_t kMaxMigrationsToNonDefaultNetworkOnPathDegrading = 5; - // Default limit on the number of undecryptable packets the connection buffers // before the CHLO/SHLO arrive. const size_t kDefaultMaxUndecryptablePackets = 10; @@ -213,6 +205,10 @@ const QuicByteCount kMaxStreamLength = (UINT64_C(1) << 62) - 1; // The max value that can be encoded using IETF Var Ints. const uint64_t kMaxIetfVarInt = UINT64_C(0x3fffffffffffffff); + +// The maximum stream id value that is supported - (2^32)-1 +const QuicStreamId kMaxQuicStreamId = 0xffffffff; + } // namespace net #endif // NET_QUIC_CORE_QUIC_CONSTANTS_H_ diff --git a/chromium/net/quic/core/quic_control_frame_manager.cc b/chromium/net/quic/core/quic_control_frame_manager.cc index c94d7f75624..a8897fe439c 100644 --- a/chromium/net/quic/core/quic_control_frame_manager.cc +++ b/chromium/net/quic/core/quic_control_frame_manager.cc @@ -108,7 +108,7 @@ void QuicControlFrameManager::OnControlFrameSent(const QuicFrame& frame) { session_->connection()->CloseConnection( QUIC_INTERNAL_ERROR, "Try to send control frames out of order", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - RecordInternalErrorLocation(QUIC_CONTROL_FRAME_MANAGER_1); + RecordInternalErrorLocation(QUIC_CONTROL_FRAME_MANAGER_CONTROL_FRAME_SENT); return; } ++least_unsent_; @@ -125,7 +125,7 @@ bool QuicControlFrameManager::OnControlFrameAcked(const QuicFrame& frame) { session_->connection()->CloseConnection( QUIC_INTERNAL_ERROR, "Try to ack unsent control frame", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - RecordInternalErrorLocation(QUIC_CONTROL_FRAME_MANAGER_2); + RecordInternalErrorLocation(QUIC_CONTROL_FRAME_MANAGER_CONTROL_FRAME_ACKED); return false; } if (id < least_unacked_ || @@ -161,7 +161,7 @@ void QuicControlFrameManager::OnControlFrameLost(const QuicFrame& frame) { session_->connection()->CloseConnection( QUIC_INTERNAL_ERROR, "Try to mark unsent control frame as lost", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - RecordInternalErrorLocation(QUIC_CONTROL_FRAME_MANAGER_3); + RecordInternalErrorLocation(QUIC_CONTROL_FRAME_MANAGER_CONTROL_FRAME_LOST); return; } if (id < least_unacked_ || @@ -225,7 +225,8 @@ bool QuicControlFrameManager::RetransmitControlFrame(const QuicFrame& frame) { session_->connection()->CloseConnection( QUIC_INTERNAL_ERROR, "Try to retransmit unsent control frame", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - RecordInternalErrorLocation(QUIC_CONTROL_FRAME_MANAGER_4); + RecordInternalErrorLocation( + QUIC_CONTROL_FRAME_MANAGER_RETRANSMIT_CONTROL_FRAME); return false; } if (id < least_unacked_ || diff --git a/chromium/net/quic/core/quic_control_frame_manager_test.cc b/chromium/net/quic/core/quic_control_frame_manager_test.cc index bc2cc32f5a2..51a415b9f44 100644 --- a/chromium/net/quic/core/quic_control_frame_manager_test.cc +++ b/chromium/net/quic/core/quic_control_frame_manager_test.cc @@ -37,7 +37,6 @@ class QuicControlFrameManagerTest : public QuicTest { protected: void Initialize() { - SetQuicReloadableFlag(quic_use_control_frame_manager, true); connection_ = new MockQuicConnection(&helper_, &alarm_factory_, Perspective::IS_SERVER); session_ = QuicMakeUnique<StrictMock<MockQuicSession>>(connection_); diff --git a/chromium/net/quic/core/quic_crypto_client_handshaker.cc b/chromium/net/quic/core/quic_crypto_client_handshaker.cc index b6f57e4006f..0fe6c37bf80 100644 --- a/chromium/net/quic/core/quic_crypto_client_handshaker.cc +++ b/chromium/net/quic/core/quic_crypto_client_handshaker.cc @@ -328,14 +328,14 @@ void QuicCryptoClientHandshaker::DoSendCHLO( if (max_packet_size <= kFramingOverhead) { QUIC_DLOG(DFATAL) << "max_packet_length (" << max_packet_size << ") has no room for framing overhead."; - RecordInternalErrorLocation(QUIC_CRYPTO_CLIENT_HANDSHAKER_1); + RecordInternalErrorLocation(QUIC_CRYPTO_CLIENT_HANDSHAKER_MAX_PACKET); stream_->CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, "max_packet_size too smalll"); return; } if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) { QUIC_DLOG(DFATAL) << "Client hello won't fit in a single packet."; - RecordInternalErrorLocation(QUIC_CRYPTO_CLIENT_HANDSHAKER_2); + RecordInternalErrorLocation(QUIC_CRYPTO_CLIENT_HANDSHAKER_CHLO); stream_->CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, "CHLO too large"); return; @@ -384,13 +384,13 @@ void QuicCryptoClientHandshaker::DoSendCHLO( // Be prepared to decrypt with the new server write key. session()->connection()->SetAlternativeDecrypter( ENCRYPTION_INITIAL, - crypto_negotiated_params_->initial_crypters.decrypter.release(), + std::move(crypto_negotiated_params_->initial_crypters.decrypter), true /* latch once used */); // Send subsequent packets under encryption on the assumption that the // server will accept the handshake. session()->connection()->SetEncrypter( ENCRYPTION_INITIAL, - crypto_negotiated_params_->initial_crypters.encrypter.release()); + std::move(crypto_negotiated_params_->initial_crypters.encrypter)); session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); // TODO(ianswett): Merge ENCRYPTION_REESTABLISHED and @@ -644,10 +644,10 @@ void QuicCryptoClientHandshaker::DoReceiveSHLO( // with the FORWARD_SECURE key until it receives a FORWARD_SECURE // packet from the client. session()->connection()->SetAlternativeDecrypter( - ENCRYPTION_FORWARD_SECURE, crypters->decrypter.release(), + ENCRYPTION_FORWARD_SECURE, std::move(crypters->decrypter), false /* don't latch */); session()->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE, - crypters->encrypter.release()); + std::move(crypters->encrypter)); session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); handshake_confirmed_ = true; diff --git a/chromium/net/quic/core/quic_crypto_client_stream_test.cc b/chromium/net/quic/core/quic_crypto_client_stream_test.cc index c62d7528a7e..5ee199732e6 100644 --- a/chromium/net/quic/core/quic_crypto_client_stream_test.cc +++ b/chromium/net/quic/core/quic_crypto_client_stream_test.cc @@ -98,6 +98,7 @@ TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) { TEST_F(QuicCryptoClientStreamTest, ConnectedAfterTlsHandshake) { FLAGS_quic_supports_tls_handshake = true; + SetQuicReloadableFlag(delay_quic_server_handshaker_construction, true); supported_versions_.clear(); for (QuicTransportVersion transport_version : AllSupportedTransportVersions()) { diff --git a/chromium/net/quic/core/quic_crypto_server_handshaker.cc b/chromium/net/quic/core/quic_crypto_server_handshaker.cc index f80a1c91ada..351609377ec 100644 --- a/chromium/net/quic/core/quic_crypto_server_handshaker.cc +++ b/chromium/net/quic/core/quic_crypto_server_handshaker.cc @@ -225,25 +225,25 @@ void QuicCryptoServerHandshaker:: // NOTE: the SHLO will be encrypted with the new server write key. session()->connection()->SetEncrypter( ENCRYPTION_INITIAL, - crypto_negotiated_params_->initial_crypters.encrypter.release()); + std::move(crypto_negotiated_params_->initial_crypters.encrypter)); session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); // Set the decrypter immediately so that we no longer accept unencrypted // packets. session()->connection()->SetDecrypter( ENCRYPTION_INITIAL, - crypto_negotiated_params_->initial_crypters.decrypter.release()); + std::move(crypto_negotiated_params_->initial_crypters.decrypter)); session()->connection()->SetDiversificationNonce(*diversification_nonce); SendHandshakeMessage(*reply); session()->connection()->SetEncrypter( ENCRYPTION_FORWARD_SECURE, - crypto_negotiated_params_->forward_secure_crypters.encrypter.release()); + std::move(crypto_negotiated_params_->forward_secure_crypters.encrypter)); session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session()->connection()->SetAlternativeDecrypter( ENCRYPTION_FORWARD_SECURE, - crypto_negotiated_params_->forward_secure_crypters.decrypter.release(), + std::move(crypto_negotiated_params_->forward_secure_crypters.decrypter), false /* don't latch */); encryption_established_ = true; diff --git a/chromium/net/quic/core/quic_crypto_server_stream.cc b/chromium/net/quic/core/quic_crypto_server_stream.cc index 1dff1316a09..001d4ba6135 100644 --- a/chromium/net/quic/core/quic_crypto_server_stream.cc +++ b/chromium/net/quic/core/quic_crypto_server_stream.cc @@ -16,6 +16,7 @@ #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_session.h" #include "net/quic/core/tls_server_handshaker.h" +#include "net/quic/platform/api/quic_flag_utils.h" #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_ptr_util.h" @@ -171,6 +172,8 @@ void QuicCryptoServerStream::OnSuccessfulVersionNegotiation( if (!delay_handshaker_construction_) { return; } + QUIC_FLAG_COUNT( + quic_reloadable_flag_delay_quic_server_handshaker_construction); CHECK(!handshaker_); switch (session()->connection()->version().handshake_protocol) { case PROTOCOL_QUIC_CRYPTO: diff --git a/chromium/net/quic/core/quic_crypto_stream.cc b/chromium/net/quic/core/quic_crypto_stream.cc index 00c3e33d5f5..2b2e70fc893 100644 --- a/chromium/net/quic/core/quic_crypto_stream.cc +++ b/chromium/net/quic/core/quic_crypto_stream.cc @@ -23,7 +23,7 @@ namespace net { " ") QuicCryptoStream::QuicCryptoStream(QuicSession* session) - : QuicStream(kCryptoStreamId, session) { + : QuicStream(kCryptoStreamId, session, /*is_static=*/true) { // The crypto stream is exempt from connection level flow control. DisableConnectionFlowControlForThisStream(); } diff --git a/chromium/net/quic/core/quic_crypto_stream_test.cc b/chromium/net/quic/core/quic_crypto_stream_test.cc index 26429163155..01dcc63aabc 100644 --- a/chromium/net/quic/core/quic_crypto_stream_test.cc +++ b/chromium/net/quic/core/quic_crypto_stream_test.cc @@ -68,8 +68,10 @@ class QuicCryptoStreamTest : public QuicTest { : connection_(new MockQuicConnection(&helper_, &alarm_factory_, Perspective::IS_CLIENT)), - session_(connection_), - stream_(&session_) { + session_(connection_, /*create_mock_crypto_stream=*/false) { + stream_ = new MockQuicCryptoStream(&session_); + session_.SetCryptoStream(stream_); + session_.Initialize(); message_.set_tag(kSHLO); message_.SetStringPiece(1, "abc"); message_.SetStringPiece(2, "def"); @@ -87,7 +89,7 @@ class QuicCryptoStreamTest : public QuicTest { MockAlarmFactory alarm_factory_; MockQuicConnection* connection_; MockQuicSpdySession session_; - MockQuicCryptoStream stream_; + MockQuicCryptoStream* stream_; CryptoHandshakeMessage message_; std::unique_ptr<QuicData> message_data_; @@ -96,16 +98,16 @@ class QuicCryptoStreamTest : public QuicTest { }; TEST_F(QuicCryptoStreamTest, NotInitiallyConected) { - EXPECT_FALSE(stream_.encryption_established()); - EXPECT_FALSE(stream_.handshake_confirmed()); + EXPECT_FALSE(stream_->encryption_established()); + EXPECT_FALSE(stream_->handshake_confirmed()); } TEST_F(QuicCryptoStreamTest, ProcessRawData) { - stream_.OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false, - /*offset=*/0, - message_data_->AsStringPiece())); - ASSERT_EQ(1u, stream_.messages()->size()); - const CryptoHandshakeMessage& message = (*stream_.messages())[0]; + stream_->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false, + /*offset=*/0, + message_data_->AsStringPiece())); + ASSERT_EQ(1u, stream_->messages()->size()); + const CryptoHandshakeMessage& message = (*stream_->messages())[0]; EXPECT_EQ(kSHLO, message.tag()); EXPECT_EQ(2u, message.tag_value_map().size()); EXPECT_EQ("abc", crypto_test_utils::GetValueForTag(message, 1)); @@ -122,13 +124,13 @@ TEST_F(QuicCryptoStreamTest, ProcessBadData) { EXPECT_CALL(*connection_, CloseConnection(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, testing::_, testing::_)); - stream_.OnStreamFrame( + stream_->OnStreamFrame( QuicStreamFrame(kCryptoStreamId, /*fin=*/false, /*offset=*/0, bad)); } TEST_F(QuicCryptoStreamTest, NoConnectionLevelFlowControl) { EXPECT_FALSE( - QuicStreamPeer::StreamContributesToConnectionFlowControl(&stream_)); + QuicStreamPeer::StreamContributesToConnectionFlowControl(stream_)); } TEST_F(QuicCryptoStreamTest, RetransmitCryptoData) { @@ -138,21 +140,21 @@ TEST_F(QuicCryptoStreamTest, RetransmitCryptoData) { QuicString data(1350, 'a'); EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 1350, 0, _)) .WillOnce(Invoke(MockQuicSession::ConsumeData)); - stream_.WriteOrBufferData(data, false, nullptr); + stream_->WriteOrBufferData(data, false, nullptr); // Send [1350, 2700) in ENCRYPTION_INITIAL. connection_->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level()); EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 1350, 1350, _)) .WillOnce(Invoke(MockQuicSession::ConsumeData)); - stream_.WriteOrBufferData(data, false, nullptr); + stream_->WriteOrBufferData(data, false, nullptr); connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); // Lost [0, 1000). - stream_.OnStreamFrameLost(0, 1000, false); - EXPECT_TRUE(stream_.HasPendingRetransmission()); + stream_->OnStreamFrameLost(0, 1000, false); + EXPECT_TRUE(stream_->HasPendingRetransmission()); // Lost [1200, 2000). - stream_.OnStreamFrameLost(1200, 800, false); + stream_->OnStreamFrameLost(1200, 800, false); EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 1000, 0, _)) .WillOnce(Invoke(MockQuicSession::ConsumeData)); // Verify [1200, 2000) are sent in [1200, 1350) and [1350, 2000) because of @@ -161,8 +163,8 @@ TEST_F(QuicCryptoStreamTest, RetransmitCryptoData) { .WillOnce(Invoke(MockQuicSession::ConsumeData)); EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 650, 1350, _)) .WillOnce(Invoke(MockQuicSession::ConsumeData)); - stream_.OnCanWrite(); - EXPECT_FALSE(stream_.HasPendingRetransmission()); + stream_->OnCanWrite(); + EXPECT_FALSE(stream_->HasPendingRetransmission()); // Verify connection's encryption level has restored. EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); } @@ -173,29 +175,29 @@ TEST_F(QuicCryptoStreamTest, NeuterUnencryptedStreamData) { QuicString data(1350, 'a'); EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 1350, 0, _)) .WillOnce(Invoke(MockQuicSession::ConsumeData)); - stream_.WriteOrBufferData(data, false, nullptr); + stream_->WriteOrBufferData(data, false, nullptr); // Send [1350, 2700) in ENCRYPTION_INITIAL. connection_->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level()); EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 1350, 1350, _)) .WillOnce(Invoke(MockQuicSession::ConsumeData)); - stream_.WriteOrBufferData(data, false, nullptr); + stream_->WriteOrBufferData(data, false, nullptr); // Lost [0, 1350). - stream_.OnStreamFrameLost(0, 1350, false); - EXPECT_TRUE(stream_.HasPendingRetransmission()); + stream_->OnStreamFrameLost(0, 1350, false); + EXPECT_TRUE(stream_->HasPendingRetransmission()); // Neuters [0, 1350). - stream_.NeuterUnencryptedStreamData(); - EXPECT_FALSE(stream_.HasPendingRetransmission()); + stream_->NeuterUnencryptedStreamData(); + EXPECT_FALSE(stream_->HasPendingRetransmission()); // Lost [0, 1350) again. - stream_.OnStreamFrameLost(0, 1350, false); - EXPECT_FALSE(stream_.HasPendingRetransmission()); + stream_->OnStreamFrameLost(0, 1350, false); + EXPECT_FALSE(stream_->HasPendingRetransmission()); // Lost [1350, 2000). - stream_.OnStreamFrameLost(1350, 650, false); - EXPECT_TRUE(stream_.HasPendingRetransmission()); - stream_.NeuterUnencryptedStreamData(); - EXPECT_TRUE(stream_.HasPendingRetransmission()); + stream_->OnStreamFrameLost(1350, 650, false); + EXPECT_TRUE(stream_->HasPendingRetransmission()); + stream_->NeuterUnencryptedStreamData(); + EXPECT_TRUE(stream_->HasPendingRetransmission()); } TEST_F(QuicCryptoStreamTest, RetransmitStreamData) { @@ -205,27 +207,27 @@ TEST_F(QuicCryptoStreamTest, RetransmitStreamData) { QuicString data(1350, 'a'); EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 1350, 0, _)) .WillOnce(Invoke(MockQuicSession::ConsumeData)); - stream_.WriteOrBufferData(data, false, nullptr); + stream_->WriteOrBufferData(data, false, nullptr); // Send [1350, 2700) in ENCRYPTION_INITIAL. connection_->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level()); EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 1350, 1350, _)) .WillOnce(Invoke(MockQuicSession::ConsumeData)); - stream_.WriteOrBufferData(data, false, nullptr); + stream_->WriteOrBufferData(data, false, nullptr); connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); // Ack [2000, 2500). - stream_.OnStreamFrameAcked(2000, 500, false, QuicTime::Delta::Zero()); + stream_->OnStreamFrameAcked(2000, 500, false, QuicTime::Delta::Zero()); // Force crypto stream to send [1350, 2700) and only [1350, 1500) is consumed. EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 650, 1350, _)) .WillOnce(InvokeWithoutArgs([this]() { - return MockQuicSession::ConsumeData(&stream_, kCryptoStreamId, 150, - 1350, NO_FIN); + return MockQuicSession::ConsumeData(stream_, kCryptoStreamId, 150, 1350, + NO_FIN); })); - EXPECT_FALSE(stream_.RetransmitStreamData(1350, 1350, false)); + EXPECT_FALSE(stream_->RetransmitStreamData(1350, 1350, false)); // Verify connection's encryption level has restored. EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); @@ -234,13 +236,13 @@ TEST_F(QuicCryptoStreamTest, RetransmitStreamData) { .WillOnce(Invoke(MockQuicSession::ConsumeData)); EXPECT_CALL(session_, WritevData(_, kCryptoStreamId, 200, 2500, _)) .WillOnce(Invoke(MockQuicSession::ConsumeData)); - EXPECT_TRUE(stream_.RetransmitStreamData(1350, 1350, false)); + EXPECT_TRUE(stream_->RetransmitStreamData(1350, 1350, false)); // Verify connection's encryption level has restored. EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); EXPECT_CALL(session_, WritevData(_, _, _, _, _)).Times(0); // Force to send an empty frame. - EXPECT_TRUE(stream_.RetransmitStreamData(0, 0, false)); + EXPECT_TRUE(stream_->RetransmitStreamData(0, 0, false)); } } // namespace diff --git a/chromium/net/quic/core/quic_data_reader.cc b/chromium/net/quic/core/quic_data_reader.cc index 913d3749217..e6c07e8d206 100644 --- a/chromium/net/quic/core/quic_data_reader.cc +++ b/chromium/net/quic/core/quic_data_reader.cc @@ -4,7 +4,6 @@ #include "net/quic/core/quic_data_reader.h" -#include "net/base/int128.h" #include "net/quic/core/quic_packets.h" #include "net/quic/core/quic_utils.h" #include "net/quic/platform/api/quic_bug_tracker.h" @@ -267,4 +266,17 @@ bool QuicDataReader::ReadVarInt62(uint64_t* result) { return false; } +bool QuicDataReader::ReadVarIntStreamId(QuicStreamId* result) { + uint64_t temp_uint64; + // TODO(fkastenholz): We should disambiguate read-errors from + // value errors. + if (!this->ReadVarInt62(&temp_uint64)) { + return false; + } + if (temp_uint64 > kMaxQuicStreamId) { + return false; + } + *result = static_cast<QuicStreamId>(temp_uint64); + return true; +} } // namespace net diff --git a/chromium/net/quic/core/quic_data_reader.h b/chromium/net/quic/core/quic_data_reader.h index cbd23ba8530..f59e5496864 100644 --- a/chromium/net/quic/core/quic_data_reader.h +++ b/chromium/net/quic/core/quic_data_reader.h @@ -9,7 +9,6 @@ #include <cstdint> #include "base/macros.h" -#include "net/base/int128.h" #include "net/quic/core/quic_types.h" #include "net/quic/platform/api/quic_endian.h" #include "net/quic/platform/api/quic_export.h" @@ -131,10 +130,16 @@ class QUIC_EXPORT_PRIVATE QuicDataReader { // Returns true if it works, false if not. The only error is that // there is not enough in the buffer to read the number. // If there is an error, |*result| is not altered. - // Numbers are encoded per the rules in draft-ietf-quic-transport-08.txt + // Numbers are encoded per the rules in draft-ietf-quic-transport-10.txt // and that the integers in the range 0 ... (2^62)-1. bool ReadVarInt62(uint64_t* result); + // Convenience method that reads a StreamId. + // Atempts to read a Stream ID into |result| using ReadVarInt62 and + // returns false if there is a read error or if the value is + // greater than (2^32)-1. + bool ReadVarIntStreamId(QuicStreamId* result); + private: // Returns true if the underlying buffer has enough room to read the given // amount of bytes. diff --git a/chromium/net/quic/core/quic_data_writer.h b/chromium/net/quic/core/quic_data_writer.h index b87d151267c..79d05e74c4a 100644 --- a/chromium/net/quic/core/quic_data_writer.h +++ b/chromium/net/quic/core/quic_data_writer.h @@ -9,7 +9,6 @@ #include <cstdint> #include "base/macros.h" -#include "net/base/int128.h" #include "net/quic/core/quic_packets.h" #include "net/quic/platform/api/quic_endian.h" #include "net/quic/platform/api/quic_export.h" diff --git a/chromium/net/quic/core/quic_data_writer_test.cc b/chromium/net/quic/core/quic_data_writer_test.cc index 3e8540c2dfc..f2d8b2d7088 100644 --- a/chromium/net/quic/core/quic_data_writer_test.cc +++ b/chromium/net/quic/core/quic_data_writer_test.cc @@ -916,6 +916,49 @@ TEST_P(QuicDataWriterTest, MultiVarInt1) { EXPECT_FALSE(reader.ReadVarInt62(&test_val)); } +// Test encoding/decoding stream-id values. +void EncodeDecodeStreamId(uint64_t value_in, bool expected_decode_result) { + char buffer[1 * kMultiVarCount]; + memset(buffer, 0, sizeof(buffer)); + + // Encode the given Stream ID. + QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), + Endianness::NETWORK_BYTE_ORDER); + EXPECT_TRUE(writer.WriteVarInt62(value_in)); + + QuicDataReader reader(buffer, sizeof(buffer), Endianness::NETWORK_BYTE_ORDER); + QuicStreamId received_stream_id; + bool read_result = reader.ReadVarIntStreamId(&received_stream_id); + EXPECT_EQ(expected_decode_result, read_result); + if (read_result) { + EXPECT_EQ(value_in, received_stream_id); + } +} + +// Test writing & reading stream-ids of various value. +TEST_P(QuicDataWriterTest, StreamId1) { + // Check a 1-byte QuicStreamId, should work + EncodeDecodeStreamId(UINT64_C(0x15), true); + + // Check a 2-byte QuicStream ID. It should work. + EncodeDecodeStreamId(UINT64_C(0x1567), true); + + // Check a QuicStreamId that requires 4 bytes of encoding + // This should work. + EncodeDecodeStreamId(UINT64_C(0x34567890), true); + + // Check a QuicStreamId that requires 8 bytes of encoding + // but whose value is in the acceptable range. + // This should work. + EncodeDecodeStreamId(UINT64_C(0xf4567890), true); + + // Check QuicStreamIds that require 8 bytes of encoding + // and whose value is not acceptable. + // This should fail. + EncodeDecodeStreamId(UINT64_C(0x100000000), false); + EncodeDecodeStreamId(UINT64_C(0x3fffffffffffffff), false); +} + } // namespace } // namespace test } // namespace net diff --git a/chromium/net/quic/core/quic_error_codes.h b/chromium/net/quic/core/quic_error_codes.h index d79970d811c..88fcca8f2f4 100644 --- a/chromium/net/quic/core/quic_error_codes.h +++ b/chromium/net/quic/core/quic_error_codes.h @@ -295,34 +295,35 @@ QUIC_EXPORT_PRIVATE const char* QuicRstStreamErrorCodeToString( QuicRstStreamErrorCode error); // Returns the name of the QuicErrorCode as a char* -QUIC_EXPORT_PRIVATE const char* QuicErrorCodeToString(QuicErrorCode error); +QUIC_EXPORT const char* QuicErrorCodeToString(QuicErrorCode error); // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. // TODO(rch): Remove this once the cause of the INTERNAL_ERROR increase is // determined. enum QuicInternalErrorLocation { - QUIC_CHROMIUM_CLIENT_SESSION = 0, - QUIC_CONNECTION_1 = 1, - QUIC_CONNECTION_2 = 2, - QUIC_CONNECTION_3 = 3, - QUIC_CONNECTION_4 = 4, - QUIC_CONTROL_FRAME_MANAGER_1 = 5, - QUIC_CONTROL_FRAME_MANAGER_2 = 6, - QUIC_CONTROL_FRAME_MANAGER_3 = 7, - QUIC_CONTROL_FRAME_MANAGER_4 = 8, - QUIC_CRYPTO_CLIENT_HANDSHAKER_1 = 9, - QUIC_CRYPTO_CLIENT_HANDSHAKER_2 = 10, + QUIC_CHROMIUM_CLIENT_SESSION_DESTRUCTOR = 0, + QUIC_CONNECTION_PROTOCOL_VERSION_MISMATCH = 1, + QUIC_CONNECTION_VERSION_NEGOTIATION_PACKET = 2, + QUIC_CONNECTION_UNAUTHENTICATED_HEADER = 3, + QUIC_CONNECTION_WRITE_PACKET = 4, + QUIC_CONTROL_FRAME_MANAGER_CONTROL_FRAME_SENT = 5, + QUIC_CONTROL_FRAME_MANAGER_CONTROL_FRAME_ACKED = 6, + QUIC_CONTROL_FRAME_MANAGER_CONTROL_FRAME_LOST = 7, + QUIC_CONTROL_FRAME_MANAGER_RETRANSMIT_CONTROL_FRAME = 8, + QUIC_CRYPTO_CLIENT_HANDSHAKER_MAX_PACKET = 9, + QUIC_CRYPTO_CLIENT_HANDSHAKER_CHLO = 10, QUIC_ERROR_CODES = 11, QUIC_FRAMER = 12, QUIC_HEADERS_STREAM = 13, - QUIC_SESSION_1 = 14, - QUIC_SESSION_2 = 15, - QUIC_SESSION_3 = 16, + QUIC_SESSION_ON_CAN_WRITE = 14, + QUIC_SESSION_WRITEV_DATA = 15, + QUIC_SESSION_STREAM_FRAME_RETRANSMITTED = 16, QUIC_SPDY_SESSION = 17, - QUIC_STREAM_1 = 18, - QUIC_STREAM_2 = 19, + QUIC_STREAM_ACKED_UNSENT_DATA = 18, + QUIC_STREAM_ACKED_UNSENT_FIN = 19, QUIC_STREAM_SEQUENCER_BUFFER = 20, + QUIC_CHROMIUM_CLIENT_SESSION_CLOSE_SESSION_ON_ERROR = 21, INTERNAL_ERROR_LOCATION_MAX }; diff --git a/chromium/net/quic/core/quic_flags_list.h b/chromium/net/quic/core/quic_flags_list.h index 53c55c2f8df..25235a77f14 100644 --- a/chromium/net/quic/core/quic_flags_list.h +++ b/chromium/net/quic/core/quic_flags_list.h @@ -3,7 +3,9 @@ // found in the LICENSE file. // This file intentionally does not have header guards, it's included -// inside a macro to generate values. +// inside a macro to generate values. The following line silences a +// presubmit warning that would otherwise be triggered by this: +// no-include-guard-because-multiply-included // This file contains the list of QUIC protocol flags. @@ -96,10 +98,6 @@ QUIC_FLAG(uint32_t, FLAGS_quic_send_buffer_max_data_slice_size, 4096u) // protocol. QUIC_FLAG(bool, FLAGS_quic_supports_tls_handshake, false) -// If true, QUIC can take ownership of data provided in a reference counted -// memory to avoid data copy. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_mem_slices, false) - // Allow QUIC to accept initial packet numbers that are random, not 1. QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_enable_accept_random_ipn, false) @@ -116,65 +114,133 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_stream_too_long, false) // TLP instead of 2. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_one_tlp, false) -// If true, QuicStreamSendBuffer keeps track of the slice which next write -// should get data from if writing new data. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_write_index, true) - -// If true, when WINDOW_UPDATE is received, add stream to session's write -// blocked list and let session unblock it later. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_streams_unblocked_by_session2, - false) - -// If true, inspects CHLO packets for indicator tags to allow early session -// creation. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_inspect_chlo_tags, true) - -// When true, ignore the specified ack delay if it causes the RTT sample to be -// less than min_rtt. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_min_rtt_ack_delay, true) - -// If true, plugin control frame manager to QuicSession, and let it manage sent -// control frames. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_control_frame_manager, true) // When true, allows two connection options to run experiments with using max // ack delay as described in QUIC IETF. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_max_ack_delay, false) -// If ture, sender will close connection when there are too many outstanding -// sent packets -QUIC_FLAG( - bool, - FLAGS_quic_reloadable_flag_quic_close_session_on_too_many_outstanding_sent_packets, - false) - // If true, enable QUIC v99. QUIC_FLAG(bool, FLAGS_quic_enable_version_99, false) // If true, enable QUIC version 42. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_42_2, false) +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_42_2, true) -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_37, false) -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_38, false) +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_37, true) +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_38, true) QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_41, false) // Delays construction of QuicCryptoServerStream::HandshakerDelegate // until QuicCryptoServerStream::OnSuccessfulVersionNegotiation is called QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_delay_quic_server_handshaker_construction, - false) + true) // Controls whether QuicConnection::OnProtocolVersionMismatch calls // QuicFramer::set_version before or after calling // OnSuccessfulVersionNegotiation. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_store_version_before_signalling, - false) + true) // When true, enable connection options to have no min TLP and RTO, // and also allow IETF style TLP. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_max_ack_delay2, false) +// If true, MemSlices in the send buffer is freed out of order. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_free_mem_slice_out_of_order, + false) + // If true, framer will process and report ack frame incrementally. QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_use_incremental_ack_processing, - false)
\ No newline at end of file + FLAGS_quic_reloadable_flag_quic_use_incremental_ack_processing3, + false) + +// If true, Http2FrameDecoderAdapter will pass decoded HTTP/2 SETTINGS through +// the SpdyFramerVisitorInterface callback OnSetting(), which will also accept +// unknown SETTINGS IDs. +QUIC_FLAG(bool, FLAGS_quic_restart_flag_http2_propagate_unknown_settings, true) + +// If true, enable fast path in QuicStream::OnStreamDataAcked. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_fast_path_on_stream_data_acked, + false) + +// If true, fix a use-after-free bug caused by writing an out-of-order queued +// packet. +QUIC_FLAG( + bool, + FLAGS_quic_reloadable_flag_quic_fix_write_out_of_order_queued_packet_crash, + true) + +// If true, QUIC streams are registered in the QuicStream constructor instead +// of in the QuicSpdyStream constructor. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_register_streams_early2, true) + +// If this flag and +// FLAGS_quic_reloadable_flag_quic_fix_write_out_of_order_queued_packet_crash +// are both ture, QUIC will clear queued packets before sending connectivity +// probing packets. +QUIC_FLAG( + bool, + FLAGS_quic_reloadable_flag_quic_clear_queued_packets_before_sending_connectivity_probing, + false) + +// When true, this flag has QuicConnection call +// QuicConnectionVisitorInterface::OnSuccessfulVersionNegotiation earlier when +// processing the packet header. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_server_early_version_negotiation, + false) + +// If true, QUIC will always discard outgoing packets after connection close. +// Currently out-of-order outgoing packets are not discarded +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_always_discard_packets_after_close, + false) + +// If true, stop sending a redundant PING every 20 acks. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_remove_redundant_ping, true) + +// If true, when a stream is reset by peer with error, it should not be added to +// zombie streams. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_reset_stream_is_not_zombie, + true) + +// If true, when a packet write for connectivity probe does not complete +// successfully synchronously, connection will not be affected, i.e., blocked or +// closed, if the probing packet writer is not the default writer. +QUIC_FLAG( + bool, + FLAGS_quic_reloadable_flag_quic_handle_write_results_for_connectivity_probe, + true) + +// If true, a separate QuicAlarm in QuicConnection is used to trigger +// OnPathDegrading() instead of using retransmission_alarm_. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_path_degrading_alarm, true) + +// Remove special logic for headers stream from QuicWriteBlockedList and +// replace it with a static streams map. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_register_static_streams, false) + +// Base the QUIC crypto retransmission timer on the last sent crypto packet. +QUIC_FLAG(bool, + FLAGS_quic_reloadable_flag_quic_better_crypto_retransmission, + false) + +// If true, enable server proxy support in QUIC. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_server_proxy, false) + +// If true, compare offset with last byte acked to determine whether it is +// disjoint before calling IntervalSet::IsDisjoint. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fast_is_disjoint, false) + +// If true, enable fast path in QuicStreamSequencerBuffer::OnStreamData. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fast_path_on_stream_data, false) + +// When true, set the initial congestion control window from connection options +// in QuicSentPacketManager rather than TcpCubicSenderBytes. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_unified_iw_options, false) + +// If true, check again that the writer isn\'t blocked before calling +// QuicConnection::OnCanWrite from WriteAndBundleAcksIfNotBlocked +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_is_write_blocked, true) diff --git a/chromium/net/quic/core/quic_flow_controller.cc b/chromium/net/quic/core/quic_flow_controller.cc index 91f0c9f2889..a5e18a6faea 100644 --- a/chromium/net/quic/core/quic_flow_controller.cc +++ b/chromium/net/quic/core/quic_flow_controller.cc @@ -231,11 +231,7 @@ void QuicFlowController::MaybeSendBlocked() { << ", send limit: " << send_window_offset_; // The entire send_window has been consumed, we are now flow control // blocked. - if (session_->use_control_frame_manager()) { - session_->SendBlocked(id_); - } else { - connection_->SendBlocked(id_); - } + session_->SendBlocked(id_); // Keep track of when we last sent a BLOCKED frame so that we only send one // at a given send offset. @@ -298,11 +294,7 @@ void QuicFlowController::UpdateReceiveWindowSize(QuicStreamOffset size) { } void QuicFlowController::SendWindowUpdate() { - if (session_->use_control_frame_manager()) { - session_->SendWindowUpdate(id_, receive_window_offset_); - return; - } - connection_->SendWindowUpdate(id_, receive_window_offset_); + session_->SendWindowUpdate(id_, receive_window_offset_); } } // namespace net diff --git a/chromium/net/quic/core/quic_flow_controller_test.cc b/chromium/net/quic/core/quic_flow_controller_test.cc index e50281707d4..aedc076f016 100644 --- a/chromium/net/quic/core/quic_flow_controller_test.cc +++ b/chromium/net/quic/core/quic_flow_controller_test.cc @@ -81,11 +81,7 @@ TEST_F(QuicFlowControllerTest, SendingBytes) { EXPECT_EQ(0u, flow_controller_->SendWindowSize()); // BLOCKED frame should get sent. - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); - } else { - EXPECT_CALL(*connection_, SendBlocked(stream_id_)).Times(1); - } + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); flow_controller_->MaybeSendBlocked(); // Update the send window, and verify this has unblocked. @@ -124,12 +120,7 @@ TEST_F(QuicFlowControllerTest, ReceivingBytes) { QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get())); // Consume enough bytes to send a WINDOW_UPDATE frame. - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); - } else { - EXPECT_CALL(*connection_, SendWindowUpdate(stream_id_, ::testing::_)) - .Times(1); - } + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); flow_controller_->AddBytesConsumed(1 + receive_window_ / 2); @@ -154,14 +145,9 @@ TEST_F(QuicFlowControllerTest, OnlySendBlockedFrameOncePerOffset) { EXPECT_EQ(0u, flow_controller_->SendWindowSize()); // Expect that 2 BLOCKED frames should get sent in total. - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(2) - .WillRepeatedly( - Invoke(this, &QuicFlowControllerTest::ClearControlFrame)); - } else { - EXPECT_CALL(*connection_, SendBlocked(stream_id_)).Times(2); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(2) + .WillRepeatedly(Invoke(this, &QuicFlowControllerTest::ClearControlFrame)); // BLOCKED frame should get sent. flow_controller_->MaybeSendBlocked(); @@ -189,12 +175,7 @@ TEST_F(QuicFlowControllerTest, ReceivingBytesFastIncreasesFlowWindow) { should_auto_tune_receive_window_ = true; Initialize(); // This test will generate two WINDOW_UPDATE frames. - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); - } else { - EXPECT_CALL(*connection_, SendWindowUpdate(stream_id_, ::testing::_)) - .Times(1); - } + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); EXPECT_TRUE(flow_controller_->auto_tune_receive_window()); // Make sure clock is inititialized. @@ -246,15 +227,9 @@ TEST_F(QuicFlowControllerTest, ReceivingBytesFastIncreasesFlowWindow) { TEST_F(QuicFlowControllerTest, ReceivingBytesFastNoAutoTune) { Initialize(); // This test will generate two WINDOW_UPDATE frames. - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(2) - .WillRepeatedly( - Invoke(this, &QuicFlowControllerTest::ClearControlFrame)); - } else { - EXPECT_CALL(*connection_, SendWindowUpdate(stream_id_, ::testing::_)) - .Times(2); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(2) + .WillRepeatedly(Invoke(this, &QuicFlowControllerTest::ClearControlFrame)); EXPECT_FALSE(flow_controller_->auto_tune_receive_window()); // Make sure clock is inititialized. @@ -307,12 +282,7 @@ TEST_F(QuicFlowControllerTest, ReceivingBytesNormalStableFlowWindow) { should_auto_tune_receive_window_ = true; Initialize(); // This test will generate two WINDOW_UPDATE frames. - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); - } else { - EXPECT_CALL(*connection_, SendWindowUpdate(stream_id_, ::testing::_)) - .Times(1); - } + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); EXPECT_TRUE(flow_controller_->auto_tune_receive_window()); // Make sure clock is inititialized. @@ -367,15 +337,9 @@ TEST_F(QuicFlowControllerTest, ReceivingBytesNormalStableFlowWindow) { TEST_F(QuicFlowControllerTest, ReceivingBytesNormalNoAutoTune) { Initialize(); // This test will generate two WINDOW_UPDATE frames. - if (connection_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(2) - .WillRepeatedly( - Invoke(this, &QuicFlowControllerTest::ClearControlFrame)); - } else { - EXPECT_CALL(*connection_, SendWindowUpdate(stream_id_, ::testing::_)) - .Times(2); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(2) + .WillRepeatedly(Invoke(this, &QuicFlowControllerTest::ClearControlFrame)); EXPECT_FALSE(flow_controller_->auto_tune_receive_window()); // Make sure clock is inititialized. diff --git a/chromium/net/quic/core/quic_framer.cc b/chromium/net/quic/core/quic_framer.cc index 45e6035beb8..7c0a19a3ff1 100644 --- a/chromium/net/quic/core/quic_framer.cc +++ b/chromium/net/quic/core/quic_framer.cc @@ -32,6 +32,7 @@ #include "net/quic/platform/api/quic_string.h" #include "net/quic/platform/api/quic_text_utils.h" +using std::string; namespace net { @@ -172,6 +173,7 @@ QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions, largest_packet_number_(0), last_serialized_connection_id_(0), last_version_label_(0), + last_packet_is_ietf_quic_(false), version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED), supported_versions_(supported_versions), decrypter_level_(ENCRYPTION_NONE), @@ -183,9 +185,9 @@ QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions, last_timestamp_(QuicTime::Delta::Zero()), data_producer_(nullptr), use_incremental_ack_processing_( - GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { + GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { if (use_incremental_ack_processing_) { - QUIC_FLAG_COUNT(quic_reloadable_flag_quic_use_incremental_ack_processing); + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_use_incremental_ack_processing3); } DCHECK(!supported_versions.empty()); version_ = supported_versions_[0]; @@ -557,6 +559,7 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildPublicResetPacket( // static std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildVersionNegotiationPacket( QuicConnectionId connection_id, + bool ietf_quic, const ParsedQuicVersionVector& versions) { DCHECK(!versions.empty()); size_t len = GetVersionNegotiationPacketSize(versions.size()); @@ -592,6 +595,7 @@ std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildVersionNegotiationPacket( bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) { QuicDataReader reader(packet.data(), packet.length(), endianness()); + last_packet_is_ietf_quic_ = false; visitor_->OnPacket(); QuicPacketHeader header; @@ -1091,7 +1095,7 @@ bool QuicFramer::ProcessFrameData(QuicDataReader* reader, ((frame_type & kQuicFrameTypeSpecialMask) == kQuicFrameTypeAckMask))) { // TODO(fayang): Remove frame when deprecating - // quic_reloadable_flag_quic_use_incremental_ack_processing. + // quic_reloadable_flag_quic_use_incremental_ack_processing3. QuicAckFrame frame; if (!ProcessAckFrame(reader, frame_type, &frame)) { return RaiseError(QUIC_INVALID_ACK_DATA); @@ -1341,25 +1345,17 @@ bool QuicFramer::ProcessIetfStreamFrame(QuicDataReader* reader, uint8_t frame_type, QuicStreamFrame* frame) { // Read stream id from the frame. It's always present. - QuicIetfStreamId streamid; - if (!reader->ReadVarInt62(&streamid)) { + if (!reader->ReadVarIntStreamId(&frame->stream_id)) { set_detailed_error("Unable to read stream_id."); return false; } - if (streamid > 0xffffffff) { - set_detailed_error("stream_id is too large."); - return false; - } - frame->stream_id = static_cast<QuicStreamId>(streamid); // If we have a data offset, read it. If not, set to 0. if (frame_type & IETF_STREAM_FRAME_OFF_BIT) { - QuicStreamOffset offset; - if (!reader->ReadVarInt62(&offset)) { + if (!reader->ReadVarInt62(&frame->offset)) { set_detailed_error("Unable to read stream data offset."); return false; } - frame->offset = offset; } else { // no offset in the frame, ensure it's 0 in the Frame. frame->offset = 0; @@ -1373,7 +1369,7 @@ bool QuicFramer::ProcessIetfStreamFrame(QuicDataReader* reader, return false; } if (length > 0xffff) { - set_detailed_error("stream data offset is too large."); + set_detailed_error("Stream data length is too large."); return false; } frame->data_length = length; @@ -1593,8 +1589,8 @@ bool QuicFramer::ProcessTimestampsInAckFrame(uint8_t num_received_packets, last_timestamp_ = CalculateTimestampFromWire(time_delta_us); ack_frame->received_packet_times.reserve(num_received_packets); - ack_frame->received_packet_times.push_back( - std::make_pair(seq_num, creation_time_ + last_timestamp_)); + ack_frame->received_packet_times.emplace_back( + seq_num, creation_time_ + last_timestamp_); for (uint8_t i = 1; i < num_received_packets; ++i) { if (!reader->ReadUInt8(&delta_from_largest_observed)) { @@ -1614,8 +1610,8 @@ bool QuicFramer::ProcessTimestampsInAckFrame(uint8_t num_received_packets, last_timestamp_ = last_timestamp_ + QuicTime::Delta::FromMicroseconds( incremental_time_delta_us); - ack_frame->received_packet_times.push_back( - std::make_pair(seq_num, creation_time_ + last_timestamp_)); + ack_frame->received_packet_times.emplace_back( + seq_num, creation_time_ + last_timestamp_); } } return true; @@ -1771,7 +1767,7 @@ bool QuicFramer::ProcessConnectionCloseFrame(QuicDataReader* reader, set_detailed_error("Unable to read connection close error details."); return false; } - frame->error_details = error_details.as_string(); + frame->error_details = string(error_details); return true; } @@ -1802,7 +1798,7 @@ bool QuicFramer::ProcessGoAwayFrame(QuicDataReader* reader, set_detailed_error("Unable to read goaway reason."); return false; } - frame->reason_phrase = reason_phrase.as_string(); + frame->reason_phrase = string(reason_phrase); return true; } @@ -1865,17 +1861,19 @@ QuicStringPiece QuicFramer::GetAssociatedDataFromEncryptedPacket( packet_number_length)); } -void QuicFramer::SetDecrypter(EncryptionLevel level, QuicDecrypter* decrypter) { +void QuicFramer::SetDecrypter(EncryptionLevel level, + std::unique_ptr<QuicDecrypter> decrypter) { DCHECK(alternative_decrypter_ == nullptr); DCHECK_GE(level, decrypter_level_); - decrypter_.reset(decrypter); + decrypter_ = std::move(decrypter); decrypter_level_ = level; } -void QuicFramer::SetAlternativeDecrypter(EncryptionLevel level, - QuicDecrypter* decrypter, - bool latch_once_used) { - alternative_decrypter_.reset(decrypter); +void QuicFramer::SetAlternativeDecrypter( + EncryptionLevel level, + std::unique_ptr<QuicDecrypter> decrypter, + bool latch_once_used) { + alternative_decrypter_ = std::move(decrypter); alternative_decrypter_level_ = level; alternative_decrypter_latch_ = latch_once_used; } @@ -1888,10 +1886,11 @@ const QuicDecrypter* QuicFramer::alternative_decrypter() const { return alternative_decrypter_.get(); } -void QuicFramer::SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter) { +void QuicFramer::SetEncrypter(EncryptionLevel level, + std::unique_ptr<QuicEncrypter> encrypter) { DCHECK_GE(level, 0); DCHECK_LT(level, NUM_ENCRYPTION_LEVELS); - encrypter_[level].reset(encrypter); + encrypter_[level] = std::move(encrypter); } size_t QuicFramer::EncryptInPlace(EncryptionLevel level, @@ -2304,20 +2303,20 @@ bool QuicFramer::AppendIetfStreamFrame(const QuicStreamFrame& frame, } // Put the type-byte in the header. - if (writer->WriteUInt8(frame_type) == false) { + if (!writer->WriteUInt8(frame_type)) { set_detailed_error("Unable to write frame-type."); return false; } // Stream ID always goes in the header... - if (writer->WriteVarInt62(static_cast<uint64_t>(frame.stream_id)) == false) { + if (!writer->WriteVarInt62(static_cast<uint64_t>(frame.stream_id))) { set_detailed_error("Writing stream id failed."); return false; } // Offset may go in the header... if (frame_type & IETF_STREAM_FRAME_OFF_BIT) { - if (writer->WriteVarInt62(static_cast<uint64_t>(frame.offset)) == false) { + if (!writer->WriteVarInt62(static_cast<uint64_t>(frame.offset))) { set_detailed_error("Writing data offset failed."); return false; } @@ -2325,7 +2324,7 @@ bool QuicFramer::AppendIetfStreamFrame(const QuicStreamFrame& frame, // Frame data length... if (frame_type & IETF_STREAM_FRAME_LEN_BIT) { - if (writer->WriteVarInt62(frame.data_length) == false) { + if (!writer->WriteVarInt62(frame.data_length)) { set_detailed_error("Writing data length failed."); return false; } @@ -2621,6 +2620,7 @@ bool QuicFramer::AppendStopWaitingFrame(const QuicPacketHeader& header, return true; } + // Append IETF Format Ack Frame. The IETF Ack Frame format is, basically, // Largest Ack'ed // ACK Delay @@ -2633,8 +2633,8 @@ bool QuicFramer::AppendStopWaitingFrame(const QuicPacketHeader& header, // 1-packet-acked, 1-packet-gap, 1-packet-acked & the first // packet has seq# LargestAcked, the last one has seq# LargestAcked-4. -bool QuicFramer::AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame, - QuicDataWriter* writer) { +bool QuicFramer::AppendIetfAckFrame(const QuicAckFrame& frame, + QuicDataWriter* writer) { if (!writer->WriteUInt8(IETF_ACK)) { set_detailed_error("No room for frame-type"); return false; @@ -2654,40 +2654,33 @@ bool QuicFramer::AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame, DCHECK_LE(0u, frame.ack_delay_time.ToMicroseconds()); ack_delay_time_us = frame.ack_delay_time.ToMicroseconds(); - // TODO(fkastenholz) when we get real IETF QUIC, need to get - // the currect shift from the transport parameters. + // TODO(fkastenholz): Use the shift from TLS transport parameters. ack_delay_time_us = ack_delay_time_us >> kIetfAckTimestampShift; if (!writer->WriteVarInt62(ack_delay_time_us)) { set_detailed_error("No room for ack-delay in ack frame"); return false; } - // Do the block-count uint64_t ack_block_count = frame.packets.NumIntervals(); if (ack_block_count == 0) { QUIC_BUG << "Trying to build an ack frame with no ack blocks"; return false; } - // Calculate the block count we will put into the frame. - // ID says the value is "The number of Additional ACK Block (and - // Gap) fields after the First ACK Block." We interpret this as - // - n(==0) means just the First ACK Block - // - n(>0) means a First Ack block followed by N pairs - // of Gap/Ack. So if N is 1, there is a First, - // a Gap, and a final Ack. + // Subtract 1 from the block count when writing because the specification + // does not allow for 0 blocks. if (!writer->WriteVarInt62(ack_block_count - 1)) { set_detailed_error("No room for ack block count in ack frame"); return false; } - auto itr = frame.packets.rbegin(); // first range - // Do the first block. + auto itr = frame.packets.rbegin(); + // Write the first block. // The ranges in frame.packets are [low...high), so - // a) we should never see 0 and - // b) we need to subtract 1 when writing the value out. + // a) 0 is invalid + // b) Subtract 1 when writing the value out. uint64_t block_length = itr->max() - itr->min(); if (block_length == 0) { - QUIC_BUG << "Have a 0-length range in QuicAckFrame::packets"; + QUIC_BUG << "0-length range in QuicAckFrame::packets"; return false; } @@ -2698,31 +2691,18 @@ bool QuicFramer::AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame, size_t previous_ack_end = itr->min(); ack_block_count--; - // TODO(fkastenholz) this loop adds all blocks to the frame, - // failing if the frame buffer is not large enough. In the future, - // we should put in as many as we can, adjusting the count to - // indicate just what we put in. Or at least have an option to do this. + // TODO(fkastenholz): Allow this code to write fewer ack blocks when it runs + // out of space in the packet. while (ack_block_count) { - // Do the gap separating the two ack-blocks - // Math note: value of the gap is nr of packets separating the two - // acks. If we have two sets of ack'd packets, 1,2,3 and 7,8,...x - // A) The gap size is 3 (the gap is packets 4,5,6), which is - // encoded in the frame as 2. - // B) The two frame.packets ranges are [1,4) and [7,x) so the - // gap calculation is (7-4)-1 ==> (3)-1 ==> 2. - - // next range + // Determine the number of packets between ack-blocks. itr++; - - // Mind the gap size_t gap = previous_ack_end - itr->max() - 1; - if (!writer->WriteVarInt62(gap)) { set_detailed_error("No room for gap block in ack frame"); return false; } - // Add the ack-block (itr already points to it) + // Add the ack-block. block_length = itr->max() - itr->min(); if (block_length == 0) { QUIC_BUG << "Have a 0-length range in QuicAckFrame::packets"; @@ -2880,14 +2860,6 @@ bool QuicFramer::AppendIetfConnectionCloseFrame( frame.error_details, writer); } -bool QuicFramer::AppendIetfConnectionCloseFrame( - const QuicIetfTransportErrorCodes code, - const QuicString& phrase, - QuicDataWriter* writer) { - return AppendIetfCloseFrame( - IETF_CONNECTION_CLOSE, static_cast<const uint16_t>(code), phrase, writer); -} - bool QuicFramer::AppendIetfApplicationCloseFrame( const QuicConnectionCloseFrame& frame, QuicDataWriter* writer) { @@ -2895,11 +2867,7 @@ bool QuicFramer::AppendIetfApplicationCloseFrame( static_cast<const uint16_t>(frame.error_code), frame.error_details, writer); } -bool QuicFramer::AppendIetfApplicationCloseFrame(const uint16_t code, - const QuicString& phrase, - QuicDataWriter* writer) { - return AppendIetfCloseFrame(IETF_APPLICATION_CLOSE, code, phrase, writer); -} + // Generate either an IETF-Connection- or IETF-Application-close frame. // General format is // type-byte @@ -2945,18 +2913,20 @@ bool QuicFramer::ProcessIetfConnectionCloseFrame( QuicConnectionCloseFrame* frame) { return ProcessIetfCloseFrame(reader, frame_type, frame); } + bool QuicFramer::ProcessIetfApplicationCloseFrame( QuicDataReader* reader, const uint8_t frame_type, QuicConnectionCloseFrame* frame) { return ProcessIetfCloseFrame(reader, frame_type, frame); } + bool QuicFramer::ProcessIetfCloseFrame(QuicDataReader* reader, const uint8_t frame_type, QuicConnectionCloseFrame* frame) { uint16_t code; if (!reader->ReadUInt16(&code)) { - set_detailed_error("Unable to read clode frame code."); + set_detailed_error("Unable to read close frame code."); return false; } frame->error_code = static_cast<QuicErrorCode>(code); @@ -2971,8 +2941,324 @@ bool QuicFramer::ProcessIetfCloseFrame(QuicDataReader* reader, set_detailed_error("Can not read extended close information phrase"); return false; } - frame->error_details = phrase.as_string(); + frame->error_details = string(phrase); + + return true; +} + +// IETF-format Padding frames. +// Padding is just N bytes of 0x00. There is no varint62/etc +// encoding required. +bool QuicFramer::AppendIetfPaddingFrame(const QuicPaddingFrame& frame, + QuicDataWriter* writer) { + DCHECK_GT(version_.transport_version, QUIC_VERSION_37); + // The base AppendPaddingFrame assumes that the type byte has + // been written. It will actually write num_padding_bytes-1 + // bytes. This takes care of that issue. + if (!writer->WriteUInt8(0)) { + set_detailed_error("Can not write close frame type byte"); + return false; + } + return AppendPaddingFrame(frame, writer); +} + +// Read the padding. Has to do it one byte at a time, stopping +// when we either A) reach the end of the buffer or B) reach a +// non-0x00 byte. +void QuicFramer::ProcessIetfPaddingFrame(QuicDataReader* reader, + QuicPaddingFrame* frame) { + DCHECK_GT(version_.transport_version, QUIC_VERSION_37); + ProcessPaddingFrame(reader, frame); +} + +// IETF Quic Path Challenge/Response frames. +bool QuicFramer::ProcessIetfPathChallengeFrame(QuicDataReader* reader, + QuicPathChallengeFrame* frame) { + if (!reader->ReadBytes(frame->data_buffer.data(), kQuicPathFrameBufferSize)) { + set_detailed_error("Can not read path Challenge data"); + return false; + } + return true; +} + +bool QuicFramer::ProcessIetfPathResponseFrame(QuicDataReader* reader, + QuicPathResponseFrame* frame) { + if (!reader->ReadBytes(frame->data_buffer.data(), kQuicPathFrameBufferSize)) { + set_detailed_error("Can not read path Response data"); + return false; + } + return true; +} + +bool QuicFramer::AppendIetfPathChallengeFrame( + const QuicPathChallengeFrame& frame, + QuicDataWriter* writer) { + if (!writer->WriteUInt8(IETF_PATH_CHALLENGE)) { + set_detailed_error("Can not write Path Challenge frame type byte"); + return false; + } + + if (!writer->WriteBytes(frame.data_buffer.data(), kQuicPathFrameBufferSize)) { + set_detailed_error("Writing Path Challenge data failed."); + return false; + } + return true; +} + +bool QuicFramer::AppendIetfPathResponseFrame(const QuicPathResponseFrame& frame, + QuicDataWriter* writer) { + if (!writer->WriteUInt8(IETF_PATH_RESPONSE)) { + set_detailed_error("Can not write Path Response frame type byte"); + return false; + } + + if (!writer->WriteBytes(frame.data_buffer.data(), kQuicPathFrameBufferSize)) { + set_detailed_error("Writing Path Response data failed."); + return false; + } + return true; +} + +// Add a new ietf-format stream reset frame. +// General format is +// stream id +// application error code +// final offset +bool QuicFramer::AppendIetfResetStreamFrame(const QuicRstStreamFrame& frame, + QuicDataWriter* writer) { + // Put the type-byte in the header. + if (!writer->WriteUInt8(QuicIetfFrameType::IETF_RST_STREAM)) { + set_detailed_error("Unable to write reset-stream frame-type."); + return false; + } + if (!writer->WriteVarInt62(static_cast<uint64_t>(frame.stream_id))) { + set_detailed_error("Writing reset-stream stream id failed."); + return false; + } + if (!writer->WriteUInt16(static_cast<uint16_t>(frame.error_code))) { + set_detailed_error("Writing reset-stream error code failed."); + return false; + } + if (!writer->WriteVarInt62(static_cast<uint64_t>(frame.byte_offset))) { + set_detailed_error("Writing reset-stream final-offset failed."); + return false; + } + return true; +} + +bool QuicFramer::ProcessIetfResetStreamFrame(QuicDataReader* reader, + QuicRstStreamFrame* frame) { + // Get Stream ID from frame. ReadVarIntStreamID returns false + // if either A) there is a read error or B) the resulting value of + // the Stream ID is larger than the maximum allowed value. + if (!reader->ReadVarIntStreamId(&frame->stream_id)) { + set_detailed_error("Reading reset-stream stream id failed."); + return false; + } + + uint16_t temp_uint16; + if (!reader->ReadUInt16(&temp_uint16)) { + set_detailed_error("Reading reset-stream error code failed."); + return false; + } + frame->error_code = static_cast<QuicRstStreamErrorCode>(temp_uint16); + if (!reader->ReadVarInt62(&frame->byte_offset)) { + set_detailed_error("Reading reset-stream final-offset failed."); + return false; + } + return true; +} + +bool QuicFramer::ProcessIetfStopSendingFrame( + QuicDataReader* reader, + QuicStopSendingFrame* stop_sending_frame) { + if (!reader->ReadVarIntStreamId(&stop_sending_frame->stream_id)) { + set_detailed_error("Unable to read stream id"); + return false; + } + + if (!reader->ReadUInt16(&stop_sending_frame->application_error_code)) { + set_detailed_error("Unable to read application error code."); + return false; + } + return true; +} + +bool QuicFramer::AppendIetfStopSendingFrame( + const QuicStopSendingFrame& stop_sending_frame, + QuicDataWriter* writer) { + if (!writer->WriteUInt8(IETF_STOP_SENDING)) { + set_detailed_error("Can not write stop sending frame type byte"); + return false; + } + if (!writer->WriteVarInt62(stop_sending_frame.stream_id)) { + set_detailed_error("Can not write stop sending stream id"); + return false; + } + if (!writer->WriteUInt16(stop_sending_frame.application_error_code)) { + set_detailed_error("Can not write application error code"); + return false; + } + return true; +} + +// Append/process IETF-Format MAX_DATA Frame +// MAX_DATA format is a single number, the maximum number of bytes +// that can be accepted on the connection. +bool QuicFramer::AppendIetfMaxDataFrame(const QuicWindowUpdateFrame& frame, + QuicDataWriter* writer) { + if (!writer->WriteUInt8(IETF_MAX_DATA)) { + set_detailed_error("Can not write IETF_MAX_DATA frame type byte"); + return false; + } + if (!writer->WriteVarInt62(frame.byte_offset)) { + set_detailed_error("Can not write IETF_MAX_DATA byte-offset"); + return false; + } + return true; +} + +bool QuicFramer::ProcessIetfMaxDataFrame(QuicDataReader* reader, + QuicWindowUpdateFrame* frame) { + frame->stream_id = 0; + if (!reader->ReadVarInt62(&frame->byte_offset)) { + set_detailed_error("Can not read IETF_MAX_DATA byte-offset"); + return false; + } + return true; +} + +// Append/process IETF-Format MAX_STREAM_DATA Frame +// MAX_STREAM_DATA is two numbers, stream ID and then max number of bytes. +bool QuicFramer::AppendIetfMaxStreamDataFrame( + const QuicWindowUpdateFrame& frame, + QuicDataWriter* writer) { + if (!writer->WriteUInt8(IETF_MAX_STREAM_DATA)) { + set_detailed_error("Can not write IETF_MAX_STREAM_DATA frame type byte"); + return false; + } + if (!writer->WriteVarInt62(frame.stream_id)) { + set_detailed_error("Can not write IETF_MAX_STREAM_DATA stream id"); + return false; + } + if (!writer->WriteVarInt62(frame.byte_offset)) { + set_detailed_error("Can not write IETF_MAX_STREAM_DATA byte-offset"); + return false; + } + return true; +} + +bool QuicFramer::ProcessIetfMaxStreamDataFrame(QuicDataReader* reader, + QuicWindowUpdateFrame* frame) { + if (!reader->ReadVarIntStreamId(&frame->stream_id)) { + set_detailed_error("Can not read IETF_MAX_STREAM_DATA stream id"); + return false; + } + if (!reader->ReadVarInt62(&frame->byte_offset)) { + set_detailed_error("Can not read IETF_MAX_STREAM_DATA byte-count"); + return false; + } + return true; +} + +bool QuicFramer::AppendIetfMaxStreamIdFrame( + const QuicIetfMaxStreamIdFrame& frame, + QuicDataWriter* writer) { + if (!writer->WriteUInt8(IETF_MAX_STREAM_ID)) { + set_detailed_error("Can not write IETF_MAX_STREAM_ID frame type byte"); + return false; + } + if (!writer->WriteVarInt62(frame.max_stream_id)) { + set_detailed_error("Can not write IETF_MAX_STREAM_ID stream id"); + return false; + } + return true; +} + +bool QuicFramer::ProcessIetfMaxStreamIdFrame(QuicDataReader* reader, + QuicIetfMaxStreamIdFrame* frame) { + if (!reader->ReadVarIntStreamId(&frame->max_stream_id)) { + set_detailed_error("Can not read IETF_MAX_STREAM_ID stream id"); + return false; + } + return true; +} + +bool QuicFramer::AppendIetfBlockedFrame(const QuicIetfBlockedFrame& frame, + QuicDataWriter* writer) { + if (!writer->WriteUInt8(IETF_BLOCKED)) { + set_detailed_error("Can not write IETF_BLOCKED frame type byte"); + return false; + } + if (!writer->WriteVarInt62(frame.offset)) { + set_detailed_error("Can not write IETF_BLOCKED offset"); + return false; + } + return true; +} + +bool QuicFramer::ProcessIetfBlockedFrame(QuicDataReader* reader, + QuicIetfBlockedFrame* frame) { + if (!reader->ReadVarInt62(&frame->offset)) { + set_detailed_error("Can not read IETF_BLOCKED offset"); + return false; + } + return true; +} + +bool QuicFramer::AppendIetfStreamBlockedFrame( + const QuicWindowUpdateFrame& frame, + QuicDataWriter* writer) { + if (!writer->WriteUInt8(IETF_STREAM_BLOCKED)) { + set_detailed_error("Can not write IETF_STREAM_BLOCKED frame type byte"); + return false; + } + if (!writer->WriteVarInt62(frame.stream_id)) { + set_detailed_error("Can not write IETF_STREAM_BLOCKED stream id"); + return false; + } + if (!writer->WriteVarInt62(frame.byte_offset)) { + set_detailed_error("Can not write IETF_STREAM_BLOCKED offset"); + return false; + } + return true; +} + +bool QuicFramer::ProcessIetfStreamBlockedFrame(QuicDataReader* reader, + QuicWindowUpdateFrame* frame) { + if (!reader->ReadVarIntStreamId(&frame->stream_id)) { + set_detailed_error("Can not read IETF_STREAM_BLOCKED stream id"); + return false; + } + if (!reader->ReadVarInt62(&frame->byte_offset)) { + set_detailed_error("Can not read IETF_STREAM_BLOCKED offset"); + return false; + } + return true; +} + +bool QuicFramer::AppendIetfStreamIdBlockedFrame( + const QuicIetfStreamIdBlockedFrame& frame, + QuicDataWriter* writer) { + if (!writer->WriteUInt8(IETF_STREAM_ID_BLOCKED)) { + set_detailed_error("Can not write IETF_STREAM_ID_BLOCKED frame type byte"); + return false; + } + if (!writer->WriteVarInt62(frame.stream_id)) { + set_detailed_error("Can not write IETF_STREAM_ID_BLOCKED stream id"); + return false; + } + return true; +} + +bool QuicFramer::ProcessIetfStreamIdBlockedFrame( + QuicDataReader* reader, + QuicIetfStreamIdBlockedFrame* frame) { + if (!reader->ReadVarIntStreamId(&frame->stream_id)) { + set_detailed_error("Can not read IETF_STREAM_ID_BLOCKED stream id"); + return false; + } return true; } diff --git a/chromium/net/quic/core/quic_framer.h b/chromium/net/quic/core/quic_framer.h index c08750b2e63..589d77575fd 100644 --- a/chromium/net/quic/core/quic_framer.h +++ b/chromium/net/quic/core/quic_framer.h @@ -10,6 +10,8 @@ #include <memory> #include "base/macros.h" +#include "net/quic/core/crypto/quic_decrypter.h" +#include "net/quic/core/crypto/quic_encrypter.h" #include "net/quic/core/quic_packets.h" #include "net/quic/platform/api/quic_endian.h" #include "net/quic/platform/api/quic_export.h" @@ -24,8 +26,6 @@ class QuicFramerPeer; class QuicDataReader; class QuicDataWriter; -class QuicDecrypter; -class QuicEncrypter; class QuicFramer; class QuicStreamFrameDataProducer; @@ -149,6 +149,14 @@ class QUIC_EXPORT_PRIVATE QuicFramerVisitorInterface { // Called when a packet has been completely processed. virtual void OnPacketComplete() = 0; + + // Called to check whether |token| is a valid stateless reset token. + virtual bool IsValidStatelessResetToken(uint128 token) const = 0; + + // Called when an IETF stateless reset packet has been parsed and validated + // with the stateless reset token. + virtual void OnAuthenticatedIetfStatelessResetPacket( + const QuicIetfStatelessResetPacket& packet) = 0; }; // Class for parsing and constructing QUIC packets. It has a @@ -281,6 +289,7 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // Returns a new version negotiation packet. static std::unique_ptr<QuicEncryptedPacket> BuildVersionNegotiationPacket( QuicConnectionId connection_id, + bool ietf_quic, const ParsedQuicVersionVector& versions); // If header.version_flag is set, the version in the @@ -295,29 +304,30 @@ class QUIC_EXPORT_PRIVATE QuicFramer { bool last_frame_in_packet, QuicDataWriter* writer); - // SetDecrypter sets the primary decrypter, replacing any that already exists, - // and takes ownership. If an alternative decrypter is in place then the - // function DCHECKs. This is intended for cases where one knows that future - // packets will be using the new decrypter and the previous decrypter is now - // obsolete. |level| indicates the encryption level of the new decrypter. - void SetDecrypter(EncryptionLevel level, QuicDecrypter* decrypter); + // SetDecrypter sets the primary decrypter, replacing any that already exists. + // If an alternative decrypter is in place then the function DCHECKs. This is + // intended for cases where one knows that future packets will be using the + // new decrypter and the previous decrypter is now obsolete. |level| indicates + // the encryption level of the new decrypter. + void SetDecrypter(EncryptionLevel level, + std::unique_ptr<QuicDecrypter> decrypter); // SetAlternativeDecrypter sets a decrypter that may be used to decrypt - // future packets and takes ownership of it. |level| indicates the encryption - // level of the decrypter. If |latch_once_used| is true, then the first time - // that the decrypter is successful it will replace the primary decrypter. - // Otherwise both decrypters will remain active and the primary decrypter - // will be the one last used. + // future packets. |level| indicates the encryption level of the decrypter. If + // |latch_once_used| is true, then the first time that the decrypter is + // successful it will replace the primary decrypter. Otherwise both + // decrypters will remain active and the primary decrypter will be the one + // last used. void SetAlternativeDecrypter(EncryptionLevel level, - QuicDecrypter* decrypter, + std::unique_ptr<QuicDecrypter> decrypter, bool latch_once_used); const QuicDecrypter* decrypter() const; const QuicDecrypter* alternative_decrypter() const; - // Changes the encrypter used for level |level| to |encrypter|. The function - // takes ownership of |encrypter|. - void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter); + // Changes the encrypter used for level |level| to |encrypter|. + void SetEncrypter(EncryptionLevel level, + std::unique_ptr<QuicEncrypter> encrypter); // Encrypts a payload in |buffer|. |ad_len| is the length of the associated // data. |total_len| is the length of the associated data plus plaintext. @@ -365,6 +375,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer { QuicVersionLabel last_version_label() const { return last_version_label_; } + bool last_packet_is_ietf_quic() const { return last_packet_is_ietf_quic_; } + void set_data_producer(QuicStreamFrameDataProducer* data_producer) { data_producer_ = data_producer; } @@ -514,30 +526,10 @@ class QUIC_EXPORT_PRIVATE QuicFramer { bool AppendPaddingFrame(const QuicPaddingFrame& frame, QuicDataWriter* writer); - // IETF defined frame append/process methods. + // IETF frame processing methods. bool ProcessIetfStreamFrame(QuicDataReader* reader, uint8_t frame_type, QuicStreamFrame* frame); - // Append a stream frame and data to the packet. - bool AppendIetfStreamFrame(const QuicStreamFrame& frame, - bool last_frame_in_packet, - QuicDataWriter* writer); - - // Add/process an IETF-Formatted Connection and Application close frames. - bool AppendIetfConnectionCloseFrame(const QuicConnectionCloseFrame& frame, - QuicDataWriter* writer); - bool AppendIetfConnectionCloseFrame(const QuicIetfTransportErrorCodes code, - const QuicString& phrase, - QuicDataWriter* writer); - bool AppendIetfApplicationCloseFrame(const QuicConnectionCloseFrame& frame, - QuicDataWriter* writer); - bool AppendIetfApplicationCloseFrame(const uint16_t code, - const QuicString& phrase, - QuicDataWriter* writer); - bool AppendIetfCloseFrame(const QuicIetfFrameType type, - const uint16_t code, - const QuicString& phrase, - QuicDataWriter* writer); bool ProcessIetfConnectionCloseFrame(QuicDataReader* reader, const uint8_t frame_type, QuicConnectionCloseFrame* frame); @@ -547,14 +539,73 @@ class QUIC_EXPORT_PRIVATE QuicFramer { bool ProcessIetfCloseFrame(QuicDataReader* reader, const uint8_t frame_type, QuicConnectionCloseFrame* frame); - - // Parse an IETF-format Ack frame from the packet bool ProcessIetfAckFrame(QuicDataReader* reader, uint8_t frame_type, QuicAckFrame* ack_frame); - // Append an IETf-format Ack frame to the packet - bool AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame, - QuicDataWriter* writer); + void ProcessIetfPaddingFrame(QuicDataReader* reader, QuicPaddingFrame* frame); + bool ProcessIetfPathChallengeFrame(QuicDataReader* reader, + QuicPathChallengeFrame* frame); + bool ProcessIetfPathResponseFrame(QuicDataReader* reader, + QuicPathResponseFrame* frame); + bool ProcessIetfResetStreamFrame(QuicDataReader* reader, + QuicRstStreamFrame* frame); + bool ProcessIetfStopSendingFrame(QuicDataReader* reader, + QuicStopSendingFrame* stop_sending_frame); + + // IETF frame appending methods. All methods append the type byte as well. + bool AppendIetfStreamFrame(const QuicStreamFrame& frame, + bool last_frame_in_packet, + QuicDataWriter* writer); + bool AppendIetfConnectionCloseFrame(const QuicConnectionCloseFrame& frame, + QuicDataWriter* writer); + bool AppendIetfApplicationCloseFrame(const QuicConnectionCloseFrame& frame, + QuicDataWriter* writer); + bool AppendIetfCloseFrame(const QuicIetfFrameType type, + const uint16_t code, + const QuicString& phrase, + QuicDataWriter* writer); + bool AppendIetfAckFrame(const QuicAckFrame& frame, QuicDataWriter* writer); + bool AppendIetfPaddingFrame(const QuicPaddingFrame& frame, + QuicDataWriter* writer); + bool AppendIetfPathChallengeFrame(const QuicPathChallengeFrame& frame, + QuicDataWriter* writer); + bool AppendIetfPathResponseFrame(const QuicPathResponseFrame& frame, + QuicDataWriter* writer); + bool AppendIetfResetStreamFrame(const QuicRstStreamFrame& frame, + QuicDataWriter* writer); + bool AppendIetfStopSendingFrame( + const QuicStopSendingFrame& stop_sending_frame, + QuicDataWriter* writer); + + // Append/consume IETF-Format MAX_DATA and MAX_STREAM_DATA frames + bool AppendIetfMaxDataFrame(const QuicWindowUpdateFrame& frame, + QuicDataWriter* writer); + bool AppendIetfMaxStreamDataFrame(const QuicWindowUpdateFrame& frame, + QuicDataWriter* writer); + bool ProcessIetfMaxDataFrame(QuicDataReader* reader, + QuicWindowUpdateFrame* frame); + bool ProcessIetfMaxStreamDataFrame(QuicDataReader* reader, + QuicWindowUpdateFrame* frame); + + bool AppendIetfMaxStreamIdFrame(const QuicIetfMaxStreamIdFrame& frame, + QuicDataWriter* writer); + bool ProcessIetfMaxStreamIdFrame(QuicDataReader* reader, + QuicIetfMaxStreamIdFrame* frame); + + bool AppendIetfBlockedFrame(const QuicIetfBlockedFrame& frame, + QuicDataWriter* writer); + bool ProcessIetfBlockedFrame(QuicDataReader* reader, + QuicIetfBlockedFrame* frame); + + bool AppendIetfStreamBlockedFrame(const QuicWindowUpdateFrame& frame, + QuicDataWriter* writer); + bool ProcessIetfStreamBlockedFrame(QuicDataReader* reader, + QuicWindowUpdateFrame* frame); + + bool AppendIetfStreamIdBlockedFrame(const QuicIetfStreamIdBlockedFrame& frame, + QuicDataWriter* writer); + bool ProcessIetfStreamIdBlockedFrame(QuicDataReader* reader, + QuicIetfStreamIdBlockedFrame* frame); bool RaiseError(QuicErrorCode error); @@ -573,6 +624,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer { QuicConnectionId last_serialized_connection_id_; // The last QUIC version label received. QuicVersionLabel last_version_label_; + // Whether last received packet is IETF QUIC packet. + bool last_packet_is_ietf_quic_; // Version of the protocol being used. ParsedQuicVersion version_; // This vector contains QUIC versions which we currently support. @@ -612,7 +665,7 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // owned. TODO(fayang): Consider add data producer to framer's constructor. QuicStreamFrameDataProducer* data_producer_; - // Latched value of quic_reloadable_flag_quic_use_incremental_ack_processing. + // Latched value of quic_reloadable_flag_quic_use_incremental_ack_processing3. const bool use_incremental_ack_processing_; DISALLOW_COPY_AND_ASSIGN(QuicFramer); diff --git a/chromium/net/quic/core/quic_framer_test.cc b/chromium/net/quic/core/quic_framer_test.cc index 05ff90c20fa..5bc570344de 100644 --- a/chromium/net/quic/core/quic_framer_test.cc +++ b/chromium/net/quic/core/quic_framer_test.cc @@ -26,6 +26,7 @@ #include "net/quic/test_tools/quic_test_utils.h" #include "net/quic/test_tools/simple_data_producer.h" +using std::string; using testing::_; using testing::Return; using testing::Truly; @@ -34,16 +35,18 @@ namespace net { namespace test { namespace { -const QuicPacketNumber kEpoch = UINT64_C(1) << 48; +const QuicPacketNumber kEpoch = UINT64_C(1) << 32; const QuicPacketNumber kMask = kEpoch - 1; +const uint128 kTestStatelessResetToken = 1010101; // 0x0F69B5 + // Use fields in which each byte is distinct to ensure that every byte is // framed correctly. The values are otherwise arbitrary. const QuicConnectionId kConnectionId = UINT64_C(0xFEDCBA9876543210); -const QuicPacketNumber kPacketNumber = UINT64_C(0x123456789ABC); +const QuicPacketNumber kPacketNumber = UINT64_C(0x12345678); const QuicPacketNumber kSmallLargestObserved = UINT16_C(0x1234); const QuicPacketNumber kSmallMissingPacket = UINT16_C(0x1233); -const QuicPacketNumber kLeastUnacked = UINT64_C(0x0123456789AA0); +const QuicPacketNumber kLeastUnacked = UINT64_C(0x012345670); const QuicStreamId kStreamId = UINT64_C(0x01020304); const QuicStreamOffset kStreamOffset = UINT64_C(0xBA98FEDC32107654); const QuicPublicResetNonceProof kNonceProof = UINT64_C(0xABCDEF0123456789); @@ -63,8 +66,8 @@ class TestEncrypter : public QuicEncrypter { size_t max_output_length) override { version_ = version; packet_number_ = packet_number; - associated_data_ = associated_data.as_string(); - plaintext_ = plaintext.as_string(); + associated_data_ = string(associated_data); + plaintext_ = string(plaintext); memcpy(output, plaintext.data(), plaintext.length()); *output_length = plaintext.length(); return true; @@ -109,8 +112,8 @@ class TestDecrypter : public QuicDecrypter { size_t max_output_length) override { version_ = version; packet_number_ = packet_number; - associated_data_ = associated_data.as_string(); - ciphertext_ = ciphertext.as_string(); + associated_data_ = string(associated_data); + ciphertext_ = string(ciphertext); memcpy(output, ciphertext.data(), ciphertext.length()); *output_length = ciphertext.length(); return true; @@ -260,6 +263,16 @@ class TestQuicVisitor : public QuicFramerVisitorInterface { return true; } + bool IsValidStatelessResetToken(uint128 token) const override { + return token == kTestStatelessResetToken; + } + + void OnAuthenticatedIetfStatelessResetPacket( + const QuicIetfStatelessResetPacket& packet) override { + stateless_reset_packet_ = + QuicMakeUnique<QuicIetfStatelessResetPacket>(packet); + } + // Counters from the visitor_ callbacks. int error_count_; int version_mismatch_; @@ -271,6 +284,7 @@ class TestQuicVisitor : public QuicFramerVisitorInterface { std::unique_ptr<QuicPacketHeader> header_; std::unique_ptr<QuicPublicResetPacket> public_reset_packet_; + std::unique_ptr<QuicIetfStatelessResetPacket> stateless_reset_packet_; std::unique_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_; std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames_; std::vector<std::unique_ptr<QuicAckFrame>> ack_frames_; @@ -294,6 +308,12 @@ struct PacketFragment { using PacketFragments = std::vector<struct PacketFragment>; +ParsedQuicVersionVector AllSupportedVersionsIncludingTls() { + QuicFlagSaver flags; + SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); + return AllSupportedVersions(); +} + class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> { public: QuicFramerTest() @@ -301,13 +321,25 @@ class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> { decrypter_(new test::TestDecrypter()), version_(GetParam()), start_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(0x10)), - framer_(AllSupportedVersions(), start_, Perspective::IS_SERVER) { + framer_(AllSupportedVersionsIncludingTls(), + start_, + Perspective::IS_SERVER) { + SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); framer_.set_version(version_); - framer_.SetDecrypter(ENCRYPTION_NONE, decrypter_); - framer_.SetEncrypter(ENCRYPTION_NONE, encrypter_); + framer_.SetDecrypter(ENCRYPTION_NONE, + std::unique_ptr<QuicDecrypter>(decrypter_)); + framer_.SetEncrypter(ENCRYPTION_NONE, + std::unique_ptr<QuicEncrypter>(encrypter_)); + framer_.set_visitor(&visitor_); } + // Helper function to get unsigned char representation of the handshake + // protocol byte of the current QUIC version number. + unsigned char GetQuicVersionProtocolByte() { + return (CreateQuicVersionLabel(version_) >> 24) & 0xff; + } + // Helper function to get unsigned char representation of digit in the // units place of the current QUIC version number. unsigned char GetQuicVersionDigitOnes() { @@ -358,13 +390,13 @@ class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> { if (QuicFramer::GetAssociatedDataFromEncryptedPacket( framer_.transport_version(), encrypted, PACKET_8BYTE_CONNECTION_ID, includes_version, includes_diversification_nonce, - PACKET_6BYTE_PACKET_NUMBER) != decrypter_->associated_data_) { + PACKET_4BYTE_PACKET_NUMBER) != decrypter_->associated_data_) { QUIC_LOG(ERROR) << "Decrypted incorrect associated data. expected " << QuicFramer::GetAssociatedDataFromEncryptedPacket( framer_.transport_version(), encrypted, PACKET_8BYTE_CONNECTION_ID, includes_version, includes_diversification_nonce, - PACKET_6BYTE_PACKET_NUMBER) + PACKET_4BYTE_PACKET_NUMBER) << " actual: " << decrypter_->associated_data_; return false; } @@ -372,7 +404,7 @@ class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> { encrypted.AsStringPiece().substr(GetStartOfEncryptedData( framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, includes_version, includes_diversification_nonce, - PACKET_6BYTE_PACKET_NUMBER))); + PACKET_4BYTE_PACKET_NUMBER))); if (ciphertext != decrypter_->ciphertext_) { QUIC_LOG(ERROR) << "Decrypted incorrect ciphertext data. expected " << ciphertext << " actual: " << decrypter_->ciphertext_; @@ -450,7 +482,7 @@ class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> { QuicPacketNumber wire_packet_number = expected_packet_number & kMask; EXPECT_EQ(expected_packet_number, QuicFramerPeer::CalculatePacketNumberFromWire( - &framer_, PACKET_6BYTE_PACKET_NUMBER, last_packet_number, + &framer_, PACKET_4BYTE_PACKET_NUMBER, last_packet_number, wire_packet_number)) << "last_packet_number: " << last_packet_number << " wire_packet_number: " << wire_packet_number; @@ -475,10 +507,19 @@ class QuicFramerTest : public QuicTestWithParam<ParsedQuicVersion> { test::TestQuicVisitor visitor_; }; +// Multiple test cases of QuicFramerTest use byte arrays to define packets for +// testing, and these byte arrays contain the QUIC version. This macro explodes +// the 32-bit version into four bytes in network order. Since it uses methods of +// QuicFramerTest, it is only valid to use this in a QuicFramerTest. +#define QUIC_VERSION_BYTES \ + GetQuicVersionProtocolByte(), '0', GetQuicVersionDigitTens(), \ + GetQuicVersionDigitOnes() + // Run all framer tests with all supported versions of QUIC. -INSTANTIATE_TEST_CASE_P(QuicFramerTests, - QuicFramerTest, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_CASE_P( + QuicFramerTests, + QuicFramerTest, + ::testing::ValuesIn(AllSupportedVersionsIncludingTls())); TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochStart) { // A few quick manual sanity checks. @@ -592,11 +633,11 @@ TEST_P(QuicFramerTest, LargePacket) { // clang-format off unsigned char packet[kMaxPacketSize + 1] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // private flags 0x00, }; @@ -604,7 +645,7 @@ TEST_P(QuicFramerTest, LargePacket) { const size_t header_size = GetPacketHeaderSize( framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER); + !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER); memset(packet + header_size, 0, kMaxPacketSize - header_size); @@ -623,25 +664,25 @@ TEST_P(QuicFramerTest, PacketHeader) { PacketFragments packet38 = { // public flags (8 byte connection_id) {"Unable to read public flags.", - {0x38}}, + {0x28}}, // connection_id {"Unable to read ConnectionId.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", - {0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, }; PacketFragments packet39 = { // public flags (8 byte connection_id) {"Unable to read public flags.", - {0x38}}, + {0x28}}, // connection_id {"Unable to read ConnectionId.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, }; // clang-format on @@ -669,23 +710,21 @@ TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) { PacketFragments packet = { // public flags (0 byte connection_id) {"Unable to read public flags.", - {0x30}}, + {0x20}}, // connection_id // packet number {"Unable to read packet number.", - {0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12}} + {0x78, 0x56, 0x34, 0x12}} }; PacketFragments packet39 = { // public flags (0 byte connection_id) {"Unable to read public flags.", - {0x30}}, + {0x20}}, // connection_id // packet number {"Unable to read packet number.", - {0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, }; // clang-format on @@ -709,31 +748,31 @@ TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) { PacketFragments packet = { // public flags (0 byte connection_id) {"Unable to read public flags.", - {0x39}}, + {0x29}}, // connection_id {"Unable to read ConnectionId.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // version tag {"Unable to read protocol version.", - {'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes()}}, + {QUIC_VERSION_BYTES}}, // packet number {"Unable to read packet number.", - {0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, }; PacketFragments packet39 = { // public flags (0 byte connection_id) {"Unable to read public flags.", - {0x39}}, + {0x29}}, // connection_id {"Unable to read ConnectionId.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // version tag {"Unable to read protocol version.", - {'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes()}}, + {QUIC_VERSION_BYTES}}, // packet number {"Unable to read packet number.", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, }; // clang-format on @@ -766,7 +805,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) { {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", - {0xBC, 0x9A, 0x78, 0x56}}, + {0x78, 0x56, 0x34, 0x12}}, }; PacketFragments packet39 = { @@ -778,7 +817,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) { {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", - {0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, }; // clang-format on @@ -810,7 +849,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) { {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", - {0xBC, 0x9A}}, + {0x78, 0x56}}, }; PacketFragments packet39 = { @@ -822,7 +861,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) { {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", - {0x9A, 0xBC}}, + {0x56, 0x78}}, }; // clang-format on @@ -855,7 +894,7 @@ TEST_P(QuicFramerTest, PacketHeaderWith1BytePacketNumber) { {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", - {0xBC}}, + {0x78}}, }; std::unique_ptr<QuicEncryptedPacket> encrypted( @@ -891,7 +930,7 @@ TEST_P(QuicFramerTest, PacketNumberDecreasesThenIncreases) { EXPECT_TRUE(framer_.ProcessPacket(encrypted)); ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(kConnectionId, visitor_.header_->connection_id); - EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER, + EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER, visitor_.header_->packet_number_length); EXPECT_EQ(kPacketNumber - 2, visitor_.header_->packet_number); @@ -936,7 +975,7 @@ TEST_P(QuicFramerTest, PacketWithDiversificationNonce) { // clang-format off unsigned char packet[] = { // public flags: includes nonce flag - 0x3C, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // nonce @@ -945,7 +984,7 @@ TEST_P(QuicFramerTest, PacketWithDiversificationNonce) { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, // packet number - 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (padding) 0x00, @@ -954,7 +993,7 @@ TEST_P(QuicFramerTest, PacketWithDiversificationNonce) { unsigned char packet39[] = { // public flags: includes nonce flag - 0x3C, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // nonce @@ -963,7 +1002,7 @@ TEST_P(QuicFramerTest, PacketWithDiversificationNonce) { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, // packet number - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // frame type (padding) 0x00, @@ -989,14 +1028,13 @@ TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id, version flag and an unknown flag) - 0x39, + 0x29, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // version tag 'Q', '0', '0', '0', // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (padding frame) 0x00, @@ -1005,14 +1043,13 @@ TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) { unsigned char packet39[] = { // public flags (8 byte connection_id, version flag and an unknown flag) - 0x39, + 0x29, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // version tag 'Q', '0', '0', '0', // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (padding frame) 0x00, @@ -1037,12 +1074,11 @@ TEST_P(QuicFramerTest, PaddingFrame) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (padding frame) 0x00, @@ -1084,7 +1120,7 @@ TEST_P(QuicFramerTest, PaddingFrame) { GetPacketHeaderSize(framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, - PACKET_6BYTE_PACKET_NUMBER), + PACKET_4BYTE_PACKET_NUMBER), "Packet has no frames.", QUIC_MISSING_PAYLOAD); } @@ -1092,12 +1128,11 @@ TEST_P(QuicFramerTest, NewPaddingFrame) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // paddings 0x00, 0x00, @@ -1120,12 +1155,11 @@ TEST_P(QuicFramerTest, NewPaddingFrame) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // paddings 0x00, 0x00, @@ -1148,12 +1182,11 @@ TEST_P(QuicFramerTest, NewPaddingFrame) { unsigned char packet41[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // paddings 0x00, 0x00, @@ -1208,14 +1241,13 @@ TEST_P(QuicFramerTest, StreamFrame) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (stream frame with fin) {"", {0xFF}}, @@ -1239,14 +1271,13 @@ TEST_P(QuicFramerTest, StreamFrame) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (stream frame with fin) {"", {0xFF}}, @@ -1270,14 +1301,13 @@ TEST_P(QuicFramerTest, StreamFrame) { PacketFragments packet41 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (stream frame with fin) {"", {0xFF}}, @@ -1324,19 +1354,20 @@ TEST_P(QuicFramerTest, StreamFrame) { TEST_P(QuicFramerTest, MissingDiversificationNonce) { QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); framer_.SetDecrypter(ENCRYPTION_NONE, - new NullDecrypter(Perspective::IS_CLIENT)); + QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); decrypter_ = new test::TestDecrypter(); - framer_.SetAlternativeDecrypter(ENCRYPTION_INITIAL, decrypter_, false); + framer_.SetAlternativeDecrypter(ENCRYPTION_INITIAL, + std::unique_ptr<QuicDecrypter>(decrypter_), + false); // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (stream frame with fin) 0xFF, @@ -1355,12 +1386,11 @@ TEST_P(QuicFramerTest, MissingDiversificationNonce) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (stream frame with fin) 0xFF, @@ -1379,12 +1409,11 @@ TEST_P(QuicFramerTest, MissingDiversificationNonce) { unsigned char packet41[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (stream frame with fin) 0xFF, @@ -1418,14 +1447,13 @@ TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (stream frame with fin) {"", {0xFE}}, @@ -1449,14 +1477,13 @@ TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (stream frame with fin) {"", {0xFE}}, @@ -1480,14 +1507,13 @@ TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) { PacketFragments packet41 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (stream frame with fin) {"", {0xF7}}, @@ -1537,14 +1563,13 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (stream frame with fin) {"", {0xFD}}, @@ -1568,14 +1593,13 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (stream frame with fin) {"", {0xFD}}, @@ -1599,14 +1623,13 @@ TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) { PacketFragments packet41 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (stream frame with fin) {"", {0xEF}}, @@ -1656,14 +1679,13 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (stream frame with fin) {"", {0xFC}}, @@ -1687,14 +1709,13 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (stream frame with fin) {"", {0xFC}}, @@ -1718,14 +1739,13 @@ TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) { PacketFragments packet41 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (stream frame with fin) {"", {0xE7}}, @@ -1775,17 +1795,16 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) { PacketFragments packet = { // public flags (version, 8 byte connection_id) {"", - {0x39}}, + {0x29}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // version tag {"", - {'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes()}}, + {QUIC_VERSION_BYTES}}, // packet number {"", - {0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (stream frame with fin) {"", {0xFE}}, @@ -1809,17 +1828,16 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) { PacketFragments packet39 = { // public flags (version, 8 byte connection_id) {"", - {0x39}}, + {0x29}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // version tag {"", - {'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes()}}, + {QUIC_VERSION_BYTES}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (stream frame with fin) {"", {0xFE}}, @@ -1843,17 +1861,16 @@ TEST_P(QuicFramerTest, StreamFrameWithVersion) { PacketFragments packet41 = { // public flags (version, 8 byte connection_id) {"", - {0x39}}, + {0x29}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // version tag {"", - {'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes()}}, + {QUIC_VERSION_BYTES}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (stream frame with fin) {"", {0xF7}}, @@ -1904,12 +1921,11 @@ TEST_P(QuicFramerTest, RejectPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (stream frame with fin) 0xFF, @@ -1928,12 +1944,11 @@ TEST_P(QuicFramerTest, RejectPacket) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (stream frame with fin) 0xFF, @@ -1952,12 +1967,11 @@ TEST_P(QuicFramerTest, RejectPacket) { unsigned char packet41[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (stream frame with fin) 0xFF, @@ -1999,7 +2013,7 @@ TEST_P(QuicFramerTest, RejectPublicHeader) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, }; @@ -2018,13 +2032,13 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlock) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - {0x3C}}, + {0x2C}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (ack frame) // (one ack block, 2 byte largest observed, 2 byte block length) {"", @@ -2046,13 +2060,13 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlock) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - {0x3C}}, + {0x2C}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (ack frame) // (one ack block, 2 byte largest observed, 2 byte block length) {"", @@ -2074,13 +2088,13 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlock) { PacketFragments packet41 = { // public flags (8 byte connection_id) {"", - {0x3C}}, + {0x2C}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (ack frame) // (one ack block, 2 byte largest observed, 2 byte block length) {"", @@ -2126,13 +2140,13 @@ TEST_P(QuicFramerTest, FirstAckFrameUnderflow) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - {0x3C}}, + {0x2C}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (ack frame) // (one ack block, 2 byte largest observed, 2 byte block length) {"", @@ -2154,13 +2168,13 @@ TEST_P(QuicFramerTest, FirstAckFrameUnderflow) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - {0x3C}}, + {0x2C}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (ack frame) // (one ack block, 2 byte largest observed, 2 byte block length) {"", @@ -2182,13 +2196,13 @@ TEST_P(QuicFramerTest, FirstAckFrameUnderflow) { PacketFragments packet41 = { // public flags (8 byte connection_id) {"", - {0x3C}}, + {0x2C}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (ack frame) // (one ack block, 2 byte largest observed, 2 byte block length) {"", @@ -2222,13 +2236,13 @@ TEST_P(QuicFramerTest, AckFrameFirstAckBlockLengthZero) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - { 0x3C }}, + { 0x2C }}, // connection_id {"", { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, // packet number {"", - { 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12 }}, + { 0x78, 0x56, 0x34, 0x12 }}, // frame type (ack frame) // (more than one ack block, 2 byte largest observed, 2 byte block length) @@ -2263,13 +2277,13 @@ TEST_P(QuicFramerTest, AckFrameFirstAckBlockLengthZero) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - { 0x3C }}, + { 0x2C }}, // connection_id {"", { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, // packet number {"", - { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC }}, + { 0x12, 0x34, 0x56, 0x78 }}, // frame type (ack frame) // (more than one ack block, 2 byte largest observed, 2 byte block length) @@ -2304,13 +2318,13 @@ TEST_P(QuicFramerTest, AckFrameFirstAckBlockLengthZero) { PacketFragments packet41 = { // public flags (8 byte connection_id) {"", - { 0x3C }}, + { 0x2C }}, // connection_id {"", { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, // packet number {"", - { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC }}, + { 0x12, 0x34, 0x56, 0x78 }}, // frame type (ack frame) // (more than one ack block, 2 byte largest observed, 2 byte block length) @@ -2372,20 +2386,20 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlockMaxLength) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - {0x3C}}, + {0x2C}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (ack frame) - // (one ack block, 6 byte largest observed, 2 byte block length) + // (one ack block, 4 byte largest observed, 2 byte block length) {"", - {0x4D}}, + {0x49}}, // largest acked {"Unable to read largest acked.", - {0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // Zero delta time. {"Unable to read ack delay time.", {0x00, 0x00}}, @@ -2400,20 +2414,20 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlockMaxLength) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - {0x3C}}, + {0x2C}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (ack frame) - // (one ack block, 6 byte largest observed, 2 byte block length) + // (one ack block, 4 byte largest observed, 2 byte block length) {"", - {0x4D}}, + {0x49}}, // largest acked {"Unable to read largest acked.", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // Zero delta time. {"Unable to read ack delay time.", {0x00, 0x00}}, @@ -2428,23 +2442,23 @@ TEST_P(QuicFramerTest, AckFrameOneAckBlockMaxLength) { PacketFragments packet41 = { // public flags (8 byte connection_id) {"", - {0x3C}}, + {0x2C}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (ack frame) - // (one ack block, 8 byte largest observed, 2 byte block length) + // (one ack block, 4 byte largest observed, 2 byte block length) {"", - {0xAD}}, + {0xA9}}, // num timestamps. {"Unable to read num received packets.", {0x00}}, // largest acked {"Unable to read largest acked.", - {0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // Zero delta time. {"Unable to read ack delay time.", {0x00, 0x00}}, @@ -2481,13 +2495,13 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - { 0x3C }}, + { 0x2C }}, // connection_id {"", { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, // packet number {"", - { 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12 }}, + { 0x78, 0x56, 0x34, 0x12 }}, // frame type (ack frame) // (more than one ack block, 2 byte largest observed, 2 byte block length) @@ -2549,13 +2563,13 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - { 0x3C }}, + { 0x2C }}, // connection_id {"", { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, // packet number {"", - { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC }}, + { 0x12, 0x34, 0x56, 0x78 }}, // frame type (ack frame) // (more than one ack block, 2 byte largest observed, 2 byte block length) @@ -2617,13 +2631,13 @@ TEST_P(QuicFramerTest, AckFrameTwoTimeStampsMultipleAckBlocks) { PacketFragments packet41 = { // public flags (8 byte connection_id) {"", - { 0x3C }}, + { 0x2C }}, // connection_id {"", { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, // packet number {"", - { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC }}, + { 0x12, 0x34, 0x56, 0x78 }}, // frame type (ack frame) // (more than one ack block, 2 byte largest observed, 2 byte block length) @@ -2713,39 +2727,37 @@ TEST_P(QuicFramerTest, NewStopWaitingFrame) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - {0x3C}}, + {0x2C}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (stop waiting frame) {"", {0x06}}, // least packet number awaiting an ack, delta from packet number. {"Unable to read least unacked delta.", - {0x08, 0x00, 0x00, 0x00, - 0x00, 0x00}} + {0x08, 0x00, 0x00, 0x00}} }; PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - {0x3C}}, + {0x2C}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xA8}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (stop waiting frame) {"", {0x06}}, // least packet number awaiting an ack, delta from packet number. {"Unable to read least unacked delta.", - {0x00, 0x00, 0x00, 0x00, - 0x00, 0x08}} + {0x00, 0x00, 0x00, 0x08}} }; // clang-format on @@ -2772,12 +2784,11 @@ TEST_P(QuicFramerTest, InvalidNewStopWaitingFrame) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x3C, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xA8, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (stop waiting frame) 0x06, // least packet number awaiting an ack, delta from packet number. @@ -2787,12 +2798,11 @@ TEST_P(QuicFramerTest, InvalidNewStopWaitingFrame) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x3C, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xA8, // frame type (stop waiting frame) 0x06, // least packet number awaiting an ack, delta from packet number. @@ -2815,13 +2825,13 @@ TEST_P(QuicFramerTest, RstStreamFrame) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (rst stream frame) {"", {0x01}}, @@ -2840,13 +2850,13 @@ TEST_P(QuicFramerTest, RstStreamFrame) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (rst stream frame) {"", {0x01}}, @@ -2865,13 +2875,13 @@ TEST_P(QuicFramerTest, RstStreamFrame) { PacketFragments packet41 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (rst stream frame) {"", {0x01}}, @@ -2912,13 +2922,13 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (connection close frame) {"", {0x02}}, @@ -2940,13 +2950,13 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (connection close frame) {"", {0x02}}, @@ -2992,13 +3002,13 @@ TEST_P(QuicFramerTest, GoAwayFrame) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (go away frame) {"", {0x03}}, @@ -3023,13 +3033,13 @@ TEST_P(QuicFramerTest, GoAwayFrame) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (go away frame) {"", {0x03}}, @@ -3076,13 +3086,13 @@ TEST_P(QuicFramerTest, WindowUpdateFrame) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (window update frame) {"", {0x04}}, @@ -3098,13 +3108,13 @@ TEST_P(QuicFramerTest, WindowUpdateFrame) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (window update frame) {"", {0x04}}, @@ -3140,13 +3150,13 @@ TEST_P(QuicFramerTest, BlockedFrame) { PacketFragments packet = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}}, + {0x78, 0x56, 0x34, 0x12}}, // frame type (blocked frame) {"", {0x05}}, @@ -3158,13 +3168,13 @@ TEST_P(QuicFramerTest, BlockedFrame) { PacketFragments packet39 = { // public flags (8 byte connection_id) {"", - {0x38}}, + {0x28}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}}, + {0x12, 0x34, 0x56, 0x78}}, // frame type (blocked frame) {"", {0x05}}, @@ -3194,12 +3204,11 @@ TEST_P(QuicFramerTest, PingFrame) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (ping frame) 0x07, @@ -3207,12 +3216,11 @@ TEST_P(QuicFramerTest, PingFrame) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (ping frame) 0x07, @@ -3430,13 +3438,13 @@ TEST_P(QuicFramerTest, VersionNegotiationPacket) { PacketFragments packet = { // public flags (version, 8 byte connection_id) {"", - {0x39}}, + {0x29}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // version tag {"Unable to read supported version in negotiation.", - {'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), + {QUIC_VERSION_BYTES, 'Q', '2', '.', '0'}}, }; // clang-format on @@ -3465,13 +3473,13 @@ TEST_P(QuicFramerTest, OldVersionNegotiationPacket) { PacketFragments packet = { // public flags (version, 8 byte connection_id) {"", - {0x3D}}, + {0x2D}}, // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // version tag {"Unable to read supported version in negotiation.", - {'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), + {QUIC_VERSION_BYTES, 'Q', '2', '.', '0'}}, }; // clang-format on @@ -3507,12 +3515,11 @@ TEST_P(QuicFramerTest, BuildPaddingFramePacket) { // clang-format off unsigned char packet[kMaxPacketSize] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (padding frame) 0x00, @@ -3521,12 +3528,11 @@ TEST_P(QuicFramerTest, BuildPaddingFramePacket) { unsigned char packet39[kMaxPacketSize] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (padding frame) 0x00, @@ -3536,7 +3542,7 @@ TEST_P(QuicFramerTest, BuildPaddingFramePacket) { uint64_t header_size = GetPacketHeaderSize( framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER); + !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER); memset((framer_.transport_version() <= QUIC_VERSION_38 ? packet : packet39) + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); @@ -3570,12 +3576,11 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // paddings 0x00, 0x00, @@ -3598,12 +3603,11 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // paddings 0x00, 0x00, @@ -3626,12 +3630,11 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) { unsigned char packet41[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // paddings 0x00, 0x00, @@ -3686,7 +3689,7 @@ TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) { // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, + 0x78, 0x56, 0x34, 0x12, // frame type (padding frame) 0x00, @@ -3699,7 +3702,7 @@ TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) { // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // frame type (padding frame) 0x00, @@ -3741,7 +3744,7 @@ TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) { // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, + 0x78, 0x56, // frame type (padding frame) 0x00, @@ -3754,7 +3757,7 @@ TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) { // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x9A, 0xBC, + 0x56, 0x78, // frame type (padding frame) 0x00, @@ -3796,7 +3799,7 @@ TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) { // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, + 0x78, // frame type (padding frame) 0x00, @@ -3832,12 +3835,11 @@ TEST_P(QuicFramerTest, BuildStreamFramePacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (stream frame with fin and no length) 0xDF, @@ -3854,12 +3856,11 @@ TEST_P(QuicFramerTest, BuildStreamFramePacket) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (stream frame with fin and no length) 0xDF, @@ -3876,12 +3877,11 @@ TEST_P(QuicFramerTest, BuildStreamFramePacket) { unsigned char packet41[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (stream frame with fin and no length) 0xFE, @@ -3925,13 +3925,13 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) { // clang-format off unsigned char packet[] = { // public flags (version, 8 byte connection_id) - 0x3D, + 0x2D, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // version tag - 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), + QUIC_VERSION_BYTES, // packet number - 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (stream frame with fin and no length) 0xDF, @@ -3945,13 +3945,13 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) { unsigned char packet39[] = { // public flags (version, 8 byte connection_id) - 0x3D, + 0x2D, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // version tag - 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), + QUIC_VERSION_BYTES, // packet number - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // frame type (stream frame with fin and no length) 0xDF, @@ -3965,13 +3965,13 @@ TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) { unsigned char packet41[] = { // public flags (version, 8 byte connection_id) - 0x3D, + 0x2D, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // version tag - 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), + QUIC_VERSION_BYTES, // packet number - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // frame type (stream frame with fin and no length) 0xFE, @@ -4007,13 +4007,13 @@ TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) { // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // version tag - 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(), + QUIC_VERSION_BYTES, }; // clang-format on QuicConnectionId connection_id = kConnectionId; std::unique_ptr<QuicEncryptedPacket> data( - framer_.BuildVersionNegotiationPacket(connection_id, + framer_.BuildVersionNegotiationPacket(connection_id, false, SupportedVersions(GetParam()))); test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(packet), @@ -4036,11 +4036,11 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (ack frame) // (no ack blocks, 2 byte largest observed, 2 byte block length) @@ -4057,11 +4057,11 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // frame type (ack frame) // (no ack blocks, 2 byte largest observed, 2 byte block length) @@ -4078,11 +4078,11 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlock) { unsigned char packet41[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // frame type (ack frame) // (no ack blocks, 2 byte largest observed, 2 byte block length) @@ -4126,65 +4126,65 @@ TEST_P(QuicFramerTest, BuildAckFramePacketOneAckBlockMaxLength) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (ack frame) - // (no ack blocks, 6 byte largest observed, 6 byte block length) - 0x4F, + // (no ack blocks, 4 byte largest observed, 4 byte block length) + 0x4A, // largest acked - 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // Zero delta time. 0x00, 0x00, // first ack block length. - 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // num timestamps. 0x00, }; unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // frame type (ack frame) - // (no ack blocks, 6 byte largest observed, 6 byte block length) - 0x4F, + // (no ack blocks, 4 byte largest observed, 4 byte block length) + 0x4A, // largest acked - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // Zero delta time. 0x00, 0x00, // first ack block length. - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // num timestamps. 0x00, }; unsigned char packet41[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // frame type (ack frame) - // (no ack blocks, 8 byte largest observed, 8 byte block length) - 0xAF, + // (no ack blocks, 4 byte largest observed, 4 byte block length) + 0xAA, // num timestamps. 0x00, // largest acked - 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // Zero delta time. 0x00, 0x00, // first ack block length. - 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, }; // clang-format on unsigned char* p = packet; @@ -4223,11 +4223,11 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (ack frame) // (has ack blocks, 2 byte largest observed, 2 byte block length) @@ -4262,11 +4262,11 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // frame type (ack frame) // (has ack blocks, 2 byte largest observed, 2 byte block length) @@ -4301,11 +4301,11 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMultipleAckBlocks) { unsigned char packet41[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // frame type (ack frame) // (has ack blocks, 2 byte largest observed, 2 byte block length) @@ -4375,11 +4375,11 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (ack frame) // (has ack blocks, 2 byte largest observed, 2 byte block length) 0x65, @@ -4468,11 +4468,11 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // frame type (ack frame) // (has ack blocks, 2 byte largest observed, 2 byte block length) 0x65, @@ -4561,11 +4561,11 @@ TEST_P(QuicFramerTest, BuildAckFramePacketMaxAckBlocks) { unsigned char packet41[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // frame type (ack frame) // (has ack blocks, 2 byte largest observed, 2 byte block length) 0xB5, @@ -4682,32 +4682,30 @@ TEST_P(QuicFramerTest, BuildNewStopWaitingPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (stop waiting frame) 0x06, // least packet number awaiting an ack, delta from packet number. - 0x1C, 0x00, 0x00, 0x00, - 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, }; unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, + 0x12, 0x34, 0x56, 0x78, // frame type (stop waiting frame) 0x06, // least packet number awaiting an ack, delta from packet number. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1C, + 0x00, 0x00, 0x00, 0x08, }; // clang-format on @@ -4736,12 +4734,11 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (rst stream frame) 0x01, @@ -4756,12 +4753,11 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (rst stream frame) 0x01, @@ -4776,12 +4772,11 @@ TEST_P(QuicFramerTest, BuildRstFramePacketQuic) { unsigned char packet41[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (rst stream frame) 0x01, @@ -4829,12 +4824,11 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (connection close frame) 0x02, @@ -4851,12 +4845,11 @@ TEST_P(QuicFramerTest, BuildCloseFramePacket) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (connection close frame) 0x02, @@ -4898,12 +4891,11 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (connection close frame) 0x02, @@ -4948,12 +4940,11 @@ TEST_P(QuicFramerTest, BuildTruncatedCloseFramePacket) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (connection close frame) 0x02, @@ -5028,12 +5019,11 @@ TEST_P(QuicFramerTest, BuildGoAwayPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (go away frame) 0x03, @@ -5052,12 +5042,11 @@ TEST_P(QuicFramerTest, BuildGoAwayPacket) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (go away frame) 0x03, @@ -5102,12 +5091,11 @@ TEST_P(QuicFramerTest, BuildTruncatedGoAwayPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (go away frame) 0x03, @@ -5154,12 +5142,11 @@ TEST_P(QuicFramerTest, BuildTruncatedGoAwayPacket) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (go away frame) 0x03, @@ -5235,12 +5222,11 @@ TEST_P(QuicFramerTest, BuildWindowUpdatePacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (window update frame) 0x04, @@ -5253,12 +5239,11 @@ TEST_P(QuicFramerTest, BuildWindowUpdatePacket) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (window update frame) 0x04, @@ -5295,12 +5280,11 @@ TEST_P(QuicFramerTest, BuildBlockedPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (blocked frame) 0x05, @@ -5310,12 +5294,11 @@ TEST_P(QuicFramerTest, BuildBlockedPacket) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (blocked frame) 0x05, @@ -5346,12 +5329,11 @@ TEST_P(QuicFramerTest, BuildPingPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (ping frame) 0x07, @@ -5359,12 +5341,11 @@ TEST_P(QuicFramerTest, BuildPingPacket) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (ping frame) 0x07, @@ -5393,12 +5374,11 @@ TEST_P(QuicFramerTest, BuildConnectivityProbingPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (ping frame) 0x07, @@ -5409,12 +5389,11 @@ TEST_P(QuicFramerTest, BuildConnectivityProbingPacket) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (ping frame) 0x07, @@ -5461,12 +5440,11 @@ TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (ping frame) 0x07, @@ -5474,12 +5452,11 @@ TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (ping frame) 0x07, @@ -5579,12 +5556,11 @@ TEST_P(QuicFramerTest, EncryptPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // redundancy 'a', 'b', 'c', 'd', @@ -5595,12 +5571,11 @@ TEST_P(QuicFramerTest, EncryptPacket) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // redundancy 'a', 'b', 'c', 'd', @@ -5615,7 +5590,7 @@ TEST_P(QuicFramerTest, EncryptPacket) { : packet39), QUIC_ARRAYSIZE(packet), false, PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, - PACKET_6BYTE_PACKET_NUMBER)); + PACKET_4BYTE_PACKET_NUMBER)); char buffer[kMaxPacketSize]; size_t encrypted_length = framer_.EncryptPayload( ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize); @@ -5629,14 +5604,13 @@ TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) { // clang-format off unsigned char packet[] = { // public flags (version, 8 byte connection_id) - 0x39, + 0x29, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // version tag 'Q', '.', '1', '0', // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // redundancy 'a', 'b', 'c', 'd', @@ -5647,14 +5621,13 @@ TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) { unsigned char packet39[] = { // public flags (version, 8 byte connection_id) - 0x39, + 0x29, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // version tag 'Q', '.', '1', '0', // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // redundancy 'a', 'b', 'c', 'd', @@ -5669,7 +5642,7 @@ TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) { : packet39), QUIC_ARRAYSIZE(packet), false, PACKET_8BYTE_CONNECTION_ID, kIncludeVersion, !kIncludeDiversificationNonce, - PACKET_6BYTE_PACKET_NUMBER)); + PACKET_4BYTE_PACKET_NUMBER)); char buffer[kMaxPacketSize]; size_t encrypted_length = framer_.EncryptPayload( ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize); @@ -5736,8 +5709,8 @@ TEST_P(QuicFramerTest, AckTruncationSmallPacket) { ASSERT_EQ(1u, visitor_.ack_frames_.size()); QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0]; EXPECT_EQ(600u, LargestAcked(processed_ack_frame)); - ASSERT_EQ(239u, processed_ack_frame.packets.NumPacketsSlow()); - EXPECT_EQ(124u, processed_ack_frame.packets.Min()); + ASSERT_EQ(240u, processed_ack_frame.packets.NumPacketsSlow()); + EXPECT_EQ(122u, processed_ack_frame.packets.Min()); EXPECT_EQ(600u, processed_ack_frame.packets.Max()); } @@ -5782,12 +5755,11 @@ TEST_P(QuicFramerTest, StopPacketProcessing) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // frame type (stream frame with fin) 0xFF, @@ -5820,12 +5792,11 @@ TEST_P(QuicFramerTest, StopPacketProcessing) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (stream frame with fin) 0xFF, @@ -5858,12 +5829,11 @@ TEST_P(QuicFramerTest, StopPacketProcessing) { unsigned char packet41[] = { // public flags (8 byte connection_id) - 0x38, + 0x28, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // frame type (stream frame with fin) 0xFF, @@ -5934,14 +5904,14 @@ TEST_P(QuicFramerTest, ConstructEncryptedPacket) { // Since we are using ConstructEncryptedPacket, we have to set the framer's // crypto to be Null. framer_.SetDecrypter(ENCRYPTION_NONE, - new NullDecrypter(framer_.perspective())); + QuicMakeUnique<NullDecrypter>(framer_.perspective())); framer_.SetEncrypter(ENCRYPTION_NONE, - new NullEncrypter(framer_.perspective())); + QuicMakeUnique<NullEncrypter>(framer_.perspective())); ParsedQuicVersionVector versions; versions.push_back(framer_.version()); std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( 42, false, false, kTestQuicStreamId, kTestString, - PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions)); + PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, &versions)); MockFramerVisitor visitor; framer_.set_visitor(&visitor); @@ -5970,14 +5940,14 @@ TEST_P(QuicFramerTest, ConstructMisFramedEncryptedPacket) { // Since we are using ConstructEncryptedPacket, we have to set the framer's // crypto to be Null. framer_.SetDecrypter(ENCRYPTION_NONE, - new NullDecrypter(framer_.perspective())); + QuicMakeUnique<NullDecrypter>(framer_.perspective())); framer_.SetEncrypter(ENCRYPTION_NONE, - new NullEncrypter(framer_.perspective())); + QuicMakeUnique<NullEncrypter>(framer_.perspective())); ParsedQuicVersionVector versions; versions.push_back(framer_.version()); std::unique_ptr<QuicEncryptedPacket> packet(ConstructMisFramedEncryptedPacket( 42, false, false, kTestQuicStreamId, kTestString, - PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions, + PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, &versions, Perspective::IS_CLIENT)); MockFramerVisitor visitor; @@ -6010,6 +5980,7 @@ extern "C" { void QuicFramerFuzzFunc(unsigned char* data, size_t size) { QuicFramer framer(AllSupportedVersions(), QuicTime::Zero(), Perspective::IS_SERVER); + ASSERT_EQ(GetQuicFlag(FLAGS_quic_supports_tls_handshake), true); const char* const packet_bytes = reinterpret_cast<const char*>(data); // Test the CryptoFramer. @@ -6032,12 +6003,11 @@ TEST_P(QuicFramerTest, FramerFuzzTest) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) - 0x3C, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, // private flags 0x00, @@ -6058,12 +6028,11 @@ TEST_P(QuicFramerTest, FramerFuzzTest) { unsigned char packet39[] = { // public flags (8 byte connection_id) - 0x3C, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // private flags 0x00, @@ -6084,12 +6053,11 @@ TEST_P(QuicFramerTest, FramerFuzzTest) { unsigned char packet41[] = { // public flags (8 byte connection_id) - 0x3C, + 0x2C, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number 0x12, 0x34, 0x56, 0x78, - 0x9A, 0xBC, // private flags 0x00, diff --git a/chromium/net/quic/core/quic_headers_stream.cc b/chromium/net/quic/core/quic_headers_stream.cc index 22da417ce0b..52e6c41917d 100644 --- a/chromium/net/quic/core/quic_headers_stream.cc +++ b/chromium/net/quic/core/quic_headers_stream.cc @@ -26,7 +26,8 @@ QuicHeadersStream::CompressedHeaderInfo::CompressedHeaderInfo( QuicHeadersStream::CompressedHeaderInfo::~CompressedHeaderInfo() {} QuicHeadersStream::QuicHeadersStream(QuicSpdySession* session) - : QuicStream(kHeadersStreamId, session), spdy_session_(session) { + : QuicStream(kHeadersStreamId, session, /*is_static=*/true), + spdy_session_(session) { // The headers stream is exempt from connection level flow control. DisableConnectionFlowControlForThisStream(); } diff --git a/chromium/net/quic/core/quic_headers_stream_test.cc b/chromium/net/quic/core/quic_headers_stream_test.cc index 30ca9007bc9..d515adcad4c 100644 --- a/chromium/net/quic/core/quic_headers_stream_test.cc +++ b/chromium/net/quic/core/quic_headers_stream_test.cc @@ -76,7 +76,8 @@ class MockVisitor : public SpdyFramerVisitorInterface { MOCK_METHOD2(OnRstStream, void(SpdyStreamId stream_id, SpdyErrorCode error_code)); MOCK_METHOD0(OnSettings, void()); - MOCK_METHOD2(OnSetting, void(SpdyKnownSettingsId id, uint32_t value)); + MOCK_METHOD2(OnSettingOld, void(SpdyKnownSettingsId id, uint32_t value)); + MOCK_METHOD2(OnSetting, void(SpdySettingsId id, uint32_t value)); MOCK_METHOD0(OnSettingsAck, void()); MOCK_METHOD0(OnSettingsEnd, void()); MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack)); @@ -167,10 +168,11 @@ class QuicHeadersStreamTest : public QuicTestWithParam<TestParams> { perspective(), GetVersion())), session_(connection_), - headers_stream_(QuicSpdySessionPeer::GetHeadersStream(&session_)), body_("hello world"), stream_frame_(kHeadersStreamId, /*fin=*/false, /*offset=*/0, ""), next_promised_stream_id_(2) { + session_.Initialize(); + headers_stream_ = QuicSpdySessionPeer::GetHeadersStream(&session_); headers_[":version"] = "HTTP/1.1"; headers_[":status"] = "200 Ok"; headers_["content-length"] = "11"; diff --git a/chromium/net/quic/core/quic_ietf_framer_test.cc b/chromium/net/quic/core/quic_ietf_framer_test.cc index 5373d6fcf31..daed5d083e9 100644 --- a/chromium/net/quic/core/quic_ietf_framer_test.cc +++ b/chromium/net/quic/core/quic_ietf_framer_test.cc @@ -96,20 +96,20 @@ class QuicIetfFramerTest : public QuicTestWithParam<ParsedQuicVersion> { QuicStreamFrame source_stream_frame( stream_id, fin_bit, offset, xmit_packet_data, xmit_packet_data_size); - // write the frame to the packet buffer. + // Write the frame to the packet buffer. EXPECT_TRUE(QuicFramerPeer::AppendIetfStreamFrame( &framer_, source_stream_frame, last_frame_bit, &writer)); - // better have something in the packet buffer. + // Better have something in the packet buffer. EXPECT_NE(0u, writer.length()); - // now set up a reader to read in the thing in. + // Now set up a reader to read in the frame. QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); - // read in the frame type + // Read in the frame type uint8_t received_frame_type; EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); EXPECT_EQ(received_frame_type, frame_type); - // a StreamFrame to hold the results... we know the frame type, + // A StreamFrame to hold the results... we know the frame type, // put it into the QuicIetfStreamFrame QuicStreamFrame sink_stream_frame; @@ -123,10 +123,10 @@ class QuicIetfFramerTest : public QuicTestWithParam<ParsedQuicVersion> { EXPECT_EQ(sink_stream_frame.fin, source_stream_frame.fin); EXPECT_EQ(sink_stream_frame.data_length, source_stream_frame.data_length); if (frame_type & IETF_STREAM_FRAME_OFF_BIT) { - // there was an offset in the frame, see if xmit and rcv vales equal. + // There was an offset in the frame, see if xmit and rcv vales equal. EXPECT_EQ(sink_stream_frame.offset, source_stream_frame.offset); } else { - // offset not in frame, so it better come out 0. + // Offset not in frame, so it better come out 0. EXPECT_EQ(sink_stream_frame.offset, 0u); } EXPECT_NE(sink_stream_frame.data_buffer, nullptr); @@ -157,15 +157,14 @@ class QuicIetfFramerTest : public QuicTestWithParam<ParsedQuicVersion> { QuicAckFrame transmit_frame = InitAckFrame(frame->ranges); transmit_frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(frame->delay_time); - QUIC_LOG(INFO) << "XXXXXXXXXX transmit frame is " << transmit_frame; - // write the frame to the packet buffer. - EXPECT_TRUE(QuicFramerPeer::AppendIetfAckFrameAndTypeByte( - &framer_, transmit_frame, &writer)); - // better have something in the packet buffer. + // Write the frame to the packet buffer. + EXPECT_TRUE( + QuicFramerPeer::AppendIetfAckFrame(&framer_, transmit_frame, &writer)); + // Better have something in the packet buffer. EXPECT_NE(0u, writer.length()); - // now set up a reader to read in the thing in. + // Now set up a reader to read in the frame. QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); // read in the frame type @@ -179,7 +178,7 @@ class QuicIetfFramerTest : public QuicTestWithParam<ParsedQuicVersion> { EXPECT_TRUE(QuicFramerPeer::ProcessIetfAckFrame( &framer_, &reader, received_frame_type, &receive_frame)); - // Now check that things are correct + // Now check that the received frame matches the sent frame. EXPECT_EQ(transmit_frame.largest_acked, receive_frame.largest_acked); // The ~0x7 needs some explaining. The ack frame format down shifts the // delay time by 3 (divide by 8) to allow for greater ranges in delay time. @@ -205,6 +204,121 @@ class QuicIetfFramerTest : public QuicTestWithParam<ParsedQuicVersion> { return true; } + // encode, decode, and check a Path Challenge frame. + bool TryPathChallengeFrame(char* packet_buffer, + size_t packet_buffer_size, + const QuicPathFrameBuffer& data) { + // Make a writer so that the serialized packet is placed in + // packet_buffer. + QuicDataWriter writer(packet_buffer_size, packet_buffer, + NETWORK_BYTE_ORDER); + + QuicPathChallengeFrame transmit_frame(0, data); + + // write the frame to the packet buffer. + EXPECT_TRUE(QuicFramerPeer::AppendIetfPathChallengeFrame( + &framer_, transmit_frame, &writer)); + + // Check for correct length in the packet buffer. + EXPECT_EQ(kQuicPathChallengeFrameSize, writer.length()); + + // now set up a reader to read in the frame. + QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + + // read in the frame type + uint8_t received_frame_type; + EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); + EXPECT_EQ(received_frame_type, IETF_PATH_CHALLENGE); + + QuicPathChallengeFrame receive_frame; + + EXPECT_TRUE(QuicFramerPeer::ProcessIetfPathChallengeFrame(&framer_, &reader, + &receive_frame)); + + // Now check that the received frame matches the sent frame. + EXPECT_EQ( + 0, memcmp(transmit_frame.data_buffer.data(), + receive_frame.data_buffer.data(), kQuicPathFrameBufferSize)); + return true; + } + + // encode, decode, and check a Path Response frame. + bool TryPathResponseFrame(char* packet_buffer, + size_t packet_buffer_size, + const QuicPathFrameBuffer& data) { + // Make a writer so that the serialized packet is placed in + // packet_buffer. + QuicDataWriter writer(packet_buffer_size, packet_buffer, + NETWORK_BYTE_ORDER); + + QuicPathResponseFrame transmit_frame(0, data); + + // Write the frame to the packet buffer. + EXPECT_TRUE(QuicFramerPeer::AppendIetfPathResponseFrame( + &framer_, transmit_frame, &writer)); + + // Check for correct length in the packet buffer. + EXPECT_EQ(kQuicPathResponseFrameSize, writer.length()); + + // Set up a reader to read in the frame. + QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + + // Read in the frame type + uint8_t received_frame_type; + EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); + EXPECT_EQ(received_frame_type, IETF_PATH_RESPONSE); + + QuicPathResponseFrame receive_frame; + + EXPECT_TRUE(QuicFramerPeer::ProcessIetfPathResponseFrame(&framer_, &reader, + &receive_frame)); + + // Now check that the received frame matches the sent frame. + EXPECT_EQ( + 0, memcmp(transmit_frame.data_buffer.data(), + receive_frame.data_buffer.data(), kQuicPathFrameBufferSize)); + return true; + } + + // Test the Serialization/deserialization of a Reset Stream Frame. + void TryResetFrame(char* packet_buffer, + size_t packet_buffer_size, + QuicStreamId stream_id, + QuicRstStreamErrorCode error_code, + QuicStreamOffset final_offset) { + // Initialize a writer so that the serialized packet is placed in + // packet_buffer. + QuicDataWriter writer(packet_buffer_size, packet_buffer, + NETWORK_BYTE_ORDER); + + QuicRstStreamFrame transmit_frame(static_cast<QuicControlFrameId>(1), + stream_id, error_code, final_offset); + + // Write the frame to the packet buffer. + EXPECT_TRUE(QuicFramerPeer::AppendIetfResetStreamFrame( + &framer_, transmit_frame, &writer)); + // Check that the size of the serialzed frame is in the allowed range. + EXPECT_LT(4u, writer.length()); + EXPECT_GT(20u, writer.length()); + // Now set up a reader to read in the thing in. + QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + + // Read in the frame type and check that it is IETF_RST_STREAM. + uint8_t received_frame_type; + EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); + EXPECT_EQ(received_frame_type, QuicIetfFrameType::IETF_RST_STREAM); + + // A QuicRstStreamFrame to hold the results + QuicRstStreamFrame receive_frame; + EXPECT_TRUE(QuicFramerPeer::ProcessIetfResetStreamFrame(&framer_, &reader, + &receive_frame)); + + // Now check that the received values match the input. + EXPECT_EQ(receive_frame.stream_id, transmit_frame.stream_id); + EXPECT_EQ(receive_frame.error_code, transmit_frame.error_code); + EXPECT_EQ(receive_frame.byte_offset, transmit_frame.byte_offset); + } + QuicTime start_; QuicFramer framer_; }; @@ -372,11 +486,7 @@ TEST_F(QuicIetfFramerTest, StreamFrame) { } } -// tests for the ietf connection/application close frames. -// These are not regular enough to be table driven, so doing -// explicit tests is what we need to do... - -TEST_F(QuicIetfFramerTest, ConnectionClose1) { +TEST_F(QuicIetfFramerTest, ConnectionCloseEmptyString) { char packet_buffer[kNormalPacketBufferSize]; // initialize a writer so that the serialized packet is placed in @@ -384,16 +494,19 @@ TEST_F(QuicIetfFramerTest, ConnectionClose1) { QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, NETWORK_BYTE_ORDER); - QuicString test_string = "This is a test of the emergency broadcast system"; + // empty string, + QuicString test_string = "Ich Bin Ein Jelly Donut?"; + QuicConnectionCloseFrame sent_frame; + sent_frame.error_code = static_cast<QuicErrorCode>(0); + sent_frame.error_details = test_string; // write the frame to the packet buffer. EXPECT_TRUE(QuicFramerPeer::AppendIetfConnectionCloseFrame( - &framer_, QuicIetfTransportErrorCodes::VERSION_NEGOTIATION_ERROR, - test_string, &writer)); + &framer_, sent_frame, &writer)); // better have something in the packet buffer. EXPECT_NE(0u, writer.length()); - // now set up a reader to read in the thing in. + // now set up a reader to read in the frame. QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); // read in the frame type @@ -408,14 +521,11 @@ TEST_F(QuicIetfFramerTest, ConnectionClose1) { &framer_, &reader, received_frame_type, &sink_frame)); // Now check that received == sent - EXPECT_EQ(sink_frame.error_code, - static_cast<QuicErrorCode>( - QuicIetfTransportErrorCodes::VERSION_NEGOTIATION_ERROR)); + EXPECT_EQ(sink_frame.error_code, static_cast<QuicErrorCode>(0)); EXPECT_EQ(sink_frame.error_details, test_string); } -// test case of having no string. also the 0 error code, -TEST_F(QuicIetfFramerTest, ConnectionClose2) { +TEST_F(QuicIetfFramerTest, ApplicationCloseEmptyString) { char packet_buffer[kNormalPacketBufferSize]; // initialize a writer so that the serialized packet is placed in @@ -424,212 +534,515 @@ TEST_F(QuicIetfFramerTest, ConnectionClose2) { NETWORK_BYTE_ORDER); // empty string, - QuicString test_string; + QuicString test_string = "Ich Bin Ein Jelly Donut?"; + QuicConnectionCloseFrame sent_frame; + sent_frame.error_code = static_cast<QuicErrorCode>(0); + sent_frame.error_details = test_string; // write the frame to the packet buffer. - EXPECT_TRUE(QuicFramerPeer::AppendIetfConnectionCloseFrame( - &framer_, - QuicIetfTransportErrorCodes::NO_IETF_QUIC_ERROR, // NO_ERROR == 0 - test_string, &writer)); + EXPECT_TRUE(QuicFramerPeer::AppendIetfApplicationCloseFrame( + &framer_, sent_frame, &writer)); // better have something in the packet buffer. EXPECT_NE(0u, writer.length()); - // now set up a reader to read in the thing in. + // now set up a reader to read in the frame. QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); // read in the frame type uint8_t received_frame_type; EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); - EXPECT_EQ(received_frame_type, QuicIetfFrameType::IETF_CONNECTION_CLOSE); + EXPECT_EQ(received_frame_type, QuicIetfFrameType::IETF_APPLICATION_CLOSE); // a QuicConnectionCloseFrame to hold the results. QuicConnectionCloseFrame sink_frame; - EXPECT_TRUE(QuicFramerPeer::ProcessIetfConnectionCloseFrame( + EXPECT_TRUE(QuicFramerPeer::ProcessIetfApplicationCloseFrame( &framer_, &reader, received_frame_type, &sink_frame)); // Now check that received == sent - EXPECT_EQ(sink_frame.error_code, - static_cast<QuicErrorCode>( - QuicIetfTransportErrorCodes::NO_IETF_QUIC_ERROR)); + EXPECT_EQ(sink_frame.error_code, static_cast<QuicErrorCode>(0)); EXPECT_EQ(sink_frame.error_details, test_string); } -// Set fields of the frame via a QuicConnectionClose object -// test case of having no string. also the 0 error code, -TEST_F(QuicIetfFramerTest, ConnectionClose3) { + +// Testing for the IETF ACK framer. +// clang-format off +struct ack_frame ack_frame_variants[] = { + { 90000, {{1000, 2001}} }, + { 0, {{1000, 2001}} }, + { 1, {{1, 2}, {5, 6}} }, + { 63, {{1, 2}, {5, 6}} }, + { 64, {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}}}, + { 10000, {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}}}, + { 100000000, {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}}}, +}; +// clang-format on + +TEST_F(QuicIetfFramerTest, AckFrame) { char packet_buffer[kNormalPacketBufferSize]; + for (auto ack_frame_variant : ack_frame_variants) { + EXPECT_TRUE( + TryAckFrame(packet_buffer, sizeof(packet_buffer), &ack_frame_variant)); + } +} - // initialize a writer so that the serialized packet is placed in - // packet_buffer. +TEST_F(QuicIetfFramerTest, PaddingEntirePacket) { + char packet_buffer[kNormalPacketBufferSize]; + + // ensure that buffer is not all 0 prior to the test. + memset(packet_buffer, 0xff, sizeof(packet_buffer)); + + // Set up the writer and transmit QuicPaddingFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, NETWORK_BYTE_ORDER); + QuicPaddingFrame transmit_frame(sizeof(packet_buffer)); - // empty string, - QuicString test_string = "Ich Bin Ein Jelly Donut?"; - QuicConnectionCloseFrame sent_frame; - sent_frame.error_code = static_cast<QuicErrorCode>(0); - sent_frame.error_details = test_string; - // write the frame to the packet buffer. - EXPECT_TRUE(QuicFramerPeer::AppendIetfConnectionCloseFrame( - &framer_, sent_frame, &writer)); + // Fill buffer with padding. + EXPECT_TRUE(QuicFramerPeer::AppendIetfPaddingFrame(&framer_, transmit_frame, + &writer)); - // better have something in the packet buffer. - EXPECT_NE(0u, writer.length()); + // better have written to the entire packet buffer. + EXPECT_EQ(kNormalPacketBufferSize, writer.length()); - // now set up a reader to read in the thing in. + // see if entire buffer is 0 + for (auto i = 0; i != sizeof(packet_buffer); i++) { + EXPECT_EQ(0, packet_buffer[i]) + << "Packet_buffer[" << i << "] is " << packet_buffer[i] << " not 0x00"; + } + + // set up reader and empty receive QuicPaddingFrame. QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicPaddingFrame receive_frame; // read in the frame type uint8_t received_frame_type; EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); - EXPECT_EQ(received_frame_type, QuicIetfFrameType::IETF_CONNECTION_CLOSE); - - // a QuicConnectionCloseFrame to hold the results. - QuicConnectionCloseFrame sink_frame; + EXPECT_EQ(received_frame_type, 0u); - EXPECT_TRUE(QuicFramerPeer::ProcessIetfConnectionCloseFrame( - &framer_, &reader, received_frame_type, &sink_frame)); + // deframe it + QuicFramerPeer::ProcessIetfPaddingFrame(&framer_, &reader, &receive_frame); // Now check that received == sent - EXPECT_EQ(sink_frame.error_code, static_cast<QuicErrorCode>(0)); - EXPECT_EQ(sink_frame.error_details, test_string); + EXPECT_EQ(transmit_frame.num_padding_bytes, receive_frame.num_padding_bytes); + int packet_buffer_size = static_cast<int>(sizeof(packet_buffer)); + EXPECT_EQ(packet_buffer_size, receive_frame.num_padding_bytes); + EXPECT_EQ(packet_buffer_size, transmit_frame.num_padding_bytes); } -TEST_F(QuicIetfFramerTest, ApplicationClose1) { +// Place a padding frame between two non-padding frames: +// app_close +// padding +// connection_close +// we do a loop, with different amounts of padding in each. +TEST_F(QuicIetfFramerTest, PaddingSandwich) { + int pad_lengths[] = {1, 2, 5, 10, 20, 50, 100, 200, 500, 0}; + int* pad_length = pad_lengths; + while (*pad_length) { + char packet_buffer[kNormalPacketBufferSize]; + + // ensure that buffer is not all 0 prior to the test. + memset(packet_buffer, 0xff, sizeof(packet_buffer)); + + // Set up the writer and transmit Quic...Frames + QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, + NETWORK_BYTE_ORDER); + QuicPaddingFrame transmit_pad_frame(*pad_length); + QuicString app_close_test_string = "Ich Bin Ein Jelly Donut?"; + QuicConnectionCloseFrame transmit_app_close_frame; + transmit_app_close_frame.error_code = static_cast<QuicErrorCode>(0); + transmit_app_close_frame.error_details = app_close_test_string; + + QuicString conn_close_test_string = "I am a Berliner?"; + QuicConnectionCloseFrame transmit_conn_close_frame; + transmit_conn_close_frame.error_code = static_cast<QuicErrorCode>(0); + transmit_conn_close_frame.error_details = conn_close_test_string; + + // Put in the frames. App close first. + EXPECT_TRUE(QuicFramerPeer::AppendIetfApplicationCloseFrame( + &framer_, transmit_app_close_frame, &writer)); + + size_t pre_padding_len = writer.length(); + // padding next. + EXPECT_TRUE(QuicFramerPeer::AppendIetfPaddingFrame( + &framer_, transmit_pad_frame, &writer)); + size_t post_padding_len = writer.length(); + EXPECT_EQ(static_cast<int>(post_padding_len - pre_padding_len), + *pad_length); + + // finally, connection close + EXPECT_TRUE(QuicFramerPeer::AppendIetfConnectionCloseFrame( + &framer_, transmit_conn_close_frame, &writer)); + + // see if buffer from offset pre_padding_len, for *pad_len, is 0 + for (auto i = pre_padding_len; i != pre_padding_len + (*pad_length); i++) { + EXPECT_EQ(0, packet_buffer[i]) << "Packet_buffer[" << i << "] is " + << packet_buffer[i] << " not 0x00"; + } + + // set up reader and empty receive QuicFrames. + QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicPaddingFrame receive_pad_frame; + QuicConnectionCloseFrame receive_app_close_frame; + QuicConnectionCloseFrame receive_conn_close_frame; + + // read in the frame type and data for the app-close frame + uint8_t received_frame_type; + EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); + EXPECT_EQ(received_frame_type, IETF_APPLICATION_CLOSE); + EXPECT_TRUE(QuicFramerPeer::ProcessIetfApplicationCloseFrame( + &framer_, &reader, received_frame_type, &receive_app_close_frame)); + + // Now the padding. + EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); + EXPECT_EQ(received_frame_type, IETF_PADDING); + QuicFramerPeer::ProcessIetfPaddingFrame(&framer_, &reader, + &receive_pad_frame); + // check that pad size is correct + EXPECT_EQ(receive_pad_frame.num_padding_bytes, *pad_length); + + // Now get the connection close frame. + EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); + EXPECT_EQ(received_frame_type, IETF_CONNECTION_CLOSE); + EXPECT_TRUE(QuicFramerPeer::ProcessIetfConnectionCloseFrame( + &framer_, &reader, received_frame_type, &receive_conn_close_frame)); + + pad_length++; + } +} + +TEST_F(QuicIetfFramerTest, PathChallengeFrame) { + // Double-braces needed on some platforms due to + // https://bugs.llvm.org/show_bug.cgi?id=21629 + QuicPathFrameBuffer buffer0 = {{0, 0, 0, 0, 0, 0, 0, 0}}; + QuicPathFrameBuffer buffer1 = { + {0x80, 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe5, 0xf7}}; char packet_buffer[kNormalPacketBufferSize]; + EXPECT_TRUE( + TryPathChallengeFrame(packet_buffer, sizeof(packet_buffer), buffer0)); + EXPECT_TRUE( + TryPathChallengeFrame(packet_buffer, sizeof(packet_buffer), buffer1)); +} - // initialize a writer so that the serialized packet is placed in +TEST_F(QuicIetfFramerTest, PathResponseFrame) { + // Double-braces needed on some platforms due to + // https://bugs.llvm.org/show_bug.cgi?id=21629 + QuicPathFrameBuffer buffer0 = {{0, 0, 0, 0, 0, 0, 0, 0}}; + QuicPathFrameBuffer buffer1 = { + {0x80, 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe5, 0xf7}}; + char packet_buffer[kNormalPacketBufferSize]; + EXPECT_TRUE( + TryPathResponseFrame(packet_buffer, sizeof(packet_buffer), buffer0)); + EXPECT_TRUE( + TryPathResponseFrame(packet_buffer, sizeof(packet_buffer), buffer1)); +} + +TEST_F(QuicIetfFramerTest, ResetStreamFrame) { + char packet_buffer[kNormalPacketBufferSize]; + struct resets { + QuicStreamId stream_id; + QuicRstStreamErrorCode error_code; + QuicStreamOffset final_offset; + } reset_frames[] = { + {0, QUIC_STREAM_NO_ERROR, 0}, {0x10, QUIC_HEADERS_TOO_LARGE, 0x300}, + }; + for (auto reset : reset_frames) { + TryResetFrame(packet_buffer, sizeof(packet_buffer), reset.stream_id, + reset.error_code, reset.final_offset); + } +} + +TEST_F(QuicIetfFramerTest, StopSendingFrame) { + char packet_buffer[kNormalPacketBufferSize]; + + // Make a writer so that the serialized packet is placed in // packet_buffer. QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, NETWORK_BYTE_ORDER); - QuicString test_string = "This is a test of the emergency broadcast system"; - // write the frame to the packet buffer. - EXPECT_TRUE(QuicFramerPeer::AppendIetfApplicationCloseFrame( - &framer_, - static_cast<uint16_t>(QuicErrorCode::QUIC_CRYPTO_VERSION_NOT_SUPPORTED), - test_string, &writer)); + QuicStopSendingFrame transmit_frame; + transmit_frame.stream_id = 12345; + transmit_frame.application_error_code = 543; - // better have something in the packet buffer. - EXPECT_NE(0u, writer.length()); + // Write the frame to the packet buffer. + EXPECT_TRUE(QuicFramerPeer::AppendIetfStopSendingFrame( + &framer_, transmit_frame, &writer)); + // Check that the number of bytes in the buffer is in the + // allowed range. + EXPECT_LE(4u, writer.length()); + EXPECT_GE(11u, writer.length()); - // now set up a reader to read in the thing in. QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); - // read in the frame type + // Read in the frame type uint8_t received_frame_type; EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); - EXPECT_EQ(received_frame_type, QuicIetfFrameType::IETF_APPLICATION_CLOSE); + EXPECT_EQ(received_frame_type, IETF_STOP_SENDING); - // a QuicConnectionCloseFrame to hold the results. - QuicConnectionCloseFrame sink_frame; + // A frame to hold the results + QuicStopSendingFrame receive_frame; - EXPECT_TRUE(QuicFramerPeer::ProcessIetfApplicationCloseFrame( - &framer_, &reader, received_frame_type, &sink_frame)); + EXPECT_TRUE(QuicFramerPeer::ProcessIetfStopSendingFrame(&framer_, &reader, + &receive_frame)); - // Now check that received == sent - EXPECT_EQ(sink_frame.error_code, - QuicErrorCode::QUIC_CRYPTO_VERSION_NOT_SUPPORTED); - EXPECT_EQ(sink_frame.error_details, test_string); + // Verify that the transmitted and received values are the same. + EXPECT_EQ(receive_frame.stream_id, 12345u); + EXPECT_EQ(receive_frame.application_error_code, 543u); + EXPECT_EQ(receive_frame.stream_id, transmit_frame.stream_id); + EXPECT_EQ(receive_frame.application_error_code, + transmit_frame.application_error_code); } -// test case of having no string. also the 0 error code, -TEST_F(QuicIetfFramerTest, ApplicationClose2) { +TEST_F(QuicIetfFramerTest, MaxDataFrame) { char packet_buffer[kNormalPacketBufferSize]; + QuicStreamOffset window_sizes[] = {0, 1, 2, 5, 10, + 20, 50, 100, 200, 500, + 1000000, kOffset8, kOffset4, kOffset2}; + for (QuicStreamOffset window_size : window_sizes) { + memset(packet_buffer, 0, sizeof(packet_buffer)); + + // Set up the writer and transmit QuicWindowUpdateFrame + QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, + NETWORK_BYTE_ORDER); + QuicWindowUpdateFrame transmit_frame(0, 99, window_size); - // initialize a writer so that the serialized packet is placed in - // packet_buffer. - QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + // Add the frame. + EXPECT_TRUE(QuicFramerPeer::AppendIetfMaxDataFrame(&framer_, transmit_frame, + &writer)); - // empty string, - QuicString test_string; - // write the frame to the packet buffer. - EXPECT_TRUE(QuicFramerPeer::AppendIetfApplicationCloseFrame( - &framer_, 0, test_string, &writer)); + // Check that the number of bytes in the buffer is in the expected range. + EXPECT_LE(2u, writer.length()); + EXPECT_GE(9u, writer.length()); - // better have something in the packet buffer. - EXPECT_NE(0u, writer.length()); + // Set up reader and an empty QuicWindowUpdateFrame + QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicWindowUpdateFrame receive_frame; - // now set up a reader to read in the thing in. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + // Read in the frame type + uint8_t received_frame_type; + EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); + EXPECT_EQ(received_frame_type, IETF_MAX_DATA); - // read in the frame type - uint8_t received_frame_type; - EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); - EXPECT_EQ(received_frame_type, QuicIetfFrameType::IETF_APPLICATION_CLOSE); + // Deframe it + EXPECT_TRUE(QuicFramerPeer::ProcessIetfMaxDataFrame(&framer_, &reader, + &receive_frame)); - // a QuicConnectionCloseFrame to hold the results. - QuicConnectionCloseFrame sink_frame; + // Now check that the received data equals the sent data. + EXPECT_EQ(transmit_frame.byte_offset, window_size); + EXPECT_EQ(transmit_frame.byte_offset, receive_frame.byte_offset); + EXPECT_EQ(0u, receive_frame.stream_id); + } +} - EXPECT_TRUE(QuicFramerPeer::ProcessIetfApplicationCloseFrame( - &framer_, &reader, received_frame_type, &sink_frame)); +TEST_F(QuicIetfFramerTest, MaxStreamDataFrame) { + char packet_buffer[kNormalPacketBufferSize]; + QuicStreamOffset window_sizes[] = {0, 1, 2, 5, 10, + 20, 50, 100, 200, 500, + 1000000, kOffset8, kOffset4, kOffset2}; + QuicIetfStreamId stream_ids[] = {kStreamId4, kStreamId2, kStreamId1, + kStreamId0}; + + for (QuicIetfStreamId stream_id : stream_ids) { + for (QuicStreamOffset window_size : window_sizes) { + memset(packet_buffer, 0, sizeof(packet_buffer)); + + // Set up the writer and transmit QuicWindowUpdateFrame + QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, + NETWORK_BYTE_ORDER); + QuicWindowUpdateFrame transmit_frame(0, stream_id, window_size); + + // Add the frame. + EXPECT_TRUE(QuicFramerPeer::AppendIetfMaxStreamDataFrame( + &framer_, transmit_frame, &writer)); + + // Check that number of bytes in the buffer is in the expected range. + EXPECT_LE(3u, writer.length()); + EXPECT_GE(17u, writer.length()); + + // Set up reader and empty receive QuicPaddingFrame. + QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicWindowUpdateFrame receive_frame; + + // Read in the frame type + uint8_t received_frame_type; + EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); + EXPECT_EQ(received_frame_type, IETF_MAX_STREAM_DATA); + + // Deframe it + EXPECT_TRUE(QuicFramerPeer::ProcessIetfMaxStreamDataFrame( + &framer_, &reader, &receive_frame)); + + // Now check that received data and sent data are equal. + EXPECT_EQ(transmit_frame.byte_offset, window_size); + EXPECT_EQ(transmit_frame.byte_offset, receive_frame.byte_offset); + EXPECT_EQ(stream_id, receive_frame.stream_id); + EXPECT_EQ(transmit_frame.stream_id, receive_frame.stream_id); + } + } +} - // Now check that received == sent - EXPECT_EQ(sink_frame.error_code, 0); - EXPECT_EQ(sink_frame.error_details, test_string); +TEST_F(QuicIetfFramerTest, MaxStreamIdFrame) { + char packet_buffer[kNormalPacketBufferSize]; + QuicIetfStreamId stream_ids[] = {kStreamId4, kStreamId2, kStreamId1, + kStreamId0}; + + for (QuicIetfStreamId stream_id : stream_ids) { + memset(packet_buffer, 0, sizeof(packet_buffer)); + + // Set up the writer and transmit QuicIetfMaxStreamIdFrame + QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, + NETWORK_BYTE_ORDER); + QuicIetfMaxStreamIdFrame transmit_frame(0, stream_id); + + // Add the frame. + EXPECT_TRUE(QuicFramerPeer::AppendIetfMaxStreamIdFrame( + &framer_, transmit_frame, &writer)); + + // Check that buffer length is in the expected range + EXPECT_LE(2u, writer.length()); + EXPECT_GE(9u, writer.length()); + + // Set up reader and empty receive QuicPaddingFrame. + QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicIetfMaxStreamIdFrame receive_frame; + + // Read in the frame type + uint8_t received_frame_type; + EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); + EXPECT_EQ(received_frame_type, IETF_MAX_STREAM_ID); + + // Deframe it + EXPECT_TRUE(QuicFramerPeer::ProcessIetfMaxStreamIdFrame(&framer_, &reader, + &receive_frame)); + + // Now check that received and sent data are equivalent + EXPECT_EQ(stream_id, receive_frame.max_stream_id); + EXPECT_EQ(transmit_frame.max_stream_id, receive_frame.max_stream_id); + } } -// Set fields of the frame via a QuicConnectionClose object wahoo -// test case of having no string. also the 0 error code, -TEST_F(QuicIetfFramerTest, ApplicationClose3) { +TEST_F(QuicIetfFramerTest, BlockedFrame) { char packet_buffer[kNormalPacketBufferSize]; + QuicStreamOffset offsets[] = {kOffset8, kOffset4, kOffset2, kOffset1, + kOffset0}; - // initialize a writer so that the serialized packet is placed in - // packet_buffer. - QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); + for (QuicStreamOffset offset : offsets) { + memset(packet_buffer, 0, sizeof(packet_buffer)); - // empty string, - QuicString test_string = "Ich Bin Ein Jelly Donut?"; - QuicConnectionCloseFrame sent_frame; - sent_frame.error_code = static_cast<QuicErrorCode>(0); - sent_frame.error_details = test_string; - // write the frame to the packet buffer. - EXPECT_TRUE(QuicFramerPeer::AppendIetfApplicationCloseFrame( - &framer_, sent_frame, &writer)); + // Set up the writer and transmit QuicIetfBlockedFrame + QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, + NETWORK_BYTE_ORDER); + QuicIetfBlockedFrame transmit_frame(0, offset); - // better have something in the packet buffer. - EXPECT_NE(0u, writer.length()); + // Add the frame. + EXPECT_TRUE(QuicFramerPeer::AppendIetfBlockedFrame(&framer_, transmit_frame, + &writer)); - // now set up a reader to read in the thing in. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + // Check that buffer length is in the expected range + EXPECT_LE(2u, writer.length()); + EXPECT_GE(9u, writer.length()); - // read in the frame type - uint8_t received_frame_type; - EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); - EXPECT_EQ(received_frame_type, QuicIetfFrameType::IETF_APPLICATION_CLOSE); + // Set up reader and empty receive QuicFrame. + QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicIetfBlockedFrame receive_frame; - // a QuicConnectionCloseFrame to hold the results. - QuicConnectionCloseFrame sink_frame; + // Read in the frame type + uint8_t received_frame_type; + EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); + EXPECT_EQ(received_frame_type, IETF_BLOCKED); - EXPECT_TRUE(QuicFramerPeer::ProcessIetfApplicationCloseFrame( - &framer_, &reader, received_frame_type, &sink_frame)); + // Deframe it + EXPECT_TRUE(QuicFramerPeer::ProcessIetfBlockedFrame(&framer_, &reader, + &receive_frame)); - // Now check that received == sent - EXPECT_EQ(sink_frame.error_code, static_cast<QuicErrorCode>(0)); - EXPECT_EQ(sink_frame.error_details, test_string); + // Check that received and sent data are equivalent + EXPECT_EQ(offset, receive_frame.offset); + EXPECT_EQ(transmit_frame.offset, receive_frame.offset); + } } -// Testing for the IETF ACK framer. -// clang-format off -struct ack_frame ack_frame_variants[] = { - { 90000, {{1000, 2001}} }, - { 0, {{1000, 2001}} }, - { 1, {{1, 2}, {5, 6}} }, - { 63, {{1, 2}, {5, 6}} }, - { 64, {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}}}, - { 10000, {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}}}, - { 100000000, {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}}}, -}; -// clang-format on +TEST_F(QuicIetfFramerTest, StreamBlockedFrame) { + char packet_buffer[kNormalPacketBufferSize]; + QuicStreamOffset offsets[] = {0, 1, 2, 5, 10, + 20, 50, 100, 200, 500, + 1000000, kOffset8, kOffset4, kOffset2}; + QuicIetfStreamId stream_ids[] = {kStreamId4, kStreamId2, kStreamId1, + kStreamId0}; + + for (QuicIetfStreamId stream_id : stream_ids) { + for (QuicStreamOffset offset : offsets) { + memset(packet_buffer, 0, sizeof(packet_buffer)); + + // Set up the writer and transmit QuicWindowUpdateFrame + QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, + NETWORK_BYTE_ORDER); + QuicWindowUpdateFrame transmit_frame(0, stream_id, offset); + + // Add the frame. + EXPECT_TRUE(QuicFramerPeer::AppendIetfStreamBlockedFrame( + &framer_, transmit_frame, &writer)); + + // Check that number of bytes in the buffer is in the expected range. + EXPECT_LE(3u, writer.length()); + EXPECT_GE(17u, writer.length()); + + // Set up reader and empty receive QuicPaddingFrame. + QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicWindowUpdateFrame receive_frame; + + // Read in the frame type + uint8_t received_frame_type; + EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); + EXPECT_EQ(received_frame_type, IETF_STREAM_BLOCKED); + + // Deframe it + EXPECT_TRUE(QuicFramerPeer::ProcessIetfStreamBlockedFrame( + &framer_, &reader, &receive_frame)); + + // Now check that received == sent + EXPECT_EQ(transmit_frame.byte_offset, offset); + EXPECT_EQ(transmit_frame.byte_offset, receive_frame.byte_offset); + EXPECT_EQ(stream_id, receive_frame.stream_id); + EXPECT_EQ(transmit_frame.stream_id, receive_frame.stream_id); + } + } +} -TEST_F(QuicIetfFramerTest, AckFrame) { +TEST_F(QuicIetfFramerTest, StreamIdBlockedFrame) { char packet_buffer[kNormalPacketBufferSize]; - for (auto ack_frame_variant : ack_frame_variants) { - QUIC_LOG(INFO) << "Doing an ack, delay = " << ack_frame_variant.delay_time; - EXPECT_TRUE( - TryAckFrame(packet_buffer, sizeof(packet_buffer), &ack_frame_variant)); + QuicIetfStreamId stream_ids[] = {kStreamId4, kStreamId2, kStreamId1, + kStreamId0}; + + for (QuicIetfStreamId stream_id : stream_ids) { + memset(packet_buffer, 0, sizeof(packet_buffer)); + + // Set up the writer and transmit QuicIetfStreamIdBlockedFrame + QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, + NETWORK_BYTE_ORDER); + QuicIetfStreamIdBlockedFrame transmit_frame(0, stream_id); + + // Add the frame. + EXPECT_TRUE(QuicFramerPeer::AppendIetfStreamIdBlockedFrame( + &framer_, transmit_frame, &writer)); + + // Check that buffer length is in the expected range + EXPECT_LE(2u, writer.length()); + EXPECT_GE(9u, writer.length()); + + // Set up reader and empty receive QuicPaddingFrame. + QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicIetfStreamIdBlockedFrame receive_frame; + + // Read in the frame type + uint8_t received_frame_type; + EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); + EXPECT_EQ(received_frame_type, IETF_STREAM_ID_BLOCKED); + + // Deframe it + EXPECT_TRUE(QuicFramerPeer::ProcessIetfStreamIdBlockedFrame( + &framer_, &reader, &receive_frame)); + + // Now check that received == sent + EXPECT_EQ(stream_id, receive_frame.stream_id); + EXPECT_EQ(transmit_frame.stream_id, receive_frame.stream_id); } } diff --git a/chromium/net/quic/core/quic_packet_creator.cc b/chromium/net/quic/core/quic_packet_creator.cc index 27ed0b93401..0d05a8c2dee 100644 --- a/chromium/net/quic/core/quic_packet_creator.cc +++ b/chromium/net/quic/core/quic_packet_creator.cc @@ -54,8 +54,8 @@ QuicPacketCreator::~QuicPacketCreator() { } void QuicPacketCreator::SetEncrypter(EncryptionLevel level, - QuicEncrypter* encrypter) { - framer_->SetEncrypter(level, encrypter); + std::unique_ptr<QuicEncrypter> encrypter) { + framer_->SetEncrypter(level, std::move(encrypter)); max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_); } @@ -182,7 +182,7 @@ void QuicPacketCreator::CreateStreamFrame(QuicStreamId id, QuicFrame* frame) { DCHECK_GT(max_packet_length_, StreamFramePacketOverhead(framer_->transport_version(), - connection_id_length_, kIncludeVersion, + GetConnectionIdLength(), kIncludeVersion, IncludeNonceInPublicHeader(), PACKET_6BYTE_PACKET_NUMBER, offset)); @@ -398,10 +398,10 @@ size_t QuicPacketCreator::PacketSize() { if (!queued_frames_.empty()) { return packet_size_; } - packet_size_ = - GetPacketHeaderSize(framer_->transport_version(), connection_id_length_, - send_version_in_packet_, IncludeNonceInPublicHeader(), - packet_.packet_number_length); + packet_size_ = GetPacketHeaderSize( + framer_->transport_version(), GetConnectionIdLength(), + IncludeVersionInHeader(), IncludeNonceInPublicHeader(), + GetPacketNumberLength()); return packet_size_; } @@ -467,10 +467,11 @@ void QuicPacketCreator::SerializePacket(char* encrypted_buffer, std::unique_ptr<QuicEncryptedPacket> QuicPacketCreator::SerializeVersionNegotiationPacket( + bool ietf_quic, const ParsedQuicVersionVector& supported_versions) { DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective()); std::unique_ptr<QuicEncryptedPacket> encrypted = - QuicFramer::BuildVersionNegotiationPacket(connection_id_, + QuicFramer::BuildVersionNegotiationPacket(connection_id_, ietf_quic, supported_versions); DCHECK(encrypted); DCHECK_GE(max_packet_length_, encrypted->length()); @@ -504,17 +505,25 @@ QuicPacketCreator::SerializeConnectivityProbingPacket() { return serialize_packet; } -// TODO(jri): Make this a public method of framer? +// TODO(b/74062209): Make this a public method of framer? SerializedPacket QuicPacketCreator::NoPacket() { return SerializedPacket(0, PACKET_1BYTE_PACKET_NUMBER, nullptr, 0, false, false); } +QuicConnectionIdLength QuicPacketCreator::GetConnectionIdLength() const { + return connection_id_length_; +} + +QuicPacketNumberLength QuicPacketCreator::GetPacketNumberLength() const { + return packet_.packet_number_length; +} + void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) { header->connection_id = connection_id_; - header->connection_id_length = connection_id_length_; + header->connection_id_length = GetConnectionIdLength(); header->reset_flag = false; - header->version_flag = send_version_in_packet_; + header->version_flag = IncludeVersionInHeader(); if (IncludeNonceInPublicHeader()) { DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective()); header->nonce = &diversification_nonce_; @@ -553,7 +562,7 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, } size_t frame_len = framer_->GetSerializedFrameLength( frame, BytesFree(), queued_frames_.empty(), true, - packet_.packet_number_length); + GetPacketNumberLength()); if (frame_len == 0) { // Current open packet is full. Flush(); @@ -618,11 +627,15 @@ void QuicPacketCreator::MaybeAddPadding() { DCHECK(success); } -bool QuicPacketCreator::IncludeNonceInPublicHeader() { +bool QuicPacketCreator::IncludeNonceInPublicHeader() const { return have_diversification_nonce_ && packet_.encryption_level == ENCRYPTION_INITIAL; } +bool QuicPacketCreator::IncludeVersionInHeader() const { + return send_version_in_packet_; +} + void QuicPacketCreator::AddPendingPadding(QuicByteCount size) { pending_padding_bytes_ += size; } @@ -644,8 +657,9 @@ void QuicPacketCreator::SetConnectionIdLength(QuicConnectionIdLength length) { void QuicPacketCreator::SetTransmissionType(TransmissionType type) { DCHECK(can_set_transmission_type_); - QUIC_DVLOG(1) << "Setting Transmission type to " - << QuicUtils::TransmissionTypeToString(type); + QUIC_DVLOG_IF(1, type != packet_.transmission_type) + << "Setting Transmission type to " + << QuicUtils::TransmissionTypeToString(type); packet_.transmission_type = type; } diff --git a/chromium/net/quic/core/quic_packet_creator.h b/chromium/net/quic/core/quic_packet_creator.h index b03e5803868..03af92ff215 100644 --- a/chromium/net/quic/core/quic_packet_creator.h +++ b/chromium/net/quic/core/quic_packet_creator.h @@ -153,6 +153,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Creates a version negotiation packet which supports |supported_versions|. std::unique_ptr<QuicEncryptedPacket> SerializeVersionNegotiationPacket( + bool ietf_quic, const ParsedQuicVersionVector& supported_versions); // Creates a connectivity probing packet. @@ -161,6 +162,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Returns a dummy packet that is valid but contains no useful information. static SerializedPacket NoPacket(); + // Returns length of connection ID to send over the wire. + QuicConnectionIdLength GetConnectionIdLength() const; + // Sets the encryption level that will be applied to new packets. void set_encryption_level(EncryptionLevel level) { packet_.encryption_level = level; @@ -170,10 +174,6 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // created. QuicPacketNumber packet_number() const { return packet_.packet_number; } - QuicConnectionIdLength connection_id_length() const { - return connection_id_length_; - } - void SetConnectionIdLength(QuicConnectionIdLength length); QuicByteCount max_packet_length() const { return max_packet_length_; } @@ -184,7 +184,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Sets the encrypter to use for the encryption level and updates the max // plaintext size. - void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter); + void SetEncrypter(EncryptionLevel level, + std::unique_ptr<QuicEncrypter> encrypter); // Indicates whether the packet creator is in a state where it can change // current maximum packet length. @@ -251,7 +252,15 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Returns true if a diversification nonce should be included in the current // packet's header. - bool IncludeNonceInPublicHeader(); + bool IncludeNonceInPublicHeader() const; + + // Returns true if version should be included in current packet's header. + bool IncludeVersionInHeader() const; + + // Returns length of packet number to send over the wire. + // packet_.packet_number_length should never be read directly, use this + // function instead. + QuicPacketNumberLength GetPacketNumberLength() const; // Returns true if |frame| starts with CHLO. bool StreamFrameStartsWithChlo(const QuicStreamFrame& frame) const; @@ -262,6 +271,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { QuicFramer* framer_; // Controls whether version should be included while serializing the packet. + // send_version_in_packet_ should never be read directly, use + // IncludeVersionInHeader() instead. bool send_version_in_packet_; // If true, then |diversification_nonce_| will be included in the header of // all packets created at the initial encryption level. @@ -270,7 +281,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Maximum length including headers and encryption (UDP payload length.) QuicByteCount max_packet_length_; size_t max_plaintext_size_; - // Length of connection_id to send over the wire. + // Length of connection_id to send over the wire. connection_id_length_ should + // never be read directly, use GetConnectionIdLength() instead. QuicConnectionIdLength connection_id_length_; // Frames to be added to the next SerializedPacket diff --git a/chromium/net/quic/core/quic_packet_creator_test.cc b/chromium/net/quic/core/quic_packet_creator_test.cc index 7dbb617d3ee..342b5b2ec2a 100644 --- a/chromium/net/quic/core/quic_packet_creator_test.cc +++ b/chromium/net/quic/core/quic_packet_creator_test.cc @@ -135,10 +135,11 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> { data_("foo"), creator_(connection_id_, &client_framer_, &delegate_, &producer_), serialized_packet_(creator_.NoPacket()) { - creator_.SetEncrypter(ENCRYPTION_INITIAL, - new NullEncrypter(Perspective::IS_CLIENT)); - creator_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, - new NullEncrypter(Perspective::IS_CLIENT)); + creator_.SetEncrypter(ENCRYPTION_INITIAL, QuicMakeUnique<NullEncrypter>( + Perspective::IS_CLIENT)); + creator_.SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT)); client_framer_.set_visitor(&framer_visitor_); server_framer_.set_visitor(&framer_visitor_); client_framer_.set_data_producer(&producer_); @@ -186,7 +187,8 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> { // the version. size_t GetPacketHeaderOverhead(QuicTransportVersion version) { return GetPacketHeaderSize( - version, creator_.connection_id_length(), kIncludeVersion, + version, creator_.GetConnectionIdLength(), + QuicPacketCreatorPeer::SendVersionInPacket(&creator_), !kIncludeDiversificationNonce, QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)); } @@ -668,7 +670,7 @@ TEST_P(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) { ParsedQuicVersionVector versions; versions.push_back(test::QuicVersionMax()); std::unique_ptr<QuicEncryptedPacket> encrypted( - creator_.SerializeVersionNegotiationPacket(versions)); + creator_.SerializeVersionNegotiationPacket(false, versions)); { InSequence s; @@ -798,8 +800,9 @@ TEST_P(QuicPacketCreatorTest, ConsumeDataLargerThanOneStreamFrame) { creator_.SetMaxPacketLength(GetPacketLengthForOneStream( client_framer_.transport_version(), QuicPacketCreatorPeer::SendVersionInPacket(&creator_), - !kIncludeDiversificationNonce, creator_.connection_id_length(), - PACKET_1BYTE_PACKET_NUMBER, &payload_length)); + !kIncludeDiversificationNonce, creator_.GetConnectionIdLength(), + QuicPacketCreatorPeer::GetPacketNumberLength(&creator_), + &payload_length)); QuicFrame frame; const QuicString too_long_payload(payload_length * 2, 'a'); MakeIOVector(too_long_payload, &iov_); @@ -827,9 +830,10 @@ TEST_P(QuicPacketCreatorTest, AddFrameAndFlush) { EXPECT_EQ(max_plaintext_size - GetPacketHeaderSize( client_framer_.transport_version(), - creator_.connection_id_length(), + creator_.GetConnectionIdLength(), QuicPacketCreatorPeer::SendVersionInPacket(&creator_), - !kIncludeDiversificationNonce, PACKET_1BYTE_PACKET_NUMBER), + !kIncludeDiversificationNonce, + QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)), creator_.BytesFree()); // Add a variety of frame types and then a padding frame. @@ -874,9 +878,10 @@ TEST_P(QuicPacketCreatorTest, AddFrameAndFlush) { EXPECT_EQ(max_plaintext_size - GetPacketHeaderSize( client_framer_.transport_version(), - creator_.connection_id_length(), + creator_.GetConnectionIdLength(), QuicPacketCreatorPeer::SendVersionInPacket(&creator_), - !kIncludeDiversificationNonce, PACKET_1BYTE_PACKET_NUMBER), + !kIncludeDiversificationNonce, + QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)), creator_.BytesFree()); } @@ -982,9 +987,9 @@ TEST_P(QuicPacketCreatorTest, SendPendingPaddingInRetransmission) { QuicFrames frames; frames.push_back(QuicFrame(stream_frame)); char buffer[kMaxPacketSize]; - QuicPendingRetransmission retransmission( - CreateRetransmission(frames, true, /*num_padding_bytes=*/0, - ENCRYPTION_NONE, PACKET_1BYTE_PACKET_NUMBER)); + QuicPendingRetransmission retransmission(CreateRetransmission( + frames, true, /*num_padding_bytes=*/0, ENCRYPTION_NONE, + QuicPacketCreatorPeer::GetPacketNumberLength(&creator_))); EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); creator_.AddPendingPadding(kMaxNumRandomPaddingBytes); diff --git a/chromium/net/quic/core/quic_packet_generator.cc b/chromium/net/quic/core/quic_packet_generator.cc index 85814b40409..5c2471c2f4d 100644 --- a/chromium/net/quic/core/quic_packet_generator.cc +++ b/chromium/net/quic/core/quic_packet_generator.cc @@ -309,8 +309,10 @@ void QuicPacketGenerator::SetMaxPacketLength(QuicByteCount length) { std::unique_ptr<QuicEncryptedPacket> QuicPacketGenerator::SerializeVersionNegotiationPacket( + bool ietf_quic, const ParsedQuicVersionVector& supported_versions) { - return packet_creator_.SerializeVersionNegotiationPacket(supported_versions); + return packet_creator_.SerializeVersionNegotiationPacket(ietf_quic, + supported_versions); } OwningSerializedPacketPointer @@ -344,9 +346,10 @@ void QuicPacketGenerator::set_encryption_level(EncryptionLevel level) { packet_creator_.set_encryption_level(level); } -void QuicPacketGenerator::SetEncrypter(EncryptionLevel level, - QuicEncrypter* encrypter) { - packet_creator_.SetEncrypter(level, encrypter); +void QuicPacketGenerator::SetEncrypter( + EncryptionLevel level, + std::unique_ptr<QuicEncrypter> encrypter) { + packet_creator_.SetEncrypter(level, std::move(encrypter)); } void QuicPacketGenerator::AddRandomPadding() { diff --git a/chromium/net/quic/core/quic_packet_generator.h b/chromium/net/quic/core/quic_packet_generator.h index f1cfd7978e9..08176a969ff 100644 --- a/chromium/net/quic/core/quic_packet_generator.h +++ b/chromium/net/quic/core/quic_packet_generator.h @@ -137,6 +137,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator { // Creates a version negotiation packet which supports |supported_versions|. std::unique_ptr<QuicEncryptedPacket> SerializeVersionNegotiationPacket( + bool ietf_quic, const ParsedQuicVersionVector& supported_versions); // Creates a connectivity probing packet. @@ -157,7 +158,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketGenerator { void SetConnectionIdLength(uint32_t length); // Sets the encrypter to use for the encryption level. - void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter); + void SetEncrypter(EncryptionLevel level, + std::unique_ptr<QuicEncrypter> encrypter); // Returns true if there are control frames or current constructed packet has // pending retransmittable frames. diff --git a/chromium/net/quic/core/quic_packet_generator_test.cc b/chromium/net/quic/core/quic_packet_generator_test.cc index 074eb4ebbdc..b2e4905f6cd 100644 --- a/chromium/net/quic/core/quic_packet_generator_test.cc +++ b/chromium/net/quic/core/quic_packet_generator_test.cc @@ -26,6 +26,7 @@ #include "net/quic/test_tools/simple_data_producer.h" #include "net/quic/test_tools/simple_quic_framer.h" +using std::string; using testing::_; using testing::InSequence; using testing::Return; @@ -150,8 +151,9 @@ class QuicPacketGeneratorTest : public QuicTest { Perspective::IS_CLIENT), generator_(42, &framer_, &random_generator_, &delegate_, &producer_), creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)) { - creator_->SetEncrypter(ENCRYPTION_FORWARD_SECURE, - new NullEncrypter(Perspective::IS_CLIENT)); + creator_->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT)); creator_->set_encryption_level(ENCRYPTION_FORWARD_SECURE); framer_.set_data_producer(&producer_); generator_.AttachPacketFlusher(); @@ -511,8 +513,9 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) { size_t length = NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + GetPacketHeaderSize( - framer_.transport_version(), creator_->connection_id_length(), - kIncludeVersion, !kIncludeDiversificationNonce, + framer_.transport_version(), creator_->GetConnectionIdLength(), + QuicPacketCreatorPeer::SendVersionInPacket(creator_), + !kIncludeDiversificationNonce, QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) + // Add an extra 3 bytes for the payload and 1 byte so BytesFree is larger // than the GetMinStreamFrameSize. @@ -774,11 +777,11 @@ TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) { TEST_F(QuicPacketGeneratorTest, TestConnectionIdLength) { QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); generator_.SetConnectionIdLength(0); - EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, creator_->connection_id_length()); + EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, creator_->GetConnectionIdLength()); for (size_t i = 1; i < 10; i++) { generator_.SetConnectionIdLength(i); - EXPECT_EQ(PACKET_8BYTE_CONNECTION_ID, creator_->connection_id_length()); + EXPECT_EQ(PACKET_8BYTE_CONNECTION_ID, creator_->GetConnectionIdLength()); } } @@ -1066,7 +1069,7 @@ TEST_F(QuicPacketGeneratorTest, ConnectionCloseFrameLargerThanPacketSize) { frame->error_code = QUIC_PACKET_WRITE_ERROR; char buf[2000] = {}; QuicStringPiece error_details(buf, 2000); - frame->error_details = error_details.as_string(); + frame->error_details = string(error_details); generator_.AddControlFrame(QuicFrame(frame)); EXPECT_TRUE(generator_.HasQueuedFrames()); EXPECT_TRUE(generator_.HasRetransmittableFrames()); @@ -1081,8 +1084,9 @@ TEST_F(QuicPacketGeneratorTest, RandomPaddingAfterFinSingleStreamSinglePacket) { size_t length = NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + GetPacketHeaderSize( - framer_.transport_version(), creator_->connection_id_length(), - kIncludeVersion, !kIncludeDiversificationNonce, + framer_.transport_version(), creator_->GetConnectionIdLength(), + QuicPacketCreatorPeer::SendVersionInPacket(creator_), + !kIncludeDiversificationNonce, QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) + QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), kDataStreamId, 0, @@ -1118,8 +1122,9 @@ TEST_F(QuicPacketGeneratorTest, size_t length = NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + GetPacketHeaderSize( - framer_.transport_version(), creator_->connection_id_length(), - kIncludeVersion, !kIncludeDiversificationNonce, + framer_.transport_version(), creator_->GetConnectionIdLength(), + QuicPacketCreatorPeer::SendVersionInPacket(creator_), + !kIncludeDiversificationNonce, QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) + QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), kDataStreamId, 0, @@ -1163,8 +1168,9 @@ TEST_F(QuicPacketGeneratorTest, size_t length = NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + GetPacketHeaderSize( - framer_.transport_version(), creator_->connection_id_length(), - kIncludeVersion, !kIncludeDiversificationNonce, + framer_.transport_version(), creator_->GetConnectionIdLength(), + QuicPacketCreatorPeer::SendVersionInPacket(creator_), + !kIncludeDiversificationNonce, QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) + QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), kDataStreamId1, 0, diff --git a/chromium/net/quic/core/quic_packets.cc b/chromium/net/quic/core/quic_packets.cc index 35013e0fadc..c157fd0ece0 100644 --- a/chromium/net/quic/core/quic_packets.cc +++ b/chromium/net/quic/core/quic_packets.cc @@ -53,7 +53,7 @@ QuicPacketHeader::QuicPacketHeader() connection_id_length(PACKET_8BYTE_CONNECTION_ID), reset_flag(false), version_flag(false), - packet_number_length(PACKET_6BYTE_PACKET_NUMBER), + packet_number_length(PACKET_4BYTE_PACKET_NUMBER), version( ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED)), nonce(nullptr), @@ -81,6 +81,19 @@ QuicVersionNegotiationPacket::QuicVersionNegotiationPacket( QuicVersionNegotiationPacket::~QuicVersionNegotiationPacket() {} +QuicIetfStatelessResetPacket::QuicIetfStatelessResetPacket() + : stateless_reset_token(0) {} + +QuicIetfStatelessResetPacket::QuicIetfStatelessResetPacket( + const QuicPacketHeader& header, + uint128 token) + : header(header), stateless_reset_token(token) {} + +QuicIetfStatelessResetPacket::QuicIetfStatelessResetPacket( + const QuicIetfStatelessResetPacket& other) = default; + +QuicIetfStatelessResetPacket::~QuicIetfStatelessResetPacket() {} + std::ostream& operator<<(std::ostream& os, const QuicPacketHeader& header) { os << "{ connection_id: " << header.connection_id << ", connection_id_length: " << header.connection_id_length diff --git a/chromium/net/quic/core/quic_packets.h b/chromium/net/quic/core/quic_packets.h index b3866c36557..085bb422df8 100644 --- a/chromium/net/quic/core/quic_packets.h +++ b/chromium/net/quic/core/quic_packets.h @@ -26,6 +26,7 @@ #include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_socket_address.h" #include "net/quic/platform/api/quic_string_piece.h" +#include "net/quic/platform/api/quic_uint128.h" namespace net { @@ -97,6 +98,17 @@ struct QUIC_EXPORT_PRIVATE QuicVersionNegotiationPacket { ParsedQuicVersionVector versions; }; +struct QUIC_EXPORT_PRIVATE QuicIetfStatelessResetPacket { + QuicIetfStatelessResetPacket(); + QuicIetfStatelessResetPacket(const QuicPacketHeader& header, + QuicUint128 token); + QuicIetfStatelessResetPacket(const QuicIetfStatelessResetPacket& other); + ~QuicIetfStatelessResetPacket(); + + QuicPacketHeader header; + QuicUint128 stateless_reset_token; +}; + class QUIC_EXPORT_PRIVATE QuicData { public: QuicData(const char* buffer, size_t length); diff --git a/chromium/net/quic/core/quic_sent_packet_manager.cc b/chromium/net/quic/core/quic_sent_packet_manager.cc index 5b61f6dd065..af956ea8c2f 100644 --- a/chromium/net/quic/core/quic_sent_packet_manager.cc +++ b/chromium/net/quic/core/quic_sent_packet_manager.cc @@ -31,8 +31,8 @@ static const int64_t kMaxRetransmissionTimeMs = 60000; static const size_t kMaxRetransmissions = 10; // Maximum number of packets retransmitted upon an RTO. static const size_t kMaxRetransmissionsOnTimeout = 2; -// Minimum number of consecutive RTOs before path is considered to be degrading. -const size_t kMinTimeoutsBeforePathDegrading = 2; +// The path degrading delay is the sum of this number of consecutive RTO delays. +const size_t kNumRetransmissionDelaysForPathDegradingDelay = 2; // Ensure the handshake timer isnt't faster than 10ms. // This limits the tenth retransmitted packet to 10s after the initial CHLO. @@ -90,7 +90,14 @@ QuicSentPacketManager::QuicSentPacketManager( handshake_confirmed_(false), largest_packet_peer_knows_is_acked_(0), delayed_ack_time_( - QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)) { + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)), + rtt_updated_(false), + acked_packets_iter_(last_ack_frame_.packets.rbegin()), + use_path_degrading_alarm_( + GetQuicReloadableFlag(quic_path_degrading_alarm)), + use_better_crypto_retransmission_( + GetQuicReloadableFlag(quic_better_crypto_retransmission)) { + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_better_crypto_retransmission); SetSendAlgorithm(congestion_control_type); } @@ -127,13 +134,11 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { min_rto_timeout_ = QuicTime::Delta::Zero(); } if (GetQuicReloadableFlag(quic_max_ack_delay2) && - GetQuicReloadableFlag(quic_min_rtt_ack_delay) && config.HasClientSentConnectionOption(kMAD4, perspective_)) { QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_max_ack_delay2, 3, 4); ietf_style_tlp_ = true; } if (GetQuicReloadableFlag(quic_max_ack_delay2) && - GetQuicReloadableFlag(quic_min_rtt_ack_delay) && config.HasClientSentConnectionOption(kMAD5, perspective_)) { QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_max_ack_delay2, 4, 4); ietf_style_2x_tlp_ = true; @@ -154,6 +159,25 @@ void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { config.HasClientRequestedIndependentOption(kTPCC, perspective_)) { SetSendAlgorithm(kPCC); } + // Initial window. + if (GetQuicReloadableFlag(quic_unified_iw_options)) { + if (config.HasClientRequestedIndependentOption(kIW03, perspective_)) { + initial_congestion_window_ = 3; + send_algorithm_->SetInitialCongestionWindowInPackets(3); + } + if (config.HasClientRequestedIndependentOption(kIW10, perspective_)) { + initial_congestion_window_ = 10; + send_algorithm_->SetInitialCongestionWindowInPackets(10); + } + if (config.HasClientRequestedIndependentOption(kIW20, perspective_)) { + initial_congestion_window_ = 20; + send_algorithm_->SetInitialCongestionWindowInPackets(20); + } + if (config.HasClientRequestedIndependentOption(kIW50, perspective_)) { + initial_congestion_window_ = 50; + send_algorithm_->SetInitialCongestionWindowInPackets(50); + } + } using_pacing_ = !FLAGS_quic_disable_pacing_for_perf_tests; @@ -237,21 +261,34 @@ void QuicSentPacketManager::SetHandshakeConfirmed() { handshake_confirmed_ = true; } -void QuicSentPacketManager::OnIncomingAck(const QuicAckFrame& ack_frame, +bool QuicSentPacketManager::OnIncomingAck(const QuicAckFrame& ack_frame, QuicTime ack_receive_time) { DCHECK_LE(LargestAcked(ack_frame), unacked_packets_.largest_sent_packet()); QuicByteCount prior_in_flight = unacked_packets_.bytes_in_flight(); - bool rtt_updated = MaybeUpdateRTT(ack_frame, ack_receive_time); + bool rtt_updated = MaybeUpdateRTT(LargestAcked(ack_frame), + ack_frame.ack_delay_time, ack_receive_time); DCHECK_GE(LargestAcked(ack_frame), unacked_packets_.largest_observed()); unacked_packets_.IncreaseLargestObserved(LargestAcked(ack_frame)); HandleAckForSentPackets(ack_frame); + const bool acked_new_packet = !packets_acked_.empty(); + PostProcessAfterMarkingPacketHandled(ack_frame, ack_receive_time, rtt_updated, + prior_in_flight); + return acked_new_packet; +} + +void QuicSentPacketManager::PostProcessAfterMarkingPacketHandled( + const QuicAckFrame& ack_frame, + QuicTime ack_receive_time, + bool rtt_updated, + QuicByteCount prior_bytes_in_flight) { InvokeLossDetection(ack_receive_time); // Ignore losses in RTO mode. if (consecutive_rto_count_ > 0 && !use_new_rto_) { packets_lost_.clear(); } - MaybeInvokeCongestionEvent(rtt_updated, prior_in_flight, ack_receive_time); + MaybeInvokeCongestionEvent(rtt_updated, prior_bytes_in_flight, + ack_receive_time); unacked_packets_.RemoveObsoletePackets(); sustained_bandwidth_recorder_.RecordEstimate( @@ -337,8 +374,8 @@ void QuicSentPacketManager::HandleAckForSentPackets( // If data is associated with the most recent transmission of this // packet, then inform the caller. if (it->in_flight) { - packets_acked_.push_back( - AckedPacket(packet_number, it->bytes_sent, QuicTime::Zero())); + packets_acked_.emplace_back(packet_number, it->bytes_sent, + QuicTime::Zero()); } else { // Unackable packets are skipped earlier. largest_newly_acked_ = packet_number; @@ -398,6 +435,9 @@ void QuicSentPacketManager::MarkForRetransmission( QuicTransmissionInfo* transmission_info = unacked_packets_.GetMutableTransmissionInfo(packet_number); QUIC_BUG_IF(!unacked_packets_.HasRetransmittableFrames(*transmission_info)); + // Handshake packets should never be sent as probing retransmissions. + DCHECK(!transmission_info->has_crypto_handshake || + transmission_type != PROBING_RETRANSMISSION); // Both TLP and the new RTO leave the packets in flight and let the loss // detection decide if packets are lost. if (transmission_type != TLP_RETRANSMISSION && @@ -572,6 +612,10 @@ bool QuicSentPacketManager::HasUnackedPackets() const { return unacked_packets_.HasUnackedPackets(); } +bool QuicSentPacketManager::HasUnackedCryptoPackets() const { + return unacked_packets_.HasPendingCryptoPackets(); +} + QuicPacketNumber QuicSentPacketManager::GetLeastUnacked() const { return unacked_packets_.GetLeastUnacked(); } @@ -646,10 +690,13 @@ void QuicSentPacketManager::OnRetransmissionTimeout() { case RTO_MODE: ++stats_->rto_count; RetransmitRtoPackets(); - if (!session_decides_what_to_write() && - network_change_visitor_ != nullptr && - consecutive_rto_count_ == kMinTimeoutsBeforePathDegrading) { - network_change_visitor_->OnPathDegrading(); + if (!use_path_degrading_alarm_) { + if (!session_decides_what_to_write() && + network_change_visitor_ != nullptr && + consecutive_rto_count_ == + kNumRetransmissionDelaysForPathDegradingDelay) { + network_change_visitor_->OnPathDegrading(); + } } return; } @@ -754,9 +801,12 @@ void QuicSentPacketManager::RetransmitRtoPackets() { ++consecutive_rto_count_; } if (session_decides_what_to_write()) { - if (network_change_visitor_ != nullptr && - consecutive_rto_count_ == kMinTimeoutsBeforePathDegrading) { - network_change_visitor_->OnPathDegrading(); + if (!use_path_degrading_alarm_) { + if (network_change_visitor_ != nullptr && + consecutive_rto_count_ == + kNumRetransmissionDelaysForPathDegradingDelay) { + network_change_visitor_->OnPathDegrading(); + } } for (QuicPacketNumber retransmission : retransmissions) { MarkForRetransmission(retransmission, RTO_RETRANSMISSION); @@ -809,26 +859,27 @@ void QuicSentPacketManager::InvokeLossDetection(QuicTime time) { } } -bool QuicSentPacketManager::MaybeUpdateRTT(const QuicAckFrame& ack_frame, +bool QuicSentPacketManager::MaybeUpdateRTT(QuicPacketNumber largest_acked, + QuicTime::Delta ack_delay_time, QuicTime ack_receive_time) { // We rely on ack_delay_time to compute an RTT estimate, so we // only update rtt when the largest observed gets acked. - if (!unacked_packets_.IsUnacked(LargestAcked(ack_frame))) { + if (!unacked_packets_.IsUnacked(largest_acked)) { return false; } // We calculate the RTT based on the highest ACKed packet number, the lower // packet numbers will include the ACK aggregation delay. const QuicTransmissionInfo& transmission_info = - unacked_packets_.GetTransmissionInfo(LargestAcked(ack_frame)); + unacked_packets_.GetTransmissionInfo(largest_acked); // Ensure the packet has a valid sent time. if (transmission_info.sent_time == QuicTime::Zero()) { QUIC_BUG << "Acked packet has zero sent time, largest_observed:" - << LargestAcked(ack_frame); + << largest_acked; return false; } QuicTime::Delta send_delta = ack_receive_time - transmission_info.sent_time; - rtt_stats_.UpdateRtt(send_delta, ack_frame.ack_delay_time, ack_receive_time); + rtt_stats_.UpdateRtt(send_delta, ack_delay_time, ack_receive_time); return true; } @@ -862,6 +913,10 @@ const QuicTime QuicSentPacketManager::GetRetransmissionTime() const { } switch (GetRetransmissionMode()) { case HANDSHAKE_MODE: + if (use_better_crypto_retransmission_) { + return unacked_packets_.GetLastCryptoPacketSentTime() + + GetCryptoRetransmissionDelay(); + } return clock_->ApproximateNow() + GetCryptoRetransmissionDelay(); case LOSS_MODE: return loss_algorithm_->GetLossTimeout(); @@ -888,6 +943,17 @@ const QuicTime QuicSentPacketManager::GetRetransmissionTime() const { return QuicTime::Zero(); } +const QuicTime::Delta QuicSentPacketManager::GetPathDegradingDelay() const { + QuicTime::Delta delay = QuicTime::Delta::Zero(); + for (size_t i = 0; i < max_tail_loss_probes_; ++i) { + delay = delay + GetTailLossProbeDelay(i); + } + for (size_t i = 0; i < kNumRetransmissionDelaysForPathDegradingDelay; ++i) { + delay = delay + GetRetransmissionDelay(i); + } + return delay; +} + const QuicTime::Delta QuicSentPacketManager::GetCryptoRetransmissionDelay() const { // This is equivalent to the TailLossProbeDelay, but slightly more aggressive @@ -907,9 +973,10 @@ const QuicTime::Delta QuicSentPacketManager::GetCryptoRetransmissionDelay() delay_ms << consecutive_crypto_retransmission_count_); } -const QuicTime::Delta QuicSentPacketManager::GetTailLossProbeDelay() const { +const QuicTime::Delta QuicSentPacketManager::GetTailLossProbeDelay( + size_t consecutive_tlp_count) const { QuicTime::Delta srtt = rtt_stats_.SmoothedOrInitialRtt(); - if (enable_half_rtt_tail_loss_probe_ && consecutive_tlp_count_ == 0u) { + if (enable_half_rtt_tail_loss_probe_ && consecutive_tlp_count == 0u) { return std::max(min_tlp_timeout_, srtt * 0.5); } if (ietf_style_tlp_) { @@ -927,7 +994,12 @@ const QuicTime::Delta QuicSentPacketManager::GetTailLossProbeDelay() const { return std::max(min_tlp_timeout_, 2 * srtt); } -const QuicTime::Delta QuicSentPacketManager::GetRetransmissionDelay() const { +const QuicTime::Delta QuicSentPacketManager::GetTailLossProbeDelay() const { + return GetTailLossProbeDelay(consecutive_tlp_count_); +} + +const QuicTime::Delta QuicSentPacketManager::GetRetransmissionDelay( + size_t consecutive_rto_count) const { QuicTime::Delta retransmission_delay = QuicTime::Delta::Zero(); if (rtt_stats_.smoothed_rtt().IsZero()) { // We are in the initial state, use default timeout values. @@ -944,7 +1016,7 @@ const QuicTime::Delta QuicSentPacketManager::GetRetransmissionDelay() const { // Calculate exponential back off. retransmission_delay = retransmission_delay * - (1 << std::min<size_t>(consecutive_rto_count_, kMaxRetransmissions)); + (1 << std::min<size_t>(consecutive_rto_count, kMaxRetransmissions)); if (retransmission_delay.ToMilliseconds() > kMaxRetransmissionTimeMs) { return QuicTime::Delta::FromMilliseconds(kMaxRetransmissionTimeMs); @@ -952,6 +1024,10 @@ const QuicTime::Delta QuicSentPacketManager::GetRetransmissionDelay() const { return retransmission_delay; } +const QuicTime::Delta QuicSentPacketManager::GetRetransmissionDelay() const { + return GetRetransmissionDelay(consecutive_rto_count_); +} + const RttStats* QuicSentPacketManager::GetRttStats() const { return &rtt_stats_; } @@ -1034,22 +1110,98 @@ void QuicSentPacketManager::OnConnectionMigration(AddressChangeType type) { } void QuicSentPacketManager::OnAckFrameStart(QuicPacketNumber largest_acked, - QuicTime::Delta ack_delay_time) { - last_ack_frame_.largest_acked = largest_acked; + QuicTime::Delta ack_delay_time, + QuicTime ack_receive_time) { + DCHECK(packets_acked_.empty()); + DCHECK_LE(largest_acked, unacked_packets_.largest_sent_packet()); + rtt_updated_ = + MaybeUpdateRTT(largest_acked, ack_delay_time, ack_receive_time); + DCHECK_GE(largest_acked, unacked_packets_.largest_observed()); last_ack_frame_.ack_delay_time = ack_delay_time; + acked_packets_iter_ = last_ack_frame_.packets.rbegin(); } void QuicSentPacketManager::OnAckRange(QuicPacketNumber start, - QuicPacketNumber end, - bool last_range, - QuicTime ack_receive_time) { - last_ack_frame_.packets.AddRange(start, end); - if (!last_range) { + QuicPacketNumber end) { + if (end > last_ack_frame_.largest_acked + 1) { + // Largest acked increases. + unacked_packets_.IncreaseLargestObserved(end - 1); + last_ack_frame_.largest_acked = end - 1; + } + // Drop ack ranges which ack packets below least_unacked. + QuicPacketNumber least_unacked = unacked_packets_.GetLeastUnacked(); + if (end <= least_unacked) { return; } - OnIncomingAck(last_ack_frame_, ack_receive_time); - // Clear last_ack_frame_. - last_ack_frame_.Clear(); + start = std::max(start, least_unacked); + DCHECK_LT(start, end); + do { + QuicPacketNumber newly_acked_start = start; + if (acked_packets_iter_ != last_ack_frame_.packets.rend()) { + newly_acked_start = std::max(start, acked_packets_iter_->max()); + } + for (QuicPacketNumber acked = end - 1; acked >= newly_acked_start; + --acked) { + // Check if end is above the current range. If so add newly acked packets + // in descending order. + packets_acked_.push_back(AckedPacket(acked, 0, QuicTime::Zero())); + } + if (acked_packets_iter_ == last_ack_frame_.packets.rend() || + start > acked_packets_iter_->min()) { + // Finish adding all newly acked packets. + return; + } + end = std::min(end, acked_packets_iter_->min()); + ++acked_packets_iter_; + } while (start < end); +} + +bool QuicSentPacketManager::OnAckFrameEnd(QuicTime ack_receive_time) { + QuicByteCount prior_bytes_in_flight = unacked_packets_.bytes_in_flight(); + // Reverse packets_acked_ so that it is in ascending order. + reverse(packets_acked_.begin(), packets_acked_.end()); + for (AckedPacket& acked_packet : packets_acked_) { + QuicTransmissionInfo* info = + unacked_packets_.GetMutableTransmissionInfo(acked_packet.packet_number); + if (!QuicUtils::IsAckable(info->state)) { + if (info->state == ACKED) { + QUIC_BUG << "Trying to ack an already acked packet: " + << acked_packet.packet_number; + } else { + QUIC_PEER_BUG << "Received ack for unackable packet: " + << acked_packet.packet_number << " with state: " + << QuicUtils::SentPacketStateToString(info->state); + } + continue; + } + QUIC_DVLOG(1) << ENDPOINT << "Got an ack for packet " + << acked_packet.packet_number; + last_ack_frame_.packets.Add(acked_packet.packet_number); + if (info->largest_acked > 0) { + largest_packet_peer_knows_is_acked_ = + std::max(largest_packet_peer_knows_is_acked_, info->largest_acked); + } + // If data is associated with the most recent transmission of this + // packet, then inform the caller. + if (info->in_flight) { + acked_packet.bytes_acked = info->bytes_sent; + } else { + // Unackable packets are skipped earlier. + largest_newly_acked_ = acked_packet.packet_number; + } + MarkPacketHandled(acked_packet.packet_number, info, + last_ack_frame_.ack_delay_time); + } + const bool acked_new_packet = !packets_acked_.empty(); + PostProcessAfterMarkingPacketHandled(last_ack_frame_, ack_receive_time, + rtt_updated_, prior_bytes_in_flight); + // TODO(fayang): Move this line to PostProcessAfterMarkingPacketHandled + // when deprecating quic_reloadable_flag_quic_use_incremental_ack_processing3. + // Remove packets below least unacked from all_packets_acked_ and + // last_ack_frame_. + last_ack_frame_.packets.RemoveUpTo(unacked_packets_.GetLeastUnacked()); + + return acked_new_packet; } void QuicSentPacketManager::SetDebugDelegate(DebugDelegate* debug_delegate) { diff --git a/chromium/net/quic/core/quic_sent_packet_manager.h b/chromium/net/quic/core/quic_sent_packet_manager.h index d067950c721..4c916ea3d99 100644 --- a/chromium/net/quic/core/quic_sent_packet_manager.h +++ b/chromium/net/quic/core/quic_sent_packet_manager.h @@ -82,6 +82,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // Called with the path may be degrading. Note that the path may only be // temporarily degrading. + // TODO(b/76462761): remove this once + // FLAGS_quic_reloadable_flag_quic_path_degrading_alarm is deprecated. virtual void OnPathDegrading() = 0; // Called when the Path MTU may have increased. @@ -110,8 +112,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { void SetHandshakeConfirmed(); - // Processes the incoming ack. - void OnIncomingAck(const QuicAckFrame& ack_frame, QuicTime ack_receive_time); + // Processes the incoming ack. Returns true if a previously-unacked packet is + // acked. + bool OnIncomingAck(const QuicAckFrame& ack_frame, QuicTime ack_receive_time); // Requests retransmission of all unacked packets of |retransmission_type|. // The behavior of this method depends on the value of |retransmission_type|: @@ -148,6 +151,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { bool HasUnackedPackets() const; + // Returns true if there's outstanding crypto data. + bool HasUnackedCryptoPackets() const; + // Returns the smallest packet number of a serialized packet which has not // been acked by the peer. QuicPacketNumber GetLeastUnacked() const; @@ -176,6 +182,10 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // there are no retransmittable packets. const QuicTime GetRetransmissionTime() const; + // Returns the current delay for the path degrading timer, which is used to + // notify the session that this connection is degrading. + const QuicTime::Delta GetPathDegradingDelay() const; + const RttStats* GetRttStats() const; // Returns the estimated bandwidth calculated by the congestion algorithm. @@ -218,13 +228,16 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // Called when an ack frame is initially parsed. void OnAckFrameStart(QuicPacketNumber largest_acked, - QuicTime::Delta ack_delay_time); + QuicTime::Delta ack_delay_time, + QuicTime ack_receive_time); + + // Called when ack range [start, end) is received. Populates packets_acked_ + // with newly acked packets. + void OnAckRange(QuicPacketNumber start, QuicPacketNumber end); - // Called when ack range [start, end) is received. - void OnAckRange(QuicPacketNumber start, - QuicPacketNumber end, - bool last_range, - QuicTime ack_receive_time); + // Called when an ack frame is parsed completely. Returns true if a previously + // -unacked packet is acked. + bool OnAckFrameEnd(QuicTime ack_receive_time); // Called to enable/disable letting session decide what to write. void SetSessionDecideWhatToWrite(bool session_decides_what_to_write); @@ -249,6 +262,10 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { void SetSessionNotifier(SessionNotifierInterface* session_notifier); + QuicPacketCount initial_congestion_window() const { + return initial_congestion_window_; + } + QuicPacketNumber largest_packet_peer_knows_is_acked() const { return largest_packet_peer_knows_is_acked_; } @@ -301,13 +318,26 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // packets from flight. void RetransmitRtoPackets(); - // Returns the timer for retransmitting crypto handshake packets. + // Returns the timeout for retransmitting crypto handshake packets. const QuicTime::Delta GetCryptoRetransmissionDelay() const; - // Returns the timer for a new tail loss probe. + // Returns the timeout for a new tail loss probe. |consecutive_tlp_count| is + // the number of consecutive tail loss probes that have already been sent. + const QuicTime::Delta GetTailLossProbeDelay( + size_t consecutive_tlp_count) const; + + // Calls GetTailLossProbeDelay() with values from the current state of this + // packet manager as its params. const QuicTime::Delta GetTailLossProbeDelay() const; // Returns the retransmission timeout, after which a full RTO occurs. + // |consecutive_rto_count| is the number of consecutive RTOs that have already + // occurred. + const QuicTime::Delta GetRetransmissionDelay( + size_t consecutive_rto_count) const; + + // Calls GetRetransmissionDelay() with values from the current state of this + // packet manager as its params. const QuicTime::Delta GetRetransmissionDelay() const; // Returns the newest transmission associated with a packet. @@ -317,7 +347,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // Update the RTT if the ack is for the largest acked packet number. // Returns true if the rtt was updated. - bool MaybeUpdateRTT(const QuicAckFrame& ack_frame, QuicTime ack_receive_time); + bool MaybeUpdateRTT(QuicPacketNumber largest_acked, + QuicTime::Delta ack_delay_time, + QuicTime ack_receive_time); // Invokes the loss detection algorithm and loses and retransmits packets if // necessary. @@ -345,6 +377,13 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { void MarkForRetransmission(QuicPacketNumber packet_number, TransmissionType transmission_type); + // Called after packets have been marked handled with last received ack frame. + void PostProcessAfterMarkingPacketHandled( + const QuicAckFrame& ack_frame, + QuicTime ack_receive_time, + bool rtt_updated, + QuicByteCount prior_bytes_in_flight); + // Notify observers that packet with QuicTransmissionInfo |info| is a spurious // retransmission. It is caller's responsibility to guarantee the packet with // QuicTransmissionInfo |info| is a spurious retransmission before calling @@ -389,7 +428,7 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { DebugDelegate* debug_delegate_; NetworkChangeVisitor* network_change_visitor_; - const QuicPacketCount initial_congestion_window_; + QuicPacketCount initial_congestion_window_; RttStats rtt_stats_; std::unique_ptr<SendAlgorithmInterface> send_algorithm_; // Not owned. Always points to |general_loss_algorithm_| outside of tests. @@ -459,6 +498,23 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // Latest received ack frame. QuicAckFrame last_ack_frame_; + // Record whether RTT gets updated by last largest acked. This is only used + // when quic_reloadable_flag_quic_use_incremental_ack_processing3 is true. + bool rtt_updated_; + + // A reverse iterator of last_ack_frame_.packets. This is reset in + // OnAckRangeStart, and gradually moves in OnAckRange. This is only used + // when quic_reloadable_flag_quic_use_incremental_ack_processing3 is true. + PacketNumberQueue::const_reverse_iterator acked_packets_iter_; + + // Latched value of + // quic_reloadable_flag_quic_path_degrading_alarm + const bool use_path_degrading_alarm_; + + // Latched value of + // quic_reloadable_flag_quic_better_crypto_retransmission + const bool use_better_crypto_retransmission_; + DISALLOW_COPY_AND_ASSIGN(QuicSentPacketManager); }; diff --git a/chromium/net/quic/core/quic_sent_packet_manager_test.cc b/chromium/net/quic/core/quic_sent_packet_manager_test.cc index 49ae651f2c6..17154215e04 100644 --- a/chromium/net/quic/core/quic_sent_packet_manager_test.cc +++ b/chromium/net/quic/core/quic_sent_packet_manager_test.cc @@ -86,7 +86,9 @@ class QuicSentPacketManagerTest : public QuicTestWithParam<bool> { QuicSentPacketManagerTest() : manager_(Perspective::IS_SERVER, &clock_, &stats_, kCubicBytes, kNack), send_algorithm_(new StrictMock<MockSendAlgorithm>), - network_change_visitor_(new StrictMock<MockNetworkChangeVisitor>) { + network_change_visitor_(new StrictMock<MockNetworkChangeVisitor>), + use_path_degrading_alarm_( + GetQuicReloadableFlag(quic_path_degrading_alarm)) { QuicSentPacketManagerPeer::SetSendAlgorithm(&manager_, send_algorithm_); // Disable tail loss probes for most tests. QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 0); @@ -255,7 +257,7 @@ class QuicSentPacketManagerTest : public QuicTestWithParam<bool> { SerializedPacket CreatePacket(QuicPacketNumber packet_number, bool retransmittable) { - SerializedPacket packet(packet_number, PACKET_6BYTE_PACKET_NUMBER, nullptr, + SerializedPacket packet(packet_number, PACKET_4BYTE_PACKET_NUMBER, nullptr, kDefaultLength, false, false); if (retransmittable) { packet.retransmittable_frames.push_back(QuicFrame( @@ -318,6 +320,10 @@ class QuicSentPacketManagerTest : public QuicTestWithParam<bool> { MockSendAlgorithm* send_algorithm_; std::unique_ptr<MockNetworkChangeVisitor> network_change_visitor_; StrictMock<MockSessionNotifier> notifier_; + + // Latched value of + // quic_reloadable_flag_quic_path_degrading_alarm + bool use_path_degrading_alarm_; }; INSTANTIATE_TEST_CASE_P(Tests, QuicSentPacketManagerTest, testing::Bool()); @@ -357,11 +363,12 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAck) { QuicAckFrame ack_frame = InitAckFrame({{2, 3}}); ExpectAck(2); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite()); - manager_.OnAckRange(2, 3, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(2, 3); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } if (manager_.session_decides_what_to_write()) { EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); @@ -391,11 +398,12 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAckBeforeSend) { // Ack 1. QuicAckFrame ack_frame = InitAckFrame(1); ExpectAck(1); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } // There should no longer be a pending retransmission. @@ -448,11 +456,12 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPrevious) { // Ack 1 but not 2. ExpectAck(1); QuicAckFrame ack_frame = InitAckFrame(1); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } if (manager_.session_decides_what_to_write()) { EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); @@ -467,9 +476,10 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPrevious) { EXPECT_CALL(notifier_, OnFrameAcked(_, _)).WillOnce(Return(false)); ExpectAck(2); QuicAckFrame ack_frame2 = InitAckFrame(2); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite()); - manager_.OnAckRange(1, 3, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(1, 3); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { manager_.OnIncomingAck(ack_frame2, clock_.ApproximateNow()); } @@ -487,11 +497,12 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) { // First, ACK packet 1 which makes packet 2 non-retransmittable. ExpectAck(1); QuicAckFrame ack_frame = InitAckFrame(1); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } SendDataPacket(3); @@ -503,22 +514,24 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) { ack_frame = InitAckFrame({{1, 2}, {3, 4}}); ExpectAck(3); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(3, QuicTime::Delta::Infinite()); - manager_.OnAckRange(3, 4, /*last_range=*/false, clock_.ApproximateNow()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(3, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(3, 4); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } ack_frame = InitAckFrame({{1, 2}, {3, 5}}); ExpectAck(4); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite()); - manager_.OnAckRange(3, 5, /*last_range=*/false, clock_.ApproximateNow()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(3, 5); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } ack_frame = InitAckFrame({{1, 2}, {3, 6}}); @@ -527,12 +540,13 @@ TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) { // Frames in all packets are acked. EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); } - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite()); - manager_.OnAckRange(3, 6, /*last_range=*/false, clock_.ApproximateNow()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(3, 6); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } // No packets remain unacked. @@ -562,11 +576,12 @@ TEST_P(QuicSentPacketManagerTest, QuicAckFrame ack_frame = InitAckFrame(1); ExpectUpdatedRtt(1); EXPECT_CALL(*send_algorithm_, RevertRetransmissionTimeout()); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } // Since 2 was marked for retransmit, when 1 is acked, 2 is kept for RTT. @@ -602,11 +617,12 @@ TEST_P(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { // Ack 1 but not 2 or 3. ExpectAck(1); QuicAckFrame ack_frame = InitAckFrame(1); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } if (manager_.session_decides_what_to_write()) { // Frames in packets 2 and 3 are acked. @@ -632,12 +648,13 @@ TEST_P(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { ack_frame = InitAckFrame({{1, 2}, {3, 5}}); QuicPacketNumber acked[] = {3, 4}; ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite()); - manager_.OnAckRange(3, 5, /*last_range=*/false, clock_.ApproximateNow()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(3, 5); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } QuicPacketNumber unacked2[] = {2}; @@ -652,12 +669,13 @@ TEST_P(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) { // Frames in all packetss are acked. EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); } - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite()); - manager_.OnAckRange(3, 6, /*last_range=*/false, clock_.ApproximateNow()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(3, 6); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } VerifyUnackedPackets(nullptr, 0); @@ -684,11 +702,12 @@ TEST_P(QuicSentPacketManagerTest, AckOriginalTransmission) { QuicAckFrame ack_frame = InitAckFrame(1); ExpectAck(1); EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _)); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } } @@ -699,27 +718,33 @@ TEST_P(QuicSentPacketManagerTest, AckOriginalTransmission) { QuicAckFrame ack_frame = InitAckFrame({{1, 2}, {4, 5}}); ExpectAck(4); EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _)); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite()); - manager_.OnAckRange(4, 5, /*last_range=*/false, clock_.Now()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(4, 5); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION); } // Ack 3, which causes SpuriousRetransmitDetected to be called. { + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + QuicPacketNumber acked[] = {3}; + ExpectAcksAndLosses(false, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); + } QuicAckFrame ack_frame = InitAckFrame({{1, 2}, {3, 5}}); EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _)); EXPECT_CALL(*loss_algorithm, SpuriousRetransmitDetected(_, _, _, 5)); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite()); - manager_.OnAckRange(3, 5, /*last_range=*/false, clock_.Now()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(4, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(3, 5); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_FALSE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } if (manager_.session_decides_what_to_write()) { // Ack 3 will not cause 5 be considered as a spurious retransmission. Ack @@ -729,10 +754,11 @@ TEST_P(QuicSentPacketManagerTest, AckOriginalTransmission) { EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _)); EXPECT_CALL(notifier_, OnFrameAcked(_, _)).WillOnce(Return(false)); QuicAckFrame ack_frame2 = InitAckFrame({{1, 2}, {3, 6}}); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite()); - manager_.OnAckRange(3, 6, /*last_range=*/false, clock_.Now()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(3, 6); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { manager_.OnIncomingAck(ack_frame2, clock_.Now()); } @@ -758,12 +784,19 @@ TEST_P(QuicSentPacketManagerTest, AckAckAndUpdateRtt) { QuicAckFrame ack_frame = InitAckFrame(2); ack_frame.ack_delay_time = QuicTime::Delta::FromMilliseconds(5); - ExpectAck(1); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(2, QuicTime::Delta::FromMilliseconds(5)); - manager_.OnAckRange(1, 3, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + QuicPacketNumber acked[] = {1, 2}; + ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); + } else { + ExpectAck(1); + } + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(2, QuicTime::Delta::FromMilliseconds(5), + clock_.Now()); + manager_.OnAckRange(1, 3); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } EXPECT_EQ(1u, manager_.largest_packet_peer_knows_is_acked()); @@ -771,12 +804,18 @@ TEST_P(QuicSentPacketManagerTest, AckAckAndUpdateRtt) { // Now ack the ack and expect only an RTT update. ack_frame = InitAckFrame(3); - ExpectUpdatedRtt(3); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(3, QuicTime::Delta::Infinite()); - manager_.OnAckRange(1, 4, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + QuicPacketNumber acked[] = {3}; + ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + ExpectUpdatedRtt(3); + } + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(3, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(1, 4); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); + } else { + EXPECT_FALSE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } EXPECT_EQ(3u, manager_.largest_packet_peer_knows_is_acked()); } @@ -789,11 +828,12 @@ TEST_P(QuicSentPacketManagerTest, Rtt) { ExpectAck(packet_number); QuicAckFrame ack_frame = InitAckFrame(packet_number); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt()); } @@ -810,11 +850,13 @@ TEST_P(QuicSentPacketManagerTest, RttWithInvalidDelta) { ExpectAck(packet_number); QuicAckFrame ack_frame = InitAckFrame(packet_number); ack_frame.ack_delay_time = QuicTime::Delta::FromMilliseconds(11); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(1, QuicTime::Delta::FromMilliseconds(11)); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(1, QuicTime::Delta::FromMilliseconds(11), + clock_.Now()); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt()); } @@ -830,11 +872,12 @@ TEST_P(QuicSentPacketManagerTest, RttWithInfiniteDelta) { ExpectAck(packet_number); QuicAckFrame ack_frame = InitAckFrame(packet_number); ack_frame.ack_delay_time = QuicTime::Delta::Infinite(); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt()); } @@ -850,11 +893,12 @@ TEST_P(QuicSentPacketManagerTest, RttZeroDelta) { ExpectAck(packet_number); QuicAckFrame ack_frame = InitAckFrame(packet_number); ack_frame.ack_delay_time = QuicTime::Delta::Zero(); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(1, QuicTime::Delta::Zero()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(1, QuicTime::Delta::Zero(), clock_.Now()); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt()); } @@ -904,11 +948,12 @@ TEST_P(QuicSentPacketManagerTest, TailLossProbeTimeout) { ExpectAck(3); QuicAckFrame ack_frame = InitAckFrame({{3, 4}}); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(3, QuicTime::Delta::Infinite()); - manager_.OnAckRange(3, 4, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(3, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(3, 4); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); @@ -925,11 +970,12 @@ TEST_P(QuicSentPacketManagerTest, TailLossProbeTimeout) { // Frames in all packets are acked. EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); } - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite()); - manager_.OnAckRange(3, 6, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(5, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(3, 6); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } EXPECT_FALSE(manager_.HasPendingRetransmissions()); @@ -1038,11 +1084,12 @@ TEST_P(QuicSentPacketManagerTest, TailLossProbeThenRTO) { // Packets 1, 2 and [4, 102] are lost. EXPECT_CALL(notifier_, OnFrameLost(_)).Times(101); } - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(103, QuicTime::Delta::Infinite()); - manager_.OnAckRange(103, 104, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(103, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(103, 104); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } // All packets before 103 should be lost. if (manager_.session_decides_what_to_write()) { @@ -1106,12 +1153,13 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeout) { EXPECT_CALL(notifier_, HasPendingCryptoData()) .WillRepeatedly(Return(false)); } - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(9, QuicTime::Delta::Infinite()); - manager_.OnAckRange(8, 10, /*last_range=*/false, clock_.ApproximateNow()); - manager_.OnAckRange(3, 6, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(9, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(8, 10); + manager_.OnAckRange(3, 6); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); @@ -1179,11 +1227,12 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) { QuicPacketNumber acked[] = {8, 9}; ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); QuicAckFrame ack_frame = InitAckFrame({{8, 10}}); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(9, QuicTime::Delta::Infinite()); - manager_.OnAckRange(8, 10, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(9, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(8, 10); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } if (manager_.session_decides_what_to_write()) { EXPECT_CALL(notifier_, HasPendingCryptoData()) @@ -1219,18 +1268,24 @@ TEST_P(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) { // Now ack the second crypto packet, and ensure the first gets removed, but // the third does not. - ExpectUpdatedRtt(2); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + QuicPacketNumber acked[] = {2}; + ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); + } else { + ExpectUpdatedRtt(2); + } QuicAckFrame ack_frame = InitAckFrame({{2, 3}}); if (manager_.session_decides_what_to_write()) { EXPECT_CALL(notifier_, HasPendingCryptoData()) .WillRepeatedly(Return(false)); EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); } - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite()); - manager_.OnAckRange(2, 3, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(2, 3); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_FALSE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_)); @@ -1347,12 +1402,18 @@ TEST_P(QuicSentPacketManagerTest, // Ensure both packets get discarded when packet 2 is acked. QuicAckFrame ack_frame = InitAckFrame({{3, 4}}); - ExpectUpdatedRtt(3); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(3, QuicTime::Delta::Infinite()); - manager_.OnAckRange(3, 4, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + QuicPacketNumber acked[] = {3}; + ExpectAcksAndLosses(true, acked, QUIC_ARRAYSIZE(acked), nullptr, 0); + } else { + ExpectUpdatedRtt(3); + } + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(3, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(3, 4); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_FALSE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } VerifyUnackedPackets(nullptr, 0); VerifyRetransmittablePackets(nullptr, 0); @@ -1420,11 +1481,12 @@ TEST_P(QuicSentPacketManagerTest, RetransmissionTimeout) { // retransmittable frames as packet 102 is acked. EXPECT_CALL(notifier_, OnFrameLost(_)).Times(98); } - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(102, QuicTime::Delta::Zero()); - manager_.OnAckRange(102, 103, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(102, QuicTime::Delta::Zero(), clock_.Now()); + manager_.OnAckRange(102, 103); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } } @@ -1495,11 +1557,12 @@ TEST_P(QuicSentPacketManagerTest, NewRetransmissionTimeout) { // retransmittable frames as packet 102 is acked. EXPECT_CALL(notifier_, OnFrameLost(_)).Times(98); } - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(102, QuicTime::Delta::Zero()); - manager_.OnAckRange(102, 103, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(102, QuicTime::Delta::Zero(), clock_.Now()); + manager_.OnAckRange(102, 103); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } } @@ -1525,7 +1588,9 @@ TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) { } // Rto a second time. - EXPECT_CALL(*network_change_visitor_, OnPathDegrading()); + if (!use_path_degrading_alarm_) { + EXPECT_CALL(*network_change_visitor_, OnPathDegrading()); + } if (manager_.session_decides_what_to_write()) { EXPECT_CALL(notifier_, RetransmitFrames(_, _)) .WillOnce(WithArgs<1>(Invoke( @@ -1548,11 +1613,12 @@ TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) { QuicAckFrame ack_frame = InitAckFrame({{2, 3}}); ack_frame.ack_delay_time = QuicTime::Delta::Zero(); ExpectAck(2); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(2, QuicTime::Delta::Zero()); - manager_.OnAckRange(2, 3, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(2, QuicTime::Delta::Zero(), clock_.Now()); + manager_.OnAckRange(2, 3); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } // The original packet and newest should be outstanding. @@ -1582,7 +1648,9 @@ TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) { } // Rto a second time. - EXPECT_CALL(*network_change_visitor_, OnPathDegrading()); + if (!use_path_degrading_alarm_) { + EXPECT_CALL(*network_change_visitor_, OnPathDegrading()); + } if (manager_.session_decides_what_to_write()) { EXPECT_CALL(notifier_, RetransmitFrames(_, _)) .WillOnce(WithArgs<1>(Invoke( @@ -1605,11 +1673,12 @@ TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) { QuicAckFrame ack_frame = InitAckFrame({{3, 4}}); ack_frame.ack_delay_time = QuicTime::Delta::Zero(); ExpectAck(3); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(3, QuicTime::Delta::Zero()); - manager_.OnAckRange(3, 4, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(3, QuicTime::Delta::Zero(), clock_.Now()); + manager_.OnAckRange(3, 4); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } // The first two packets should still be outstanding. @@ -1618,6 +1687,10 @@ TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) { } TEST_P(QuicSentPacketManagerTest, OnPathDegrading) { + if (use_path_degrading_alarm_) { + return; + } + SendDataPacket(1); for (size_t i = 1; i < kMinTimeoutsBeforePathDegrading; ++i) { if (manager_.session_decides_what_to_write()) { @@ -1645,6 +1718,7 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionTime) { } TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeCryptoHandshake) { + QuicTime crypto_packet_send_time = clock_.Now(); SendCryptoPacket(1); // Check the min. @@ -1665,6 +1739,7 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeCryptoHandshake) { if (manager_.session_decides_what_to_write()) { EXPECT_CALL(notifier_, RetransmitFrames(_, _)) .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); })); + crypto_packet_send_time = clock_.Now(); } manager_.OnRetransmissionTimeout(); if (!manager_.session_decides_what_to_write()) { @@ -1672,7 +1747,11 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeCryptoHandshake) { } // The retransmission time should now be twice as far in the future. - expected_time = clock_.Now() + srtt * 2 * 1.5; + if (GetQuicReloadableFlag(quic_better_crypto_retransmission)) { + expected_time = crypto_packet_send_time + srtt * 2 * 1.5; + } else { + expected_time = clock_.Now() + srtt * 2 * 1.5; + } EXPECT_EQ(expected_time, manager_.GetRetransmissionTime()); } @@ -1691,6 +1770,7 @@ TEST_P(QuicSentPacketManagerTest, EXPECT_CALL(*send_algorithm_, GetCongestionWindow()) .WillRepeatedly(Return(10 * kDefaultTCPMSS)); + QuicTime crypto_packet_send_time = clock_.Now(); SendCryptoPacket(1); // Check the min. @@ -1711,6 +1791,7 @@ TEST_P(QuicSentPacketManagerTest, if (manager_.session_decides_what_to_write()) { EXPECT_CALL(notifier_, RetransmitFrames(_, _)) .WillOnce(InvokeWithoutArgs([this]() { RetransmitCryptoPacket(2); })); + crypto_packet_send_time = clock_.Now(); } manager_.OnRetransmissionTimeout(); if (!manager_.session_decides_what_to_write()) { @@ -1718,7 +1799,11 @@ TEST_P(QuicSentPacketManagerTest, } // The retransmission time should now be twice as far in the future. - expected_time = clock_.Now() + srtt * 2 * 2; + if (GetQuicReloadableFlag(quic_better_crypto_retransmission)) { + expected_time = crypto_packet_send_time + srtt * 2 * 2; + } else { + expected_time = clock_.Now() + srtt * 2 * 2; + } EXPECT_EQ(expected_time, manager_.GetRetransmissionTime()); } @@ -1811,11 +1896,12 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) { // original value and OnRetransmissionTimeout is not called or reverted. QuicAckFrame ack_frame = InitAckFrame({{2, 3}}); ExpectAck(2); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite()); - manager_.OnAckRange(2, 3, /*last_range=*/true, clock_.ApproximateNow()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(2, 3); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow())); } EXPECT_FALSE(manager_.HasPendingRetransmissions()); EXPECT_EQ(5 * kDefaultLength, @@ -1841,10 +1927,14 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayMin) { // If the delay is smaller than the min, ensure it exponentially backs off // from the min. - EXPECT_CALL(*network_change_visitor_, OnPathDegrading()); + if (!use_path_degrading_alarm_) { + EXPECT_CALL(*network_change_visitor_, OnPathDegrading()); + } for (int i = 0; i < 5; ++i) { EXPECT_EQ(delay, QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_)); + EXPECT_EQ(delay, + QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, i)); delay = delay + delay; if (manager_.session_decides_what_to_write()) { EXPECT_CALL(notifier_, RetransmitFrames(_, _)) @@ -1868,6 +1958,8 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayMax) { EXPECT_EQ(QuicTime::Delta::FromSeconds(60), QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_)); + EXPECT_EQ(QuicTime::Delta::FromSeconds(60), + QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, 0)); } TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayExponentialBackoff) { @@ -1875,10 +1967,14 @@ TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayExponentialBackoff) { QuicTime::Delta delay = QuicTime::Delta::FromMilliseconds(500); // Delay should back off exponentially. - EXPECT_CALL(*network_change_visitor_, OnPathDegrading()); + if (!use_path_degrading_alarm_) { + EXPECT_CALL(*network_change_visitor_, OnPathDegrading()); + } for (int i = 0; i < 5; ++i) { EXPECT_EQ(delay, QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_)); + EXPECT_EQ(delay, + QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, i)); delay = delay + delay; if (manager_.session_decides_what_to_write()) { EXPECT_CALL(notifier_, RetransmitFrames(_, _)) @@ -1908,6 +2004,8 @@ TEST_P(QuicSentPacketManagerTest, RetransmissionDelay) { QuicTime::Delta::FromMilliseconds(kRttMs + kRttMs / 2 * 4); EXPECT_EQ(expected_delay, QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_)); + EXPECT_EQ(expected_delay, + QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, 0)); for (int i = 0; i < 100; ++i) { // Run to make sure that we converge. @@ -1925,6 +2023,8 @@ TEST_P(QuicSentPacketManagerTest, RetransmissionDelay) { QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_) .ToMilliseconds(), 1); + EXPECT_EQ(QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, 0), + QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_)); } TEST_P(QuicSentPacketManagerTest, GetLossDelay) { @@ -1941,11 +2041,12 @@ TEST_P(QuicSentPacketManagerTest, GetLossDelay) { ExpectAck(2); EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _)); QuicAckFrame ack_frame = InitAckFrame({{2, 3}}); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite()); - manager_.OnAckRange(2, 3, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(2, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(2, 3); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.Now())); } QuicTime timeout(clock_.Now() + QuicTime::Delta::FromMilliseconds(10)); @@ -2116,12 +2217,16 @@ TEST_F(QuicSentPacketManagerTest, // The TLP with fewer than 2 packets outstanding includes 1/2 min RTO(200ms). EXPECT_EQ(QuicTime::Delta::FromMicroseconds(100002), QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); + EXPECT_EQ(QuicTime::Delta::FromMicroseconds(100002), + QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); // Send two packets, and the TLP should be 2 us. SendDataPacket(1); SendDataPacket(2); EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2), QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); + EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2), + QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); } TEST_F(QuicSentPacketManagerTest, @@ -2146,18 +2251,20 @@ TEST_F(QuicSentPacketManagerTest, // The TLP with fewer than 2 packets outstanding includes 1/2 min RTO(200ms). EXPECT_EQ(QuicTime::Delta::FromMicroseconds(100002), QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); - + EXPECT_EQ(QuicTime::Delta::FromMicroseconds(100002), + QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); // Send two packets, and the TLP should be 2 us. SendDataPacket(1); SendDataPacket(2); EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2), QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); + EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2), + QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); } TEST_F(QuicSentPacketManagerTest, DISABLED_NegotiateIETFTLPFromOptionsAtServer) { SetQuicReloadableFlag(quic_max_ack_delay2, true); - SetQuicReloadableFlag(quic_min_rtt_ack_delay, true); QuicConfig config; QuicTagVector options; @@ -2173,18 +2280,21 @@ TEST_F(QuicSentPacketManagerTest, // Expect 1.5x * SRTT + 0ms MAD EXPECT_EQ(QuicTime::Delta::FromMilliseconds(150), QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(150), + QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); // Expect 1.5x * SRTT + 50ms MAD rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(150), QuicTime::Delta::FromMilliseconds(50), QuicTime::Zero()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats->smoothed_rtt()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), + QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); } TEST_F(QuicSentPacketManagerTest, DISABLED_NegotiateIETFTLPFromOptionsAtClient) { SetQuicReloadableFlag(quic_max_ack_delay2, true); - SetQuicReloadableFlag(quic_min_rtt_ack_delay, true); QuicConfig client_config; QuicTagVector options; @@ -2201,12 +2311,16 @@ TEST_F(QuicSentPacketManagerTest, // Expect 1.5x * SRTT + 0ms MAD EXPECT_EQ(QuicTime::Delta::FromMilliseconds(150), QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(150), + QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); // Expect 1.5x * SRTT + 50ms MAD rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(150), QuicTime::Delta::FromMilliseconds(50), QuicTime::Zero()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats->smoothed_rtt()); EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), + QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); } TEST_F(QuicSentPacketManagerTest, @@ -2226,9 +2340,13 @@ TEST_F(QuicSentPacketManagerTest, QuicTime::Delta::Zero(), QuicTime::Zero()); EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1), QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_)); + EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1), + QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, 0)); // The TLP with fewer than 2 packets outstanding includes 1/2 min RTO(0ms). EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2), QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); + EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2), + QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); } TEST_F(QuicSentPacketManagerTest, @@ -2249,9 +2367,13 @@ TEST_F(QuicSentPacketManagerTest, QuicTime::Delta::Zero(), QuicTime::Zero()); EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1), QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_)); + EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1), + QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_, 0)); // The TLP with fewer than 2 packets outstanding includes 1/2 min RTO(0ms). EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2), QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_)); + EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2), + QuicSentPacketManagerPeer::GetTailLossProbeDelay(&manager_, 0)); } TEST_F(QuicSentPacketManagerTest, DISABLED_NegotiateNoTLPFromOptionsAtServer) { @@ -2444,7 +2566,7 @@ TEST_P(QuicSentPacketManagerTest, ConnectionMigrationPortChange) { TEST_P(QuicSentPacketManagerTest, PathMtuIncreased) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), 1, _, _)); - SerializedPacket packet(1, PACKET_6BYTE_PACKET_NUMBER, nullptr, + SerializedPacket packet(1, PACKET_4BYTE_PACKET_NUMBER, nullptr, kDefaultLength + 100, false, false); manager_.OnPacketSent(&packet, 0, clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); @@ -2454,12 +2576,41 @@ TEST_P(QuicSentPacketManagerTest, PathMtuIncreased) { EXPECT_CALL(*network_change_visitor_, OnPathMtuIncreased(kDefaultLength + 100)); QuicAckFrame ack_frame = InitAckFrame(1); - if (GetQuicReloadableFlag(quic_use_incremental_ack_processing)) { - manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite()); - manager_.OnAckRange(1, 2, /*last_range=*/true, clock_.Now()); + if (GetQuicReloadableFlag(quic_use_incremental_ack_processing3)) { + manager_.OnAckFrameStart(1, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(1, 2); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } else { - manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_TRUE(manager_.OnIncomingAck(ack_frame, clock_.Now())); + } +} + +TEST_P(QuicSentPacketManagerTest, OnAckRangeSlowPath) { + SetQuicReloadableFlag(quic_use_incremental_ack_processing3, true); + // Send packets 1 - 20. + for (size_t i = 1; i <= 20; ++i) { + SendDataPacket(i); } + // Ack [5, 7), [10, 12), [15, 17). + QuicPacketNumber acked1[] = {5, 6, 10, 11, 15, 16}; + QuicPacketNumber lost1[] = {1, 2, 3, 4, 7, 8, 9, 12, 13}; + ExpectAcksAndLosses(true, acked1, QUIC_ARRAYSIZE(acked1), lost1, + QUIC_ARRAYSIZE(lost1)); + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(AnyNumber()); + manager_.OnAckFrameStart(16, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(15, 17); + manager_.OnAckRange(10, 12); + manager_.OnAckRange(5, 7); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); + + // Ack [4, 8), [9, 13), [14, 21). + QuicPacketNumber acked2[] = {4, 7, 9, 12, 14, 17, 18, 19, 20}; + ExpectAcksAndLosses(true, acked2, QUIC_ARRAYSIZE(acked2), nullptr, 0); + manager_.OnAckFrameStart(20, QuicTime::Delta::Infinite(), clock_.Now()); + manager_.OnAckRange(14, 21); + manager_.OnAckRange(9, 13); + manager_.OnAckRange(4, 8); + EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); } } // namespace diff --git a/chromium/net/quic/core/quic_server_session_base_test.cc b/chromium/net/quic/core/quic_server_session_base_test.cc index afc48cc1b62..cb8dd785c81 100644 --- a/chromium/net/quic/core/quic_server_session_base_test.cc +++ b/chromium/net/quic/core/quic_server_session_base_test.cc @@ -207,14 +207,9 @@ TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) { QuicRstStreamFrame rst1(kInvalidControlFrameId, GetNthClientInitiatedId(0), QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(GetNthClientInitiatedId(0), - QUIC_RST_ACKNOWLEDGEMENT)); - } else { - EXPECT_CALL(*connection_, SendRstStream(GetNthClientInitiatedId(0), - QUIC_RST_ACKNOWLEDGEMENT, 0)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(GetNthClientInitiatedId(0), + QUIC_RST_ACKNOWLEDGEMENT)); visitor_->OnRstStream(rst1); EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); @@ -231,14 +226,9 @@ TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) { QuicRstStreamFrame rst1(kInvalidControlFrameId, GetNthClientInitiatedId(0), QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(GetNthClientInitiatedId(0), - QUIC_RST_ACKNOWLEDGEMENT)); - } else { - EXPECT_CALL(*connection_, SendRstStream(GetNthClientInitiatedId(0), - QUIC_RST_ACKNOWLEDGEMENT, 0)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(GetNthClientInitiatedId(0), + QUIC_RST_ACKNOWLEDGEMENT)); visitor_->OnRstStream(rst1); EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); @@ -266,14 +256,9 @@ TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) { QuicRstStreamFrame rst(kInvalidControlFrameId, GetNthClientInitiatedId(0), QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(GetNthClientInitiatedId(0), - QUIC_RST_ACKNOWLEDGEMENT)); - } else { - EXPECT_CALL(*connection_, SendRstStream(GetNthClientInitiatedId(0), - QUIC_RST_ACKNOWLEDGEMENT, 0)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(GetNthClientInitiatedId(0), + QUIC_RST_ACKNOWLEDGEMENT)); visitor_->OnRstStream(rst); // If we were tracking, we'd probably want to reject this because it's data @@ -322,12 +307,8 @@ TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) { // Now violate the server's internal stream limit. stream_id += QuicSpdySessionPeer::NextStreamId(*session_); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(stream_id, QUIC_REFUSED_STREAM)); - } else { - EXPECT_CALL(*connection_, SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream_id, QUIC_REFUSED_STREAM)); // Even if the connection remains open, the stream creation should fail. EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( session_.get(), stream_id)); @@ -424,10 +405,20 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { const QuicString serving_region = "not a real region"; session_->set_serving_region(serving_region); + if (GetQuicReloadableFlag(quic_register_streams_early2) && + GetQuicReloadableFlag(quic_register_static_streams)) { + session_->UnregisterStreamPriority(kHeadersStreamId, /*is_static=*/true); + } + QuicServerSessionBasePeer::SetCryptoStream(session_.get(), nullptr); MockQuicCryptoServerStream* crypto_stream = new MockQuicCryptoServerStream(&crypto_config_, &compressed_certs_cache_, session_.get(), &stream_helper_); QuicServerSessionBasePeer::SetCryptoStream(session_.get(), crypto_stream); + if (GetQuicReloadableFlag(quic_register_streams_early2) && + GetQuicReloadableFlag(quic_register_static_streams)) { + session_->RegisterStreamPriority(kHeadersStreamId, /*is_static=*/true, + QuicStream::kDefaultPriority); + } // Set some initial bandwidth values. QuicSentPacketManager* sent_packet_manager = @@ -474,7 +465,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { // Bandwidth estimate has now changed sufficiently, enough time has passed, // and enough packets have been sent. SerializedPacket packet(1 + kMinPacketsBetweenServerConfigUpdates, - PACKET_6BYTE_PACKET_NUMBER, nullptr, 1000, false, + PACKET_4BYTE_PACKET_NUMBER, nullptr, 1000, false, false); sent_packet_manager->OnPacketSent(&packet, 0, now, NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); @@ -615,7 +606,7 @@ TEST_P(StreamMemberLifetimeTest, Basic) { QuicString(chlo.GetSerialized(Perspective::IS_CLIENT) .AsStringPiece() .as_string()), - PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, + PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, &packet_version_list)); EXPECT_CALL(stream_helper_, CanAcceptClientHello(_, _, _)) diff --git a/chromium/net/quic/core/quic_session.cc b/chromium/net/quic/core/quic_session.cc index 636e2ed8ccc..91157d7db7f 100644 --- a/chromium/net/quic/core/quic_session.cc +++ b/chromium/net/quic/core/quic_session.cc @@ -17,13 +17,15 @@ #include "net/quic/platform/api/quic_str_cat.h" #include "net/quic/platform/api/quic_string.h" +using net::SpdyPriority; + namespace net { namespace { // Stateless reset token used in IETF public reset packet. // TODO(fayang): use a real stateless reset token instead of a hard code one. -const uint128 kStatelessResetToken = 1010101; +const QuicUint128 kStatelessResetToken = 1010101; } // namespace @@ -35,6 +37,11 @@ QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config) : connection_(connection), visitor_(owner), + register_streams_early_( + GetQuicReloadableFlag(quic_register_streams_early2)), + write_blocked_streams_( + GetQuicReloadableFlag(quic_register_static_streams) && + register_streams_early_), config_(config), max_open_outgoing_streams_(kDefaultMaxStreamsPerConnection), max_open_incoming_streams_(config_.GetMaxIncomingDynamicStreamsToSend()), @@ -56,12 +63,9 @@ QuicSession::QuicSession(QuicConnection* connection, currently_writing_stream_id_(0), goaway_sent_(false), goaway_received_(false), - control_frame_manager_(this), - can_use_slices_(GetQuicReloadableFlag(quic_use_mem_slices)), - session_unblocks_stream_( - GetQuicReloadableFlag(quic_streams_unblocked_by_session2)) { - if (use_control_frame_manager()) { - QUIC_FLAG_COUNT(quic_reloadable_flag_quic_use_control_frame_manager); + control_frame_manager_(this) { + if (register_streams_early()) { + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_register_streams_early2); } } @@ -212,6 +216,8 @@ bool QuicSession::AllowSelfAddressChange() const { return false; } +void QuicSession::OnForwardProgressConfirmed() {} + void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't // assume that it still exists. @@ -299,35 +305,27 @@ void QuicSession::OnCanWrite() { // streams become pending, WillingAndAbleToWrite will be true, which will // cause the connection to request resumption before yielding to other // connections. - size_t num_writes = write_blocked_streams_.NumBlockedStreams(); - if (flow_controller_.IsBlocked()) { - // If we are connection level flow control blocked, then only allow the - // crypto and headers streams to try writing as all other streams will be - // blocked. - num_writes = 0; - if (write_blocked_streams_.crypto_stream_blocked()) { - num_writes += 1; - } - if (write_blocked_streams_.headers_stream_blocked()) { - num_writes += 1; - } - } - if (num_writes == 0 && (!use_control_frame_manager() || - !control_frame_manager_.WillingToWrite())) { + // If we are connection level flow control blocked, then only allow the + // crypto and headers streams to try writing as all other streams will be + // blocked. + size_t num_writes = flow_controller_.IsBlocked() + ? write_blocked_streams_.NumBlockedSpecialStreams() + : write_blocked_streams_.NumBlockedStreams(); + if (num_writes == 0 && !control_frame_manager_.WillingToWrite()) { return; } QuicConnection::ScopedPacketFlusher flusher( connection_, QuicConnection::SEND_ACK_IF_QUEUED); - if (use_control_frame_manager() && control_frame_manager_.WillingToWrite()) { + if (control_frame_manager_.WillingToWrite()) { control_frame_manager_.OnCanWrite(); } for (size_t i = 0; i < num_writes; ++i) { - if (!(write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() || + if (!(write_blocked_streams_.HasWriteBlockedSpecialStream() || write_blocked_streams_.HasWriteBlockedDataStreams())) { // Writing one stream removed another!? Something's broken. QUIC_BUG << "WriteBlockedStream is missing"; - RecordInternalErrorLocation(QUIC_SESSION_1); + RecordInternalErrorLocation(QUIC_SESSION_ON_CAN_WRITE); connection_->CloseConnection(QUIC_INTERNAL_ERROR, "WriteBlockedStream is missing", ConnectionCloseBehavior::SILENT_CLOSE); @@ -361,10 +359,9 @@ bool QuicSession::WillingAndAbleToWrite() const { // 3) If the crypto or headers streams are blocked, or // 4) connection is not flow control blocked and there are write blocked // streams. - return (use_control_frame_manager() && - control_frame_manager_.WillingToWrite()) || + return control_frame_manager_.WillingToWrite() || !streams_with_pending_retransmission_.empty() || - write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() || + write_blocked_streams_.HasWriteBlockedSpecialStream() || (!flow_controller_.IsBlocked() && write_blocked_streams_.HasWriteBlockedDataStreams()); } @@ -372,7 +369,7 @@ bool QuicSession::WillingAndAbleToWrite() const { bool QuicSession::HasPendingHandshake() const { return QuicContainsKey(streams_with_pending_retransmission_, kCryptoStreamId) || - write_blocked_streams_.crypto_stream_blocked(); + write_blocked_streams_.IsStreamBlocked(kCryptoStreamId); } bool QuicSession::HasOpenDynamicStreams() const { @@ -398,7 +395,7 @@ QuicConsumedData QuicSession::WritevData(QuicStream* stream, // seems like a reasonable mitigation. if (id == kCryptoStreamId && stream != GetMutableCryptoStream()) { QUIC_BUG << "Stream id mismatch"; - RecordInternalErrorLocation(QUIC_SESSION_2); + RecordInternalErrorLocation(QUIC_SESSION_WRITEV_DATA); connection_->CloseConnection( QUIC_INTERNAL_ERROR, "Non-crypto stream attempted to write data as crypto stream.", @@ -420,7 +417,6 @@ QuicConsumedData QuicSession::WritevData(QuicStream* stream, } bool QuicSession::WriteControlFrame(const QuicFrame& frame) { - DCHECK(use_control_frame_manager()); return connection_->SendControlFrame(frame); } @@ -434,12 +430,8 @@ void QuicSession::SendRstStream(QuicStreamId id, if (connection()->connected()) { // Only send a RST_STREAM frame if still connected. - if (use_control_frame_manager()) { - control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written); - connection_->OnStreamReset(id, error); - } else { - connection_->SendRstStream(id, error, bytes_written); - } + control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written); + connection_->OnStreamReset(id, error); } CloseStreamInner(id, true); } @@ -450,23 +442,16 @@ void QuicSession::SendGoAway(QuicErrorCode error_code, return; } goaway_sent_ = true; - if (use_control_frame_manager()) { - control_frame_manager_.WriteOrBufferGoAway( - error_code, largest_peer_created_stream_id_, reason); - } else { - connection_->SendGoAway(error_code, largest_peer_created_stream_id_, - reason); - } + control_frame_manager_.WriteOrBufferGoAway( + error_code, largest_peer_created_stream_id_, reason); } void QuicSession::SendBlocked(QuicStreamId id) { - DCHECK(use_control_frame_manager()); control_frame_manager_.WriteOrBufferBlocked(id); } void QuicSession::SendWindowUpdate(QuicStreamId id, QuicStreamOffset byte_offset) { - DCHECK(use_control_frame_manager()); control_frame_manager_.WriteOrBufferWindowUpdate(id, byte_offset); } @@ -484,14 +469,14 @@ void QuicSession::InsertLocallyClosedStreamsHighestOffset( } void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) { - QUIC_DLOG(INFO) << ENDPOINT << "Closing stream " << stream_id; + QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id; DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id); if (it == dynamic_stream_map_.end()) { // When CloseStreamInner has been called recursively (via // QuicStream::OnClose), the stream will already have been deleted // from stream_map_, so return immediately. - QUIC_DLOG(INFO) << ENDPOINT << "Stream is already closed: " << stream_id; + QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id; return; } QuicStream* stream = it->second.get(); @@ -752,14 +737,48 @@ void QuicSession::OnCryptoHandshakeMessageSent( void QuicSession::OnCryptoHandshakeMessageReceived( const CryptoHandshakeMessage& /*message*/) {} +void QuicSession::RegisterStreamPriority(QuicStreamId id, + bool is_static, + SpdyPriority priority) { + // Static streams should not be registered unless register_streams_early + // is true. + DCHECK(register_streams_early() || !is_static); + // Static streams do not need to be registered with the write blocked list, + // since it has special handling for them. + if (!write_blocked_streams()->register_static_streams() && + register_streams_early() && is_static) { + return; + } + + write_blocked_streams()->RegisterStream(id, is_static, priority); +} + +void QuicSession::UnregisterStreamPriority(QuicStreamId id, bool is_static) { + // Static streams should not be registered unless register_streams_early + // is true. + DCHECK(register_streams_early() || !is_static); + // Static streams do not need to be registered with the write blocked list, + // since it has special handling for them. + if (!write_blocked_streams()->register_static_streams() && + register_streams_early() && is_static) { + return; + } + write_blocked_streams()->UnregisterStream(id, is_static); +} + +void QuicSession::UpdateStreamPriority(QuicStreamId id, + SpdyPriority new_priority) { + write_blocked_streams()->UpdateStreamPriority(id, new_priority); +} + QuicConfig* QuicSession::config() { return &config_; } void QuicSession::ActivateStream(std::unique_ptr<QuicStream> stream) { QuicStreamId stream_id = stream->id(); - QUIC_DLOG(INFO) << ENDPOINT << "num_streams: " << dynamic_stream_map_.size() - << ". activating " << stream_id; + QUIC_DVLOG(1) << ENDPOINT << "num_streams: " << dynamic_stream_map_.size() + << ". activating " << stream_id; DCHECK(!QuicContainsKey(dynamic_stream_map_, stream_id)); DCHECK(!QuicContainsKey(static_stream_map_, stream_id)); dynamic_stream_map_[stream_id] = std::move(stream); @@ -837,14 +856,6 @@ bool QuicSession::ShouldYield(QuicStreamId stream_id) { return write_blocked_streams()->ShouldYield(stream_id); } -void QuicSession::NeuterUnencryptedStreamData() { - QuicCryptoStream* crypto_stream = GetMutableCryptoStream(); - crypto_stream->NeuterUnencryptedStreamData(); - if (!crypto_stream->HasPendingRetransmission()) { - streams_with_pending_retransmission_.erase(kCryptoStreamId); - } -} - QuicStream* QuicSession::GetOrCreateDynamicStream( const QuicStreamId stream_id) { DCHECK(!QuicContainsKey(static_stream_map_, stream_id)) @@ -927,9 +938,9 @@ size_t QuicSession::GetNumOpenIncomingStreams() const { } size_t QuicSession::GetNumOpenOutgoingStreams() const { - CHECK_GE(GetNumDynamicOutgoingStreams() + - GetNumLocallyClosedOutgoingStreamsHighestOffset(), - GetNumDrainingOutgoingStreams()); + DCHECK_GE(GetNumDynamicOutgoingStreams() + + GetNumLocallyClosedOutgoingStreamsHighestOffset(), + GetNumDrainingOutgoingStreams()); return GetNumDynamicOutgoingStreams() + GetNumLocallyClosedOutgoingStreamsHighestOffset() - GetNumDrainingOutgoingStreams(); @@ -951,12 +962,11 @@ void QuicSession::MarkConnectionLevelWriteBlocked(QuicStreamId id) { } bool QuicSession::HasDataToWrite() const { - return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() || + return write_blocked_streams_.HasWriteBlockedSpecialStream() || write_blocked_streams_.HasWriteBlockedDataStreams() || connection_->HasQueuedData() || !streams_with_pending_retransmission_.empty() || - (use_control_frame_manager() && - control_frame_manager_.WillingToWrite()); + control_frame_manager_.WillingToWrite(); } void QuicSession::PostProcessAfterData() { @@ -965,13 +975,16 @@ void QuicSession::PostProcessAfterData() { void QuicSession::OnAckNeedsRetransmittableFrame() { flow_controller_.SendWindowUpdate(); - if (use_control_frame_manager() && !control_frame_manager_.WillingToWrite()) { + if (GetQuicReloadableFlag(quic_remove_redundant_ping)) { + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_remove_redundant_ping); + return; + } + if (!control_frame_manager_.WillingToWrite()) { SendPing(); } } void QuicSession::SendPing() { - DCHECK(use_control_frame_manager()); control_frame_manager_.WritePing(); } @@ -1049,10 +1062,7 @@ QuicStream* QuicSession::GetStream(QuicStreamId id) const { bool QuicSession::OnFrameAcked(const QuicFrame& frame, QuicTime::Delta ack_delay_time) { if (frame.type != STREAM_FRAME) { - if (use_control_frame_manager()) { - return control_frame_manager_.OnControlFrameAcked(frame); - } - return false; + return control_frame_manager_.OnControlFrameAcked(frame); } bool new_stream_data_acked = false; QuicStream* stream = GetStream(frame.stream_frame->stream_id); @@ -1073,7 +1083,7 @@ void QuicSession::OnStreamFrameRetransmitted(const QuicStreamFrame& frame) { if (stream == nullptr) { QUIC_BUG << "Stream: " << frame.stream_id << " is closed when " << frame << " is retransmitted."; - RecordInternalErrorLocation(QUIC_SESSION_3); + RecordInternalErrorLocation(QUIC_SESSION_STREAM_FRAME_RETRANSMITTED); connection()->CloseConnection( QUIC_INTERNAL_ERROR, "Attempt to retransmit frame of a closed stream", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); @@ -1085,9 +1095,7 @@ void QuicSession::OnStreamFrameRetransmitted(const QuicStreamFrame& frame) { void QuicSession::OnFrameLost(const QuicFrame& frame) { if (frame.type != STREAM_FRAME) { - if (use_control_frame_manager()) { - control_frame_manager_.OnControlFrameLost(frame); - } + control_frame_manager_.OnControlFrameLost(frame); return; } QuicStream* stream = GetStream(frame.stream_frame->stream_id); @@ -1112,8 +1120,7 @@ void QuicSession::RetransmitFrames(const QuicFrames& frames, SetTransmissionType(type); for (const QuicFrame& frame : frames) { if (frame.type != STREAM_FRAME) { - if (use_control_frame_manager() && - !control_frame_manager_.RetransmitControlFrame(frame)) { + if (!control_frame_manager_.RetransmitControlFrame(frame)) { break; } continue; @@ -1130,10 +1137,7 @@ void QuicSession::RetransmitFrames(const QuicFrames& frames, bool QuicSession::IsFrameOutstanding(const QuicFrame& frame) const { if (frame.type != STREAM_FRAME) { - if (use_control_frame_manager()) { - return control_frame_manager_.IsControlFrameOutstanding(frame); - } - return false; + return control_frame_manager_.IsControlFrameOutstanding(frame); } QuicStream* stream = GetStream(frame.stream_frame->stream_id); return stream != nullptr && @@ -1160,7 +1164,7 @@ bool QuicSession::WriteStreamData(QuicStreamId id, return stream->WriteStreamData(offset, data_length, writer); } -uint128 QuicSession::GetStatelessResetToken() const { +QuicUint128 QuicSession::GetStatelessResetToken() const { return kStatelessResetToken; } @@ -1180,8 +1184,7 @@ bool QuicSession::RetransmitLostData() { streams_with_pending_retransmission_.erase(kCryptoStreamId); } } - if (use_control_frame_manager() && - control_frame_manager_.HasPendingRetransmission()) { + if (control_frame_manager_.HasPendingRetransmission()) { SetTransmissionType(LOSS_RETRANSMISSION); control_frame_manager_.OnCanWrite(); if (control_frame_manager_.HasPendingRetransmission()) { @@ -1229,10 +1232,6 @@ void QuicSession::SetTransmissionType(TransmissionType type) { connection_->SetTransmissionType(type); } -bool QuicSession::use_control_frame_manager() const { - return connection_->use_control_frame_manager(); -} - bool QuicSession::session_decides_what_to_write() const { return connection_->session_decides_what_to_write(); } diff --git a/chromium/net/quic/core/quic_session.h b/chromium/net/quic/core/quic_session.h index a1db9b35a8e..c853834d134 100644 --- a/chromium/net/quic/core/quic_session.h +++ b/chromium/net/quic/core/quic_session.h @@ -14,7 +14,6 @@ #include "base/compiler_specific.h" #include "base/macros.h" -#include "net/base/int128.h" #include "net/quic/core/quic_connection.h" #include "net/quic/core/quic_control_frame_manager.h" #include "net/quic/core/quic_crypto_stream.h" @@ -117,6 +116,7 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, bool HasOpenDynamicStreams() const override; void OnPathDegrading() override; bool AllowSelfAddressChange() const override; + void OnForwardProgressConfirmed() override; // QuicStreamFrameDataProducer bool WriteStreamData(QuicStreamId id, @@ -200,6 +200,17 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, virtual void OnCryptoHandshakeMessageReceived( const CryptoHandshakeMessage& message); + // Called by the stream on creation to set priority in the write blocked list. + virtual void RegisterStreamPriority(QuicStreamId id, + bool is_static, + SpdyPriority priority); + // Called by the stream on deletion to clear priority crom the write blocked + // list. + virtual void UnregisterStreamPriority(QuicStreamId id, bool is_static); + // Called by the stream on SetPriority to update priority on the write blocked + // list. + virtual void UpdateStreamPriority(QuicStreamId id, SpdyPriority new_priority); + // Returns mutable config for this session. Returned config is owned // by QuicSession. QuicConfig* config(); @@ -294,17 +305,10 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // Returns true if this stream should yield writes to another blocked stream. bool ShouldYield(QuicStreamId stream_id); - // Called to cancel retransmission of unencrypted stream data. - void NeuterUnencryptedStreamData(); - // Set transmission type of next sending packets. void SetTransmissionType(TransmissionType type); - bool can_use_slices() const { return can_use_slices_; } - - bool session_unblocks_stream() const { return session_unblocks_stream_; } - - bool use_control_frame_manager() const; + bool register_streams_early() const { return register_streams_early_; } bool session_decides_what_to_write() const; @@ -424,7 +428,7 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // Returns a stateless reset token which will be included in the public reset // packet. - virtual uint128 GetStatelessResetToken() const; + virtual QuicUint128 GetStatelessResetToken() const; QuicControlFrameManager& control_frame_manager() { return control_frame_manager_; @@ -474,8 +478,15 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // May be null. Visitor* visitor_; - ClosedStreams closed_streams_; + // Latched value of quic_reloadable_flag_quic_register_streams_early2. + const bool register_streams_early_; + + // A list of streams which need to write more data. Stream register + // themselves in their constructor, and unregisterm themselves in their + // destructors, so the write blocked list must outlive all streams. + QuicWriteBlockedList write_blocked_streams_; + ClosedStreams closed_streams_; // Streams which are closed, but need to be kept alive. Currently, the only // reason is the stream's sent data (including FIN) does not get fully acked. ZombieStreamMap zombie_streams_; @@ -507,9 +518,6 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, // been consumed. QuicUnorderedSet<QuicStreamId> draining_streams_; - // A list of streams which need to write more data. - QuicWriteBlockedList write_blocked_streams_; - QuicStreamId largest_peer_created_stream_id_; // A counter for peer initiated streams which are in the dynamic_stream_map_. @@ -540,18 +548,11 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface, QuicControlFrameManager control_frame_manager_; - // QUIC stream can take ownership of application data provided in reference - // counted memory to avoid data copy. - const bool can_use_slices_; - // TODO(fayang): switch to linked_hash_set when chromium supports it. The bool // is not used here. // List of streams with pending retransmissions. QuicLinkedHashMap<QuicStreamId, bool> streams_with_pending_retransmission_; - // Latched value of quic_reloadable_flag_quic_streams_unblocked_by_session2. - const bool session_unblocks_stream_; - DISALLOW_COPY_AND_ASSIGN(QuicSession); }; diff --git a/chromium/net/quic/core/quic_session_test.cc b/chromium/net/quic/core/quic_session_test.cc new file mode 100644 index 00000000000..abc67d61a8c --- /dev/null +++ b/chromium/net/quic/core/quic_session_test.cc @@ -0,0 +1,1427 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/core/quic_session.h" + +#include <cstdint> +#include <set> +#include <utility> + +#include "base/callback.h" +#include "base/rand_util.h" +#include "build/build_config.h" +#include "net/quic/core/crypto/crypto_protocol.h" +#include "net/quic/core/crypto/null_encrypter.h" +#include "net/quic/core/quic_crypto_stream.h" +#include "net/quic/core/quic_data_writer.h" +#include "net/quic/core/quic_packets.h" +#include "net/quic/core/quic_stream.h" +#include "net/quic/core/quic_utils.h" +#include "net/quic/platform/api/quic_flags.h" +#include "net/quic/platform/api/quic_map_util.h" +#include "net/quic/platform/api/quic_ptr_util.h" +#include "net/quic/platform/api/quic_str_cat.h" +#include "net/quic/platform/api/quic_string.h" +#include "net/quic/platform/api/quic_string_piece.h" +#include "net/quic/platform/api/quic_test.h" +#include "net/quic/test_tools/quic_config_peer.h" +#include "net/quic/test_tools/quic_connection_peer.h" +#include "net/quic/test_tools/quic_flow_controller_peer.h" +#include "net/quic/test_tools/quic_session_peer.h" +#include "net/quic/test_tools/quic_stream_peer.h" +#include "net/quic/test_tools/quic_stream_send_buffer_peer.h" +#include "net/quic/test_tools/quic_test_utils.h" +#include "net/test/gtest_util.h" +#include "testing/gmock_mutant.h" + +using net::kV3HighestPriority; +using net::SpdyPriority; +using testing::_; +using testing::AtLeast; +using testing::InSequence; +using testing::Invoke; +using testing::Return; +using testing::StrictMock; + +namespace net { +namespace test { +namespace { + +class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { + public: + explicit TestCryptoStream(QuicSession* session) + : QuicCryptoStream(session), + QuicCryptoHandshaker(this, session), + encryption_established_(false), + handshake_confirmed_(false), + params_(new QuicCryptoNegotiatedParameters) {} + + void OnHandshakeMessage(const CryptoHandshakeMessage& /*message*/) override { + encryption_established_ = true; + handshake_confirmed_ = true; + CryptoHandshakeMessage msg; + QuicString error_details; + session()->config()->SetInitialStreamFlowControlWindowToSend( + kInitialStreamFlowControlWindowForTest); + session()->config()->SetInitialSessionFlowControlWindowToSend( + kInitialSessionFlowControlWindowForTest); + session()->config()->ToHandshakeMessage(&msg); + const QuicErrorCode error = + session()->config()->ProcessPeerHello(msg, CLIENT, &error_details); + EXPECT_EQ(QUIC_NO_ERROR, error); + session()->OnConfigNegotiated(); + session()->connection()->SetDefaultEncryptionLevel( + ENCRYPTION_FORWARD_SECURE); + session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + } + + // QuicCryptoStream implementation + bool encryption_established() const override { + return encryption_established_; + } + bool handshake_confirmed() const override { return handshake_confirmed_; } + const QuicCryptoNegotiatedParameters& crypto_negotiated_params() + const override { + return *params_; + } + CryptoMessageParser* crypto_message_parser() override { + return QuicCryptoHandshaker::crypto_message_parser(); + } + + MOCK_METHOD0(OnCanWrite, void()); + + MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); + + private: + using QuicCryptoStream::session; + + bool encryption_established_; + bool handshake_confirmed_; + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_; +}; + +class TestStream : public QuicStream { + public: + TestStream(QuicStreamId id, QuicSession* session) + : QuicStream(id, session, /*is_static=*/false) { + if (!session->register_streams_early()) { + session->RegisterStreamPriority(id, false, QuicStream::kDefaultPriority); + } + } + + ~TestStream() override { + if (!session()->register_streams_early()) { + session()->UnregisterStreamPriority(id(), false); + } + } + + using QuicStream::CloseWriteSide; + + void OnDataAvailable() override {} + + MOCK_METHOD0(OnCanWrite, void()); + MOCK_METHOD3(RetransmitStreamData, + bool(QuicStreamOffset, QuicByteCount, bool)); + + MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); +}; + +class TestSession : public QuicSession { + public: + explicit TestSession(QuicConnection* connection) + : QuicSession(connection, nullptr, DefaultQuicConfig()), + crypto_stream_(this), + writev_consumes_all_data_(false) { + Initialize(); + this->connection()->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + QuicMakeUnique<NullEncrypter>(connection->perspective())); + } + + ~TestSession() override { delete connection(); } + + TestCryptoStream* GetMutableCryptoStream() override { + return &crypto_stream_; + } + + const TestCryptoStream* GetCryptoStream() const override { + return &crypto_stream_; + } + + TestStream* CreateOutgoingDynamicStream() override { + TestStream* stream = new TestStream(GetNextOutgoingStreamId(), this); + ActivateStream(QuicWrapUnique(stream)); + return stream; + } + + TestStream* CreateIncomingDynamicStream(QuicStreamId id) override { + // Enforce the limit on the number of open streams. + if (GetNumOpenIncomingStreams() + 1 > max_open_incoming_streams()) { + connection()->CloseConnection( + QUIC_TOO_MANY_OPEN_STREAMS, "Too many streams!", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return nullptr; + } else { + TestStream* stream = new TestStream(id, this); + ActivateStream(QuicWrapUnique(stream)); + return stream; + } + } + + bool IsClosedStream(QuicStreamId id) { + return QuicSession::IsClosedStream(id); + } + + QuicStream* GetOrCreateDynamicStream(QuicStreamId stream_id) { + return QuicSession::GetOrCreateDynamicStream(stream_id); + } + + QuicConsumedData WritevData(QuicStream* stream, + QuicStreamId id, + size_t write_length, + QuicStreamOffset offset, + StreamSendingState state) override { + bool fin = state != NO_FIN; + QuicConsumedData consumed(write_length, fin); + if (!writev_consumes_all_data_) { + consumed = + QuicSession::WritevData(stream, id, write_length, offset, state); + } + if (fin && consumed.fin_consumed) { + stream->set_fin_sent(true); + } + QuicSessionPeer::GetWriteBlockedStreams(this)->UpdateBytesForStream( + id, consumed.bytes_consumed); + return consumed; + } + + void set_writev_consumes_all_data(bool val) { + writev_consumes_all_data_ = val; + } + + QuicConsumedData SendStreamData(QuicStream* stream) { + struct iovec iov; + if (stream->id() != kCryptoStreamId) { + this->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + } + MakeIOVector("not empty", &iov); + QuicStreamPeer::SendBuffer(stream).SaveStreamData(&iov, 1, 0, 9); + QuicConsumedData consumed = WritevData(stream, stream->id(), 9, 0, FIN); + QuicStreamPeer::SendBuffer(stream).OnStreamDataConsumed( + consumed.bytes_consumed); + return consumed; + } + + bool ClearControlFrame(const QuicFrame& frame) { + DeleteFrame(&const_cast<QuicFrame&>(frame)); + return true; + } + + QuicConsumedData SendLargeFakeData(QuicStream* stream, int bytes) { + DCHECK(writev_consumes_all_data_); + return WritevData(stream, stream->id(), bytes, 0, FIN); + } + + using QuicSession::closed_streams; + using QuicSession::next_outgoing_stream_id; + using QuicSession::PostProcessAfterData; + using QuicSession::zombie_streams; + + private: + StrictMock<TestCryptoStream> crypto_stream_; + + bool writev_consumes_all_data_; +}; + +class QuicSessionTestBase : public QuicTestWithParam<ParsedQuicVersion> { + protected: + explicit QuicSessionTestBase(Perspective perspective) + : connection_( + new StrictMock<MockQuicConnection>(&helper_, + &alarm_factory_, + perspective, + SupportedVersions(GetParam()))), + session_(connection_) { + session_.config()->SetInitialStreamFlowControlWindowToSend( + kInitialStreamFlowControlWindowForTest); + session_.config()->SetInitialSessionFlowControlWindowToSend( + kInitialSessionFlowControlWindowForTest); + connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); + TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream(); + EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) + .Times(testing::AnyNumber()); + } + + void CheckClosedStreams() { + for (QuicStreamId i = kCryptoStreamId; i < 100; i++) { + if (!QuicContainsKey(closed_streams_, i)) { + EXPECT_FALSE(session_.IsClosedStream(i)) << " stream id: " << i; + } else { + EXPECT_TRUE(session_.IsClosedStream(i)) << " stream id: " << i; + } + } + } + + void CloseStream(QuicStreamId id) { + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); + EXPECT_CALL(*connection_, OnStreamReset(id, _)); + session_.CloseStream(id); + closed_streams_.insert(id); + } + + QuicTransportVersion transport_version() const { + return connection_->transport_version(); + } + + QuicStreamId GetNthClientInitiatedId(int n) { return 3 + 2 * n; } + + QuicStreamId GetNthServerInitiatedId(int n) { return 2 + 2 * n; } + + MockQuicConnectionHelper helper_; + MockAlarmFactory alarm_factory_; + StrictMock<MockQuicConnection>* connection_; + TestSession session_; + std::set<QuicStreamId> closed_streams_; +}; + +class QuicSessionTestServer : public QuicSessionTestBase { + protected: + QuicSessionTestServer() : QuicSessionTestBase(Perspective::IS_SERVER) {} +}; + +INSTANTIATE_TEST_CASE_P(Tests, + QuicSessionTestServer, + ::testing::ValuesIn(AllSupportedVersions())); + +TEST_P(QuicSessionTestServer, PeerAddress) { + EXPECT_EQ(QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort), + session_.peer_address()); +} + +TEST_P(QuicSessionTestServer, SelfAddress) { + EXPECT_EQ(QuicSocketAddress(), session_.self_address()); +} + +TEST_P(QuicSessionTestServer, IsCryptoHandshakeConfirmed) { + EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed()); + CryptoHandshakeMessage message; + session_.GetMutableCryptoStream()->OnHandshakeMessage(message); + EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed()); +} + +TEST_P(QuicSessionTestServer, IsClosedStreamDefault) { + // Ensure that no streams are initially closed. + for (QuicStreamId i = kCryptoStreamId; i < 100; i++) { + EXPECT_FALSE(session_.IsClosedStream(i)) << "stream id: " << i; + } +} + +TEST_P(QuicSessionTestServer, AvailableStreams) { + ASSERT_TRUE(session_.GetOrCreateDynamicStream(9) != nullptr); + // Both 5 and 7 should be available. + EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 5)); + EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 7)); + ASSERT_TRUE(session_.GetOrCreateDynamicStream(7) != nullptr); + ASSERT_TRUE(session_.GetOrCreateDynamicStream(5) != nullptr); +} + +TEST_P(QuicSessionTestServer, IsClosedStreamLocallyCreated) { + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + EXPECT_EQ(GetNthServerInitiatedId(0), stream2->id()); + TestStream* stream4 = session_.CreateOutgoingDynamicStream(); + EXPECT_EQ(GetNthServerInitiatedId(1), stream4->id()); + + CheckClosedStreams(); + CloseStream(GetNthServerInitiatedId(0)); + CheckClosedStreams(); + CloseStream(GetNthServerInitiatedId(1)); + CheckClosedStreams(); +} + +TEST_P(QuicSessionTestServer, IsClosedStreamPeerCreated) { + QuicStreamId stream_id1 = GetNthClientInitiatedId(0); + QuicStreamId stream_id2 = GetNthClientInitiatedId(1); + session_.GetOrCreateDynamicStream(stream_id1); + session_.GetOrCreateDynamicStream(stream_id2); + + CheckClosedStreams(); + CloseStream(stream_id1); + CheckClosedStreams(); + CloseStream(stream_id2); + // Create a stream, and make another available. + QuicStream* stream3 = session_.GetOrCreateDynamicStream(stream_id2 + 4); + CheckClosedStreams(); + // Close one, but make sure the other is still not closed + CloseStream(stream3->id()); + CheckClosedStreams(); +} + +TEST_P(QuicSessionTestServer, MaximumAvailableOpenedStreams) { + QuicStreamId stream_id = GetNthClientInitiatedId(0); + session_.GetOrCreateDynamicStream(stream_id); + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); + EXPECT_NE(nullptr, + session_.GetOrCreateDynamicStream( + stream_id + 2 * (session_.max_open_incoming_streams() - 1))); +} + +TEST_P(QuicSessionTestServer, TooManyAvailableStreams) { + QuicStreamId stream_id1 = GetNthClientInitiatedId(0); + QuicStreamId stream_id2; + EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id1)); + // A stream ID which is too large to create. + stream_id2 = GetNthClientInitiatedId(2 * session_.MaxAvailableStreams() + 4); + EXPECT_CALL(*connection_, + CloseConnection(QUIC_TOO_MANY_AVAILABLE_STREAMS, _, _)); + EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(stream_id2)); +} + +TEST_P(QuicSessionTestServer, ManyAvailableStreams) { + // When max_open_streams_ is 200, should be able to create 200 streams + // out-of-order, that is, creating the one with the largest stream ID first. + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); + QuicStreamId stream_id = GetNthClientInitiatedId(0); + // Create one stream. + session_.GetOrCreateDynamicStream(stream_id); + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); + // Create the largest stream ID of a threatened total of 200 streams. + session_.GetOrCreateDynamicStream(stream_id + 2 * (200 - 1)); +} + +TEST_P(QuicSessionTestServer, DebugDFatalIfMarkingClosedStreamWriteBlocked) { + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + QuicStreamId closed_stream_id = stream2->id(); + // Close the stream. + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(closed_stream_id, _)); + stream2->Reset(QUIC_BAD_APPLICATION_PAYLOAD); + QuicString msg = + QuicStrCat("Marking unknown stream ", closed_stream_id, " blocked."); + EXPECT_QUIC_BUG(session_.MarkConnectionLevelWriteBlocked(closed_stream_id), + msg); +} + +TEST_P(QuicSessionTestServer, OnCanWrite) { + session_.set_writev_consumes_all_data(true); + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + TestStream* stream4 = session_.CreateOutgoingDynamicStream(); + TestStream* stream6 = session_.CreateOutgoingDynamicStream(); + + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + session_.MarkConnectionLevelWriteBlocked(stream6->id()); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + + InSequence s; + + // Reregister, to test the loop limit. + EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(Invoke([this, stream2]() { + session_.SendStreamData(stream2); + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + })); + // 2 will get called a second time as it didn't finish its block + EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(Invoke([this, stream2]() { + session_.SendStreamData(stream2); + })); + EXPECT_CALL(*stream6, OnCanWrite()).WillOnce(Invoke([this, stream6]() { + session_.SendStreamData(stream6); + })); + // 4 will not get called, as we exceeded the loop limit. + session_.OnCanWrite(); + EXPECT_TRUE(session_.WillingAndAbleToWrite()); +} + +TEST_P(QuicSessionTestServer, TestBatchedWrites) { + session_.set_writev_consumes_all_data(true); + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + TestStream* stream4 = session_.CreateOutgoingDynamicStream(); + TestStream* stream6 = session_.CreateOutgoingDynamicStream(); + + session_.set_writev_consumes_all_data(true); + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + + // With two sessions blocked, we should get two write calls. They should both + // go to the first stream as it will only write 6k and mark itself blocked + // again. + InSequence s; + EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(Invoke([this, stream2]() { + session_.SendLargeFakeData(stream2, 6000); + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + })); + EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(Invoke([this, stream2]() { + session_.SendLargeFakeData(stream2, 6000); + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + })); + session_.OnCanWrite(); + + // We should get one more call for stream2, at which point it has used its + // write quota and we move over to stream 4. + EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(Invoke([this, stream2]() { + session_.SendLargeFakeData(stream2, 6000); + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + })); + EXPECT_CALL(*stream4, OnCanWrite()).WillOnce(Invoke([this, stream4]() { + session_.SendLargeFakeData(stream4, 6000); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + })); + session_.OnCanWrite(); + + // Now let stream 4 do the 2nd of its 3 writes, but add a block for a high + // priority stream 6. 4 should be preempted. 6 will write but *not* block so + // will cede back to 4. + stream6->SetPriority(kV3HighestPriority); + EXPECT_CALL(*stream4, OnCanWrite()) + .WillOnce(Invoke([this, stream4, stream6]() { + session_.SendLargeFakeData(stream4, 6000); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + session_.MarkConnectionLevelWriteBlocked(stream6->id()); + })); + EXPECT_CALL(*stream6, OnCanWrite()) + .WillOnce(Invoke([this, stream4, stream6]() { + session_.SendStreamData(stream6); + session_.SendLargeFakeData(stream4, 6000); + })); + session_.OnCanWrite(); + + // Stream4 alread did 6k worth of writes, so after doing another 12k it should + // cede and 2 should resume. + EXPECT_CALL(*stream4, OnCanWrite()).WillOnce(Invoke([this, stream4]() { + session_.SendLargeFakeData(stream4, 12000); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + })); + EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(Invoke([this, stream2]() { + session_.SendLargeFakeData(stream2, 6000); + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + })); + session_.OnCanWrite(); +} + +TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) { + // Encryption needs to be established before data can be sent. + CryptoHandshakeMessage msg; + MockPacketWriter* writer = static_cast<MockPacketWriter*>( + QuicConnectionPeer::GetWriter(session_.connection())); + session_.GetMutableCryptoStream()->OnHandshakeMessage(msg); + + // Drive congestion control manually. + MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; + QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); + + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + TestStream* stream4 = session_.CreateOutgoingDynamicStream(); + TestStream* stream6 = session_.CreateOutgoingDynamicStream(); + + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + session_.MarkConnectionLevelWriteBlocked(stream6->id()); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + + EXPECT_CALL(*send_algorithm, CanSend(_)).WillRepeatedly(Return(true)); + EXPECT_CALL(*send_algorithm, GetCongestionWindow()) + .WillRepeatedly(Return(kMaxPacketSize * 10)); + EXPECT_CALL(*send_algorithm, InRecovery()).WillRepeatedly(Return(false)); + EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(Invoke([this, stream2]() { + session_.SendStreamData(stream2); + })); + EXPECT_CALL(*stream4, OnCanWrite()).WillOnce(Invoke([this, stream4]() { + session_.SendStreamData(stream4); + })); + EXPECT_CALL(*stream6, OnCanWrite()).WillOnce(Invoke([this, stream6]() { + session_.SendStreamData(stream6); + })); + + // Expect that we only send one packet, the writes from different streams + // should be bundled together. + EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)) + .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); + EXPECT_CALL(*send_algorithm, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(*send_algorithm, OnApplicationLimited(_)); + session_.OnCanWrite(); + EXPECT_FALSE(session_.WillingAndAbleToWrite()); +} + +TEST_P(QuicSessionTestServer, OnCanWriteCongestionControlBlocks) { + session_.set_writev_consumes_all_data(true); + InSequence s; + + // Drive congestion control manually. + MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; + QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); + + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + TestStream* stream4 = session_.CreateOutgoingDynamicStream(); + TestStream* stream6 = session_.CreateOutgoingDynamicStream(); + + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + session_.MarkConnectionLevelWriteBlocked(stream6->id()); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + + EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true)); + EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(Invoke([this, stream2]() { + session_.SendStreamData(stream2); + })); + EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true)); + EXPECT_CALL(*stream6, OnCanWrite()).WillOnce(Invoke([this, stream6]() { + session_.SendStreamData(stream6); + })); + EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(false)); + // stream4->OnCanWrite is not called. + + session_.OnCanWrite(); + EXPECT_TRUE(session_.WillingAndAbleToWrite()); + + // Still congestion-control blocked. + EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(false)); + session_.OnCanWrite(); + EXPECT_TRUE(session_.WillingAndAbleToWrite()); + + // stream4->OnCanWrite is called once the connection stops being + // congestion-control blocked. + EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true)); + EXPECT_CALL(*stream4, OnCanWrite()).WillOnce(Invoke([this, stream4]() { + session_.SendStreamData(stream4); + })); + EXPECT_CALL(*send_algorithm, OnApplicationLimited(_)); + session_.OnCanWrite(); + EXPECT_FALSE(session_.WillingAndAbleToWrite()); +} + +TEST_P(QuicSessionTestServer, OnCanWriteWriterBlocks) { + // Drive congestion control manually in order to ensure that + // application-limited signaling is handled correctly. + MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; + QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); + EXPECT_CALL(*send_algorithm, CanSend(_)).WillRepeatedly(Return(true)); + + // Drive packet writer manually. + MockPacketWriter* writer = static_cast<MockPacketWriter*>( + QuicConnectionPeer::GetWriter(session_.connection())); + EXPECT_CALL(*writer, IsWriteBlocked()).WillRepeatedly(Return(true)); + EXPECT_CALL(*writer, IsWriteBlockedDataBuffered()) + .WillRepeatedly(Return(true)); + EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)).Times(0); + + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + + EXPECT_CALL(*stream2, OnCanWrite()).Times(0); + EXPECT_CALL(*send_algorithm, OnApplicationLimited(_)).Times(0); + + session_.OnCanWrite(); + EXPECT_TRUE(session_.WillingAndAbleToWrite()); +} + +TEST_P(QuicSessionTestServer, BufferedHandshake) { + session_.set_writev_consumes_all_data(true); + EXPECT_FALSE(session_.HasPendingHandshake()); // Default value. + + // Test that blocking other streams does not change our status. + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + EXPECT_FALSE(session_.HasPendingHandshake()); + + TestStream* stream3 = session_.CreateOutgoingDynamicStream(); + session_.MarkConnectionLevelWriteBlocked(stream3->id()); + EXPECT_FALSE(session_.HasPendingHandshake()); + + // Blocking (due to buffering of) the Crypto stream is detected. + session_.MarkConnectionLevelWriteBlocked(kCryptoStreamId); + EXPECT_TRUE(session_.HasPendingHandshake()); + + TestStream* stream4 = session_.CreateOutgoingDynamicStream(); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + EXPECT_TRUE(session_.HasPendingHandshake()); + + InSequence s; + // Force most streams to re-register, which is common scenario when we block + // the Crypto stream, and only the crypto stream can "really" write. + + // Due to prioritization, we *should* be asked to write the crypto stream + // first. + // Don't re-register the crypto stream (which signals complete writing). + TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream(); + EXPECT_CALL(*crypto_stream, OnCanWrite()); + + EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(Invoke([this, stream2]() { + session_.SendStreamData(stream2); + })); + EXPECT_CALL(*stream3, OnCanWrite()).WillOnce(Invoke([this, stream3]() { + session_.SendStreamData(stream3); + })); + EXPECT_CALL(*stream4, OnCanWrite()).WillOnce(Invoke([this, stream4]() { + session_.SendStreamData(stream4); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + })); + + session_.OnCanWrite(); + EXPECT_TRUE(session_.WillingAndAbleToWrite()); + EXPECT_FALSE(session_.HasPendingHandshake()); // Crypto stream wrote. +} + +TEST_P(QuicSessionTestServer, OnCanWriteWithClosedStream) { + session_.set_writev_consumes_all_data(true); + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + TestStream* stream4 = session_.CreateOutgoingDynamicStream(); + TestStream* stream6 = session_.CreateOutgoingDynamicStream(); + + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + session_.MarkConnectionLevelWriteBlocked(stream6->id()); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + CloseStream(stream6->id()); + + InSequence s; + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); + EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(Invoke([this, stream2]() { + session_.SendStreamData(stream2); + })); + EXPECT_CALL(*stream4, OnCanWrite()).WillOnce(Invoke([this, stream4]() { + session_.SendStreamData(stream4); + })); + session_.OnCanWrite(); + EXPECT_FALSE(session_.WillingAndAbleToWrite()); +} + +TEST_P(QuicSessionTestServer, OnCanWriteLimitsNumWritesIfFlowControlBlocked) { + // Drive congestion control manually in order to ensure that + // application-limited signaling is handled correctly. + MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; + QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); + EXPECT_CALL(*send_algorithm, CanSend(_)).WillRepeatedly(Return(true)); + + // Ensure connection level flow control blockage. + QuicFlowControllerPeer::SetSendWindowOffset(session_.flow_controller(), 0); + EXPECT_TRUE(session_.flow_controller()->IsBlocked()); + EXPECT_TRUE(session_.IsConnectionFlowControlBlocked()); + EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); + + // Mark the crypto and headers streams as write blocked, we expect them to be + // allowed to write later. + session_.MarkConnectionLevelWriteBlocked(kCryptoStreamId); + + // Create a data stream, and although it is write blocked we never expect it + // to be allowed to write as we are connection level flow control blocked. + TestStream* stream = session_.CreateOutgoingDynamicStream(); + session_.MarkConnectionLevelWriteBlocked(stream->id()); + EXPECT_CALL(*stream, OnCanWrite()).Times(0); + + // The crypto and headers streams should be called even though we are + // connection flow control blocked. + TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream(); + EXPECT_CALL(*crypto_stream, OnCanWrite()); + + // After the crypto and header streams perform a write, the connection will be + // blocked by the flow control, hence it should become application-limited. + EXPECT_CALL(*send_algorithm, OnApplicationLimited(_)); + + session_.OnCanWrite(); + EXPECT_FALSE(session_.WillingAndAbleToWrite()); +} + +TEST_P(QuicSessionTestServer, SendGoAway) { + MockPacketWriter* writer = static_cast<MockPacketWriter*>( + QuicConnectionPeer::GetWriter(session_.connection())); + EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)) + .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); + + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce( + Invoke(connection_, &MockQuicConnection::ReallySendControlFrame)); + session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); + EXPECT_TRUE(session_.goaway_sent()); + + const QuicStreamId kTestStreamId = 5u; + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); + EXPECT_CALL(*connection_, + OnStreamReset(kTestStreamId, QUIC_STREAM_PEER_GOING_AWAY)) + .Times(0); + EXPECT_TRUE(session_.GetOrCreateDynamicStream(kTestStreamId)); +} + +TEST_P(QuicSessionTestServer, DoNotSendGoAwayTwice) { + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); + session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); + EXPECT_TRUE(session_.goaway_sent()); + session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); +} + +TEST_P(QuicSessionTestServer, InvalidGoAway) { + QuicGoAwayFrame go_away(kInvalidControlFrameId, QUIC_PEER_GOING_AWAY, + session_.next_outgoing_stream_id(), ""); + session_.OnGoAway(go_away); +} + +// Test that server session will send a connectivity probe in response to a +// connectivity probe on the same path. +TEST_P(QuicSessionTestServer, ServerReplyToConnecitivityProbe) { + QuicSocketAddress old_peer_address = + QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort); + EXPECT_EQ(old_peer_address, session_.peer_address()); + + QuicSocketAddress new_peer_address = + QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort + 1); + + MockPacketWriter* writer = static_cast<MockPacketWriter*>( + QuicConnectionPeer::GetWriter(session_.connection())); + EXPECT_CALL(*writer, WritePacket(_, _, _, new_peer_address, _)) + .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); + EXPECT_CALL(*connection_, + SendConnectivityProbingPacket(nullptr, new_peer_address)) + .WillOnce( + Invoke(connection_, + &MockQuicConnection::ReallySendConnectivityProbingPacket)); + session_.OnConnectivityProbeReceived(session_.self_address(), + new_peer_address); + EXPECT_EQ(old_peer_address, session_.peer_address()); +} + +TEST_P(QuicSessionTestServer, IncreasedTimeoutAfterCryptoHandshake) { + EXPECT_EQ(kInitialIdleTimeoutSecs + 3, + QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); + CryptoHandshakeMessage msg; + session_.GetMutableCryptoStream()->OnHandshakeMessage(msg); + EXPECT_EQ(kMaximumIdleTimeoutSecs + 3, + QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); +} + +TEST_P(QuicSessionTestServer, OnStreamFrameFinStaticStreamId) { + // Send two bytes of payload. + QuicStreamFrame data1(kCryptoStreamId, true, 0, QuicStringPiece("HT")); + EXPECT_CALL(*connection_, + CloseConnection( + QUIC_INVALID_STREAM_ID, "Attempt to close a static stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET)); + session_.OnStreamFrame(data1); +} + +TEST_P(QuicSessionTestServer, OnRstStreamStaticStreamId) { + // Send two bytes of payload. + QuicRstStreamFrame rst1(kInvalidControlFrameId, kCryptoStreamId, + QUIC_ERROR_PROCESSING_STREAM, 0); + EXPECT_CALL(*connection_, + CloseConnection( + QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET)); + session_.OnRstStream(rst1); +} + +TEST_P(QuicSessionTestServer, OnStreamFrameInvalidStreamId) { + // Send two bytes of payload. + QuicStreamFrame data1(kInvalidStreamId, true, 0, QuicStringPiece("HT")); + EXPECT_CALL(*connection_, + CloseConnection( + QUIC_INVALID_STREAM_ID, "Recevied data for an invalid stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET)); + session_.OnStreamFrame(data1); +} + +TEST_P(QuicSessionTestServer, OnRstStreamInvalidStreamId) { + // Send two bytes of payload. + QuicRstStreamFrame rst1(kInvalidControlFrameId, kInvalidStreamId, + QUIC_ERROR_PROCESSING_STREAM, 0); + EXPECT_CALL(*connection_, + CloseConnection( + QUIC_INVALID_STREAM_ID, "Recevied data for an invalid stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET)); + session_.OnRstStream(rst1); +} + +TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedStream) { + // Test that if a stream is flow control blocked, then on receipt of the SHLO + // containing a suitable send window offset, the stream becomes unblocked. + + // Ensure that Writev consumes all the data it is given (simulate no socket + // blocking). + session_.set_writev_consumes_all_data(true); + + // Create a stream, and send enough data to make it flow control blocked. + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + QuicString body(kMinimumFlowControlSendWindow, '.'); + EXPECT_FALSE(stream2->flow_controller()->IsBlocked()); + EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); + EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(AtLeast(1)); + stream2->WriteOrBufferData(body, false, nullptr); + EXPECT_TRUE(stream2->flow_controller()->IsBlocked()); + EXPECT_TRUE(session_.IsConnectionFlowControlBlocked()); + EXPECT_TRUE(session_.IsStreamFlowControlBlocked()); + + // Now complete the crypto handshake, resulting in an increased flow control + // send window. + CryptoHandshakeMessage msg; + session_.GetMutableCryptoStream()->OnHandshakeMessage(msg); + EXPECT_TRUE(QuicSessionPeer::IsStreamWriteBlocked(&session_, stream2->id())); + // Stream is now unblocked. + EXPECT_FALSE(stream2->flow_controller()->IsBlocked()); + EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); + EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); +} + +TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) { + // Test that if the crypto stream is flow control blocked, then if the SHLO + // contains a larger send window offset, the stream becomes unblocked. + session_.set_writev_consumes_all_data(true); + TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream(); + EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked()); + EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); + EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); + EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); + EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); + for (QuicStreamId i = 0; + !crypto_stream->flow_controller()->IsBlocked() && i < 1000u; i++) { + EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); + EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); + QuicStreamOffset offset = crypto_stream->stream_bytes_written(); + QuicConfig config; + CryptoHandshakeMessage crypto_message; + config.ToHandshakeMessage(&crypto_message); + crypto_stream->SendHandshakeMessage(crypto_message); + char buf[1000]; + QuicDataWriter writer(1000, buf, NETWORK_BYTE_ORDER); + crypto_stream->WriteStreamData(offset, crypto_message.size(), &writer); + } + EXPECT_TRUE(crypto_stream->flow_controller()->IsBlocked()); + EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); + EXPECT_TRUE(session_.IsStreamFlowControlBlocked()); + EXPECT_FALSE(session_.HasDataToWrite()); + EXPECT_TRUE(crypto_stream->HasBufferedData()); + + // Now complete the crypto handshake, resulting in an increased flow control + // send window. + CryptoHandshakeMessage msg; + session_.GetMutableCryptoStream()->OnHandshakeMessage(msg); + EXPECT_TRUE( + QuicSessionPeer::IsStreamWriteBlocked(&session_, kCryptoStreamId)); + // Stream is now unblocked and will no longer have buffered data. + EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked()); + EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); + EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); +} + +TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstOutOfOrder) { + // Test that when we receive an out of order stream RST we correctly adjust + // our connection level flow control receive window. + // On close, the stream should mark as consumed all bytes between the highest + // byte consumed so far and the final byte offset from the RST frame. + TestStream* stream = session_.CreateOutgoingDynamicStream(); + + const QuicStreamOffset kByteOffset = + 1 + kInitialSessionFlowControlWindowForTest / 2; + + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(2) + .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); + QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream->id(), + QUIC_STREAM_CANCELLED, kByteOffset); + session_.OnRstStream(rst_frame); + session_.PostProcessAfterData(); + EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed()); +} + +TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAndLocalReset) { + // Test the situation where we receive a FIN on a stream, and before we fully + // consume all the data from the sequencer buffer we locally RST the stream. + // The bytes between highest consumed byte, and the final byte offset that we + // determined when the FIN arrived, should be marked as consumed at the + // connection level flow controller when the stream is reset. + TestStream* stream = session_.CreateOutgoingDynamicStream(); + + const QuicStreamOffset kByteOffset = + kInitialSessionFlowControlWindowForTest / 2 - 1; + QuicStreamFrame frame(stream->id(), true, kByteOffset, "."); + session_.OnStreamFrame(frame); + session_.PostProcessAfterData(); + EXPECT_TRUE(connection_->connected()); + + EXPECT_EQ(0u, stream->flow_controller()->bytes_consumed()); + EXPECT_EQ(kByteOffset + frame.data_length, + stream->flow_controller()->highest_received_byte_offset()); + + // Reset stream locally. + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); + stream->Reset(QUIC_STREAM_CANCELLED); + EXPECT_EQ(kByteOffset + frame.data_length, + session_.flow_controller()->bytes_consumed()); +} + +TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAfterRst) { + // Test that when we RST the stream (and tear down stream state), and then + // receive a FIN from the peer, we correctly adjust our connection level flow + // control receive window. + + // Connection starts with some non-zero highest received byte offset, + // due to other active streams. + const uint64_t kInitialConnectionBytesConsumed = 567; + const uint64_t kInitialConnectionHighestReceivedOffset = 1234; + EXPECT_LT(kInitialConnectionBytesConsumed, + kInitialConnectionHighestReceivedOffset); + session_.flow_controller()->UpdateHighestReceivedOffset( + kInitialConnectionHighestReceivedOffset); + session_.flow_controller()->AddBytesConsumed(kInitialConnectionBytesConsumed); + + // Reset our stream: this results in the stream being closed locally. + TestStream* stream = session_.CreateOutgoingDynamicStream(); + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); + stream->Reset(QUIC_STREAM_CANCELLED); + + // Now receive a response from the peer with a FIN. We should handle this by + // adjusting the connection level flow control receive window to take into + // account the total number of bytes sent by the peer. + const QuicStreamOffset kByteOffset = 5678; + QuicString body = "hello"; + QuicStreamFrame frame(stream->id(), true, kByteOffset, QuicStringPiece(body)); + session_.OnStreamFrame(frame); + + QuicStreamOffset total_stream_bytes_sent_by_peer = + kByteOffset + body.length(); + EXPECT_EQ(kInitialConnectionBytesConsumed + total_stream_bytes_sent_by_peer, + session_.flow_controller()->bytes_consumed()); + EXPECT_EQ( + kInitialConnectionHighestReceivedOffset + total_stream_bytes_sent_by_peer, + session_.flow_controller()->highest_received_byte_offset()); +} + +TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstAfterRst) { + // Test that when we RST the stream (and tear down stream state), and then + // receive a RST from the peer, we correctly adjust our connection level flow + // control receive window. + + // Connection starts with some non-zero highest received byte offset, + // due to other active streams. + const uint64_t kInitialConnectionBytesConsumed = 567; + const uint64_t kInitialConnectionHighestReceivedOffset = 1234; + EXPECT_LT(kInitialConnectionBytesConsumed, + kInitialConnectionHighestReceivedOffset); + session_.flow_controller()->UpdateHighestReceivedOffset( + kInitialConnectionHighestReceivedOffset); + session_.flow_controller()->AddBytesConsumed(kInitialConnectionBytesConsumed); + + // Reset our stream: this results in the stream being closed locally. + TestStream* stream = session_.CreateOutgoingDynamicStream(); + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); + stream->Reset(QUIC_STREAM_CANCELLED); + EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream)); + + // Now receive a RST from the peer. We should handle this by adjusting the + // connection level flow control receive window to take into account the total + // number of bytes sent by the peer. + const QuicStreamOffset kByteOffset = 5678; + QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream->id(), + QUIC_STREAM_CANCELLED, kByteOffset); + session_.OnRstStream(rst_frame); + + EXPECT_EQ(kInitialConnectionBytesConsumed + kByteOffset, + session_.flow_controller()->bytes_consumed()); + EXPECT_EQ(kInitialConnectionHighestReceivedOffset + kByteOffset, + session_.flow_controller()->highest_received_byte_offset()); +} + +TEST_P(QuicSessionTestServer, InvalidStreamFlowControlWindowInHandshake) { + // Test that receipt of an invalid (< default) stream flow control window from + // the peer results in the connection being torn down. + const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1; + QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(session_.config(), + kInvalidWindow); + + EXPECT_CALL(*connection_, + CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _)); + session_.OnConfigNegotiated(); +} + +TEST_P(QuicSessionTestServer, InvalidSessionFlowControlWindowInHandshake) { + // Test that receipt of an invalid (< default) session flow control window + // from the peer results in the connection being torn down. + const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1; + QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(), + kInvalidWindow); + + EXPECT_CALL(*connection_, + CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _)); + session_.OnConfigNegotiated(); +} + +// Test negotiation of custom server initial flow control window. +TEST_P(QuicSessionTestServer, CustomFlowControlWindow) { + QuicTagVector copt; + copt.push_back(kIFW7); + QuicConfigPeer::SetReceivedConnectionOptions(session_.config(), copt); + + session_.OnConfigNegotiated(); + EXPECT_EQ(192 * 1024u, QuicFlowControllerPeer::ReceiveWindowSize( + session_.flow_controller())); +} + +TEST_P(QuicSessionTestServer, FlowControlWithInvalidFinalOffset) { + // Test that if we receive a stream RST with a highest byte offset that + // violates flow control, that we close the connection. + const uint64_t kLargeOffset = kInitialSessionFlowControlWindowForTest + 1; + EXPECT_CALL(*connection_, + CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _)) + .Times(2); + + // Check that stream frame + FIN results in connection close. + TestStream* stream = session_.CreateOutgoingDynamicStream(); + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); + stream->Reset(QUIC_STREAM_CANCELLED); + QuicStreamFrame frame(stream->id(), true, kLargeOffset, QuicStringPiece()); + session_.OnStreamFrame(frame); + + // Check that RST results in connection close. + QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream->id(), + QUIC_STREAM_CANCELLED, kLargeOffset); + session_.OnRstStream(rst_frame); +} + +TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseServerRejectStream) { + // If a buggy/malicious peer creates too many streams that are not ended + // with a FIN or RST then we send an RST to refuse streams. + const QuicStreamId kMaxStreams = 5; + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + const QuicStreamId kFirstStreamId = GetNthClientInitiatedId(0); + const QuicStreamId kFinalStreamId = GetNthClientInitiatedId(kMaxStreams); + // Create kMaxStreams data streams, and close them all without receiving a + // FIN or a RST_STREAM from the client. + for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) { + QuicStreamFrame data1(i, false, 0, QuicStringPiece("HT")); + session_.OnStreamFrame(data1); + // EXPECT_EQ(1u, session_.GetNumOpenStreams()); + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); + EXPECT_CALL(*connection_, OnStreamReset(i, _)); + session_.CloseStream(i); + } + + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); + EXPECT_CALL(*connection_, OnStreamReset(kFinalStreamId, QUIC_REFUSED_STREAM)) + .Times(1); + // Create one more data streams to exceed limit of open stream. + QuicStreamFrame data1(kFinalStreamId, false, 0, QuicStringPiece("HT")); + session_.OnStreamFrame(data1); + + // Called after any new data is received by the session, and triggers the + // call to close the connection. + session_.PostProcessAfterData(); +} + +TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) { + // Verify that a draining stream (which has received a FIN but not consumed + // it) does not count against the open quota (because it is closed from the + // protocol point of view). + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); + EXPECT_CALL(*connection_, OnStreamReset(_, QUIC_REFUSED_STREAM)).Times(0); + const QuicStreamId kMaxStreams = 5; + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + + // Create kMaxStreams + 1 data streams, and mark them draining. + const QuicStreamId kFirstStreamId = GetNthClientInitiatedId(0); + const QuicStreamId kFinalStreamId = + GetNthClientInitiatedId(2 * kMaxStreams + 1); + for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) { + QuicStreamFrame data1(i, true, 0, QuicStringPiece("HT")); + session_.OnStreamFrame(data1); + EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams()); + session_.StreamDraining(i); + EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams()); + } + + // Called after any new data is received by the session, and triggers the call + // to close the connection. + session_.PostProcessAfterData(); +} + +TEST_P(QuicSessionTestServer, TestMaxIncomingAndOutgoingStreamsAllowed) { + // Tests that on server side, the value of max_open_incoming/outgoing streams + // are setup correctly during negotiation. + // The value for outgoing stream is limited to negotiated value and for + // incoming stream it is set to be larger than that. + session_.OnConfigNegotiated(); + // The max number of open outgoing streams is less than that of incoming + // streams, and it should be same as negotiated value. + EXPECT_LT(session_.max_open_outgoing_streams(), + session_.max_open_incoming_streams()); + EXPECT_EQ(session_.max_open_outgoing_streams(), + kDefaultMaxStreamsPerConnection); + EXPECT_GT(session_.max_open_incoming_streams(), + kDefaultMaxStreamsPerConnection); +} + +class QuicSessionTestClient : public QuicSessionTestBase { + protected: + QuicSessionTestClient() : QuicSessionTestBase(Perspective::IS_CLIENT) {} +}; + +INSTANTIATE_TEST_CASE_P(Tests, + QuicSessionTestClient, + ::testing::ValuesIn(AllSupportedVersions())); + +TEST_P(QuicSessionTestClient, AvailableStreamsClient) { + ASSERT_TRUE(session_.GetOrCreateDynamicStream(6) != nullptr); + // Both 2 and 4 should be available. + EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 2)); + EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 4)); + ASSERT_TRUE(session_.GetOrCreateDynamicStream(2) != nullptr); + ASSERT_TRUE(session_.GetOrCreateDynamicStream(4) != nullptr); + // And 5 should be not available. + EXPECT_FALSE(QuicSessionPeer::IsStreamAvailable(&session_, 5)); +} + +TEST_P(QuicSessionTestClient, RecordFinAfterReadSideClosed) { + // Verify that an incoming FIN is recorded in a stream object even if the read + // side has been closed. This prevents an entry from being made in + // locally_closed_streams_highest_offset_ (which will never be deleted). + TestStream* stream = session_.CreateOutgoingDynamicStream(); + QuicStreamId stream_id = stream->id(); + + // Close the read side manually. + QuicStreamPeer::CloseReadSide(stream); + + // Receive a stream data frame with FIN. + QuicStreamFrame frame(stream_id, true, 0, QuicStringPiece()); + session_.OnStreamFrame(frame); + EXPECT_TRUE(stream->fin_received()); + + // Reset stream locally. + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); + stream->Reset(QUIC_STREAM_CANCELLED); + EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream)); + + // Allow the session to delete the stream object. + session_.PostProcessAfterData(); + EXPECT_TRUE(connection_->connected()); + EXPECT_TRUE(QuicSessionPeer::IsStreamClosed(&session_, stream_id)); + EXPECT_FALSE(QuicSessionPeer::IsStreamCreated(&session_, stream_id)); + + // The stream is not waiting for the arrival of the peer's final offset as it + // was received with the FIN earlier. + EXPECT_EQ( + 0u, + QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(&session_).size()); +} + +TEST_P(QuicSessionTestClient, TestMaxIncomingAndOutgoingStreamsAllowed) { + // Tests that on client side, the value of max_open_incoming/outgoing streams + // are setup correctly during negotiation. + // When flag is true, the value for outgoing stream is limited to negotiated + // value and for incoming stream it is set to be larger than that. + session_.OnConfigNegotiated(); + EXPECT_LT(session_.max_open_outgoing_streams(), + session_.max_open_incoming_streams()); + EXPECT_EQ(session_.max_open_outgoing_streams(), + kDefaultMaxStreamsPerConnection); +} + +TEST_P(QuicSessionTestServer, ZombieStreams) { + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + QuicStreamPeer::SetStreamBytesWritten(3, stream2); + EXPECT_TRUE(stream2->IsWaitingForAcks()); + + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(2, _)); + session_.CloseStream(2); + if (GetQuicReloadableFlag(quic_reset_stream_is_not_zombie)) { + EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), 2)); + ASSERT_EQ(1u, session_.closed_streams()->size()); + EXPECT_EQ(2u, session_.closed_streams()->front()->id()); + } else { + EXPECT_TRUE(QuicContainsKey(session_.zombie_streams(), 2)); + EXPECT_TRUE(session_.closed_streams()->empty()); + } + session_.OnStreamDoneWaitingForAcks(2); + EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), 2)); + EXPECT_EQ(1u, session_.closed_streams()->size()); + EXPECT_EQ(2u, session_.closed_streams()->front()->id()); +} + +// Regression test of b/71548958. +TEST_P(QuicSessionTestServer, TestZombieStreams) { + session_.set_writev_consumes_all_data(true); + + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + QuicString body(100, '.'); + stream2->WriteOrBufferData(body, false, nullptr); + EXPECT_TRUE(stream2->IsWaitingForAcks()); + EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream2).size()); + + QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream2->id(), + QUIC_STREAM_CANCELLED, 1234); + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); + EXPECT_CALL(*connection_, + OnStreamReset(stream2->id(), QUIC_RST_ACKNOWLEDGEMENT)); + stream2->OnStreamReset(rst_frame); + if (GetQuicReloadableFlag(quic_reset_stream_is_not_zombie)) { + EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id())); + ASSERT_EQ(1u, session_.closed_streams()->size()); + EXPECT_EQ(stream2->id(), session_.closed_streams()->front()->id()); + } else { + // Stream reset by peer, and it becomes zombie stream and the data will be + // NEVER be acked because the frames in unacked packet map are removed. + EXPECT_TRUE(QuicContainsKey(session_.zombie_streams(), stream2->id())); + EXPECT_TRUE(session_.closed_streams()->empty()); + EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream2).size()); + } + + TestStream* stream4 = session_.CreateOutgoingDynamicStream(); + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); + EXPECT_CALL(*connection_, + OnStreamReset(stream4->id(), QUIC_STREAM_CANCELLED)); + stream4->WriteOrBufferData(body, false, nullptr); + stream4->Reset(QUIC_STREAM_CANCELLED); + EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream4->id())); + if (GetQuicReloadableFlag(quic_reset_stream_is_not_zombie)) { + EXPECT_EQ(2u, session_.closed_streams()->size()); + } else { + EXPECT_EQ(1u, session_.closed_streams()->size()); + } +} + +TEST_P(QuicSessionTestServer, OnStreamFrameLost) { + QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); + InSequence s; + + // Drive congestion control manually. + MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; + QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); + + TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream(); + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + TestStream* stream4 = session_.CreateOutgoingDynamicStream(); + + QuicStreamFrame frame1(kCryptoStreamId, false, 0, 1300); + QuicStreamFrame frame2(stream2->id(), false, 0, 9); + QuicStreamFrame frame3(stream4->id(), false, 0, 9); + + // Lost data on cryption stream, streams 2 and 4. + EXPECT_CALL(*stream4, HasPendingRetransmission()).WillOnce(Return(true)); + EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) + .WillOnce(Return(true)); + EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(true)); + session_.OnFrameLost(QuicFrame(&frame3)); + session_.OnFrameLost(QuicFrame(&frame1)); + session_.OnFrameLost(QuicFrame(&frame2)); + EXPECT_TRUE(session_.WillingAndAbleToWrite()); + + // Mark streams 2 and 4 write blocked. + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + + // Lost data is retransmitted before new data, and retransmissions for crypto + // stream go first. + // Do not check congestion window when crypto stream has lost data. + EXPECT_CALL(*send_algorithm, CanSend(_)).Times(0); + EXPECT_CALL(*crypto_stream, OnCanWrite()); + EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) + .WillOnce(Return(false)); + // Check congestion window for non crypto streams. + EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true)); + EXPECT_CALL(*stream4, OnCanWrite()); + EXPECT_CALL(*stream4, HasPendingRetransmission()).WillOnce(Return(false)); + // Connection is blocked. + EXPECT_CALL(*send_algorithm, CanSend(_)).WillRepeatedly(Return(false)); + + session_.OnCanWrite(); + EXPECT_TRUE(session_.WillingAndAbleToWrite()); + + // Unblock connection. + // Stream 2 retransmits lost data. + EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true)); + EXPECT_CALL(*stream2, OnCanWrite()); + EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(false)); + EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true)); + // Stream 2 sends new data. + EXPECT_CALL(*stream2, OnCanWrite()); + EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true)); + EXPECT_CALL(*stream4, OnCanWrite()); + EXPECT_CALL(*send_algorithm, OnApplicationLimited(_)); + + session_.OnCanWrite(); + EXPECT_FALSE(session_.WillingAndAbleToWrite()); +} + +TEST_P(QuicSessionTestServer, DonotRetransmitDataOfClosedStreams) { + QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); + InSequence s; + + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + TestStream* stream4 = session_.CreateOutgoingDynamicStream(); + TestStream* stream6 = session_.CreateOutgoingDynamicStream(); + + QuicStreamFrame frame1(stream2->id(), false, 0, 9); + QuicStreamFrame frame2(stream4->id(), false, 0, 9); + QuicStreamFrame frame3(stream6->id(), false, 0, 9); + + EXPECT_CALL(*stream6, HasPendingRetransmission()).WillOnce(Return(true)); + EXPECT_CALL(*stream4, HasPendingRetransmission()).WillOnce(Return(true)); + EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(true)); + session_.OnFrameLost(QuicFrame(&frame3)); + session_.OnFrameLost(QuicFrame(&frame2)); + session_.OnFrameLost(QuicFrame(&frame1)); + + session_.MarkConnectionLevelWriteBlocked(stream2->id()); + session_.MarkConnectionLevelWriteBlocked(stream4->id()); + session_.MarkConnectionLevelWriteBlocked(stream6->id()); + + // Reset stream 4 locally. + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream4->id(), _)); + stream4->Reset(QUIC_STREAM_CANCELLED); + + // Verify stream 4 is removed from streams with lost data list. + EXPECT_CALL(*stream6, OnCanWrite()); + EXPECT_CALL(*stream6, HasPendingRetransmission()).WillOnce(Return(false)); + EXPECT_CALL(*stream2, OnCanWrite()); + EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(false)); + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); + EXPECT_CALL(*stream2, OnCanWrite()); + EXPECT_CALL(*stream6, OnCanWrite()); + session_.OnCanWrite(); +} + +TEST_P(QuicSessionTestServer, RetransmitFrames) { + QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); + MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; + QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); + InSequence s; + + TestStream* stream2 = session_.CreateOutgoingDynamicStream(); + TestStream* stream4 = session_.CreateOutgoingDynamicStream(); + TestStream* stream6 = session_.CreateOutgoingDynamicStream(); + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); + session_.SendWindowUpdate(stream2->id(), 9); + + QuicStreamFrame frame1(stream2->id(), false, 0, 9); + QuicStreamFrame frame2(stream4->id(), false, 0, 9); + QuicStreamFrame frame3(stream6->id(), false, 0, 9); + QuicWindowUpdateFrame window_update(1, stream2->id(), 9); + QuicFrames frames; + frames.push_back(QuicFrame(&frame1)); + frames.push_back(QuicFrame(&window_update)); + frames.push_back(QuicFrame(&frame2)); + frames.push_back(QuicFrame(&frame3)); + EXPECT_FALSE(session_.WillingAndAbleToWrite()); + + EXPECT_CALL(*stream2, RetransmitStreamData(_, _, _)).WillOnce(Return(true)); + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); + EXPECT_CALL(*stream4, RetransmitStreamData(_, _, _)).WillOnce(Return(true)); + EXPECT_CALL(*stream6, RetransmitStreamData(_, _, _)).WillOnce(Return(true)); + EXPECT_CALL(*send_algorithm, OnApplicationLimited(_)); + session_.RetransmitFrames(frames, TLP_RETRANSMISSION); +} + +} // namespace +} // namespace test +} // namespace net diff --git a/chromium/net/quic/core/quic_spdy_session.cc b/chromium/net/quic/core/quic_spdy_session.cc index a64af281494..f05447305e3 100644 --- a/chromium/net/quic/core/quic_spdy_session.cc +++ b/chromium/net/quic/core/quic_spdy_session.cc @@ -119,7 +119,50 @@ class QuicSpdySession::SpdyFramerVisitor QUIC_INVALID_HEADERS_STREAM_DATA); } - void OnSetting(SpdyKnownSettingsId id, uint32_t value) override { + void OnSettingOld(SpdyKnownSettingsId id, uint32_t value) override { + QUIC_BUG_IF(GetQuicRestartFlag(http2_propagate_unknown_settings)); + if (!GetQuicReloadableFlag(quic_respect_http2_settings_frame)) { + CloseConnection("SPDY SETTINGS frame received.", + QUIC_INVALID_HEADERS_STREAM_DATA); + return; + } + switch (id) { + case SETTINGS_HEADER_TABLE_SIZE: + session_->UpdateHeaderEncoderTableSize(value); + break; + case SETTINGS_ENABLE_PUSH: + if (session_->perspective() == Perspective::IS_SERVER) { + // See rfc7540, Section 6.5.2. + if (value > 1) { + CloseConnection( + QuicStrCat("Invalid value for SETTINGS_ENABLE_PUSH: ", value), + QUIC_INVALID_HEADERS_STREAM_DATA); + return; + } + session_->UpdateEnableServerPush(value > 0); + break; + } else { + CloseConnection( + QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id), + QUIC_INVALID_HEADERS_STREAM_DATA); + } + break; + // TODO(fayang): Need to support SETTINGS_MAX_HEADER_LIST_SIZE when + // clients are actually sending it. + case SETTINGS_MAX_HEADER_LIST_SIZE: + if (GetQuicReloadableFlag(quic_send_max_header_list_size)) { + break; + } + QUIC_FALLTHROUGH_INTENDED; + default: + CloseConnection( + QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id), + QUIC_INVALID_HEADERS_STREAM_DATA); + } + } + + void OnSetting(SpdySettingsId id, uint32_t value) override { + QUIC_BUG_IF(!GetQuicRestartFlag(http2_propagate_unknown_settings)); if (!GetQuicReloadableFlag(quic_respect_http2_settings_frame)) { CloseConnection("SPDY SETTINGS frame received.", QUIC_INVALID_HEADERS_STREAM_DATA); @@ -490,20 +533,6 @@ void QuicSpdySession::OnHeadersHeadOfLineBlocking(QuicTime::Delta delta) { // Implemented in Chromium for stats tracking. } -void QuicSpdySession::RegisterStreamPriority(QuicStreamId id, - SpdyPriority priority) { - write_blocked_streams()->RegisterStream(id, priority); -} - -void QuicSpdySession::UnregisterStreamPriority(QuicStreamId id) { - write_blocked_streams()->UnregisterStream(id); -} - -void QuicSpdySession::UpdateStreamPriority(QuicStreamId id, - SpdyPriority new_priority) { - write_blocked_streams()->UpdateStreamPriority(id, new_priority); -} - QuicSpdyStream* QuicSpdySession::GetSpdyDataStream( const QuicStreamId stream_id) { return static_cast<QuicSpdyStream*>(GetOrCreateDynamicStream(stream_id)); diff --git a/chromium/net/quic/core/quic_spdy_session.h b/chromium/net/quic/core/quic_spdy_session.h index 7268cc2ba70..fd9600a20bc 100644 --- a/chromium/net/quic/core/quic_spdy_session.h +++ b/chromium/net/quic/core/quic_spdy_session.h @@ -120,15 +120,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession : public QuicSession { // |delta| indicates how long that piece of data has been blocked. virtual void OnHeadersHeadOfLineBlocking(QuicTime::Delta delta); - // Called by the stream on creation to set priority in the write blocked list. - virtual void RegisterStreamPriority(QuicStreamId id, SpdyPriority priority); - // Called by the stream on deletion to clear priority crom the write blocked - // list. - virtual void UnregisterStreamPriority(QuicStreamId id); - // Called by the stream on SetPriority to update priority on the write blocked - // list. - virtual void UpdateStreamPriority(QuicStreamId id, SpdyPriority new_priority); - void OnConfigNegotiated() override; bool server_push_enabled() const { return server_push_enabled_; } diff --git a/chromium/net/quic/core/quic_spdy_session_test.cc b/chromium/net/quic/core/quic_spdy_session_test.cc index 8267f8060ab..77b1753ceca 100644 --- a/chromium/net/quic/core/quic_spdy_session_test.cc +++ b/chromium/net/quic/core/quic_spdy_session_test.cc @@ -135,7 +135,7 @@ class TestSession : public QuicSpdySession { Initialize(); this->connection()->SetEncrypter( ENCRYPTION_FORWARD_SECURE, - new NullEncrypter(connection->perspective())); + QuicMakeUnique<NullEncrypter>(connection->perspective())); } ~TestSession() override { delete connection(); } @@ -239,9 +239,9 @@ class TestSession : public QuicSpdySession { bool writev_consumes_all_data_; }; -class QuicSessionTestBase : public QuicTestWithParam<ParsedQuicVersion> { +class QuicSpdySessionTestBase : public QuicTestWithParam<ParsedQuicVersion> { protected: - explicit QuicSessionTestBase(Perspective perspective) + explicit QuicSpdySessionTestBase(Perspective perspective) : connection_( new StrictMock<MockQuicConnection>(&helper_, &alarm_factory_, @@ -296,13 +296,9 @@ class QuicSessionTestBase : public QuicTestWithParam<ParsedQuicVersion> { } void CloseStream(QuicStreamId id) { - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); - EXPECT_CALL(*connection_, OnStreamReset(id, _)); - } else { - EXPECT_CALL(*connection_, SendRstStream(id, _, _)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); + EXPECT_CALL(*connection_, OnStreamReset(id, _)); session_.CloseStream(id); closed_streams_.insert(id); } @@ -329,39 +325,40 @@ class QuicSessionTestBase : public QuicTestWithParam<ParsedQuicVersion> { SpdyHeaderBlock headers_; }; -class QuicSessionTestServer : public QuicSessionTestBase { +class QuicSpdySessionTestServer : public QuicSpdySessionTestBase { protected: - QuicSessionTestServer() : QuicSessionTestBase(Perspective::IS_SERVER) {} + QuicSpdySessionTestServer() + : QuicSpdySessionTestBase(Perspective::IS_SERVER) {} }; INSTANTIATE_TEST_CASE_P(Tests, - QuicSessionTestServer, + QuicSpdySessionTestServer, ::testing::ValuesIn(AllSupportedVersions())); -TEST_P(QuicSessionTestServer, PeerAddress) { +TEST_P(QuicSpdySessionTestServer, PeerAddress) { EXPECT_EQ(QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort), session_.peer_address()); } -TEST_P(QuicSessionTestServer, SelfAddress) { +TEST_P(QuicSpdySessionTestServer, SelfAddress) { EXPECT_EQ(QuicSocketAddress(), session_.self_address()); } -TEST_P(QuicSessionTestServer, IsCryptoHandshakeConfirmed) { +TEST_P(QuicSpdySessionTestServer, IsCryptoHandshakeConfirmed) { EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed()); CryptoHandshakeMessage message; session_.GetMutableCryptoStream()->OnHandshakeMessage(message); EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed()); } -TEST_P(QuicSessionTestServer, IsClosedStreamDefault) { +TEST_P(QuicSpdySessionTestServer, IsClosedStreamDefault) { // Ensure that no streams are initially closed. for (QuicStreamId i = kCryptoStreamId; i < 100; i++) { EXPECT_FALSE(session_.IsClosedStream(i)) << "stream id: " << i; } } -TEST_P(QuicSessionTestServer, AvailableStreams) { +TEST_P(QuicSpdySessionTestServer, AvailableStreams) { ASSERT_TRUE(session_.GetOrCreateDynamicStream(9) != nullptr); // Both 5 and 7 should be available. EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 5)); @@ -370,7 +367,7 @@ TEST_P(QuicSessionTestServer, AvailableStreams) { ASSERT_TRUE(session_.GetOrCreateDynamicStream(5) != nullptr); } -TEST_P(QuicSessionTestServer, IsClosedStreamLocallyCreated) { +TEST_P(QuicSpdySessionTestServer, IsClosedStreamLocallyCreated) { TestStream* stream2 = session_.CreateOutgoingDynamicStream(); EXPECT_EQ(GetNthServerInitiatedId(0), stream2->id()); QuicSpdyStream* stream4 = session_.CreateOutgoingDynamicStream(); @@ -383,7 +380,7 @@ TEST_P(QuicSessionTestServer, IsClosedStreamLocallyCreated) { CheckClosedStreams(); } -TEST_P(QuicSessionTestServer, IsClosedStreamPeerCreated) { +TEST_P(QuicSpdySessionTestServer, IsClosedStreamPeerCreated) { QuicStreamId stream_id1 = GetNthClientInitiatedId(0); QuicStreamId stream_id2 = GetNthClientInitiatedId(1); session_.GetOrCreateDynamicStream(stream_id1); @@ -401,7 +398,7 @@ TEST_P(QuicSessionTestServer, IsClosedStreamPeerCreated) { CheckClosedStreams(); } -TEST_P(QuicSessionTestServer, MaximumAvailableOpenedStreams) { +TEST_P(QuicSpdySessionTestServer, MaximumAvailableOpenedStreams) { QuicStreamId stream_id = GetNthClientInitiatedId(0); session_.GetOrCreateDynamicStream(stream_id); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); @@ -410,7 +407,7 @@ TEST_P(QuicSessionTestServer, MaximumAvailableOpenedStreams) { stream_id + 2 * (session_.max_open_incoming_streams() - 1))); } -TEST_P(QuicSessionTestServer, TooManyAvailableStreams) { +TEST_P(QuicSpdySessionTestServer, TooManyAvailableStreams) { QuicStreamId stream_id1 = GetNthClientInitiatedId(0); QuicStreamId stream_id2; EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id1)); @@ -421,7 +418,7 @@ TEST_P(QuicSessionTestServer, TooManyAvailableStreams) { EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(stream_id2)); } -TEST_P(QuicSessionTestServer, ManyAvailableStreams) { +TEST_P(QuicSpdySessionTestServer, ManyAvailableStreams) { // When max_open_streams_ is 200, should be able to create 200 streams // out-of-order, that is, creating the one with the largest stream ID first. QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); @@ -433,16 +430,13 @@ TEST_P(QuicSessionTestServer, ManyAvailableStreams) { session_.GetOrCreateDynamicStream(stream_id + 2 * (200 - 1)); } -TEST_P(QuicSessionTestServer, DebugDFatalIfMarkingClosedStreamWriteBlocked) { +TEST_P(QuicSpdySessionTestServer, + DebugDFatalIfMarkingClosedStreamWriteBlocked) { TestStream* stream2 = session_.CreateOutgoingDynamicStream(); QuicStreamId closed_stream_id = stream2->id(); // Close the stream. - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(closed_stream_id, _)); - } else { - EXPECT_CALL(*connection_, SendRstStream(closed_stream_id, _, _)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(closed_stream_id, _)); stream2->Reset(QUIC_BAD_APPLICATION_PAYLOAD); QuicString msg = QuicStrCat("Marking unknown stream ", closed_stream_id, " blocked."); @@ -450,7 +444,7 @@ TEST_P(QuicSessionTestServer, DebugDFatalIfMarkingClosedStreamWriteBlocked) { msg); } -TEST_P(QuicSessionTestServer, OnCanWrite) { +TEST_P(QuicSpdySessionTestServer, OnCanWrite) { session_.set_writev_consumes_all_data(true); TestStream* stream2 = session_.CreateOutgoingDynamicStream(); TestStream* stream4 = session_.CreateOutgoingDynamicStream(); @@ -479,7 +473,7 @@ TEST_P(QuicSessionTestServer, OnCanWrite) { EXPECT_TRUE(session_.WillingAndAbleToWrite()); } -TEST_P(QuicSessionTestServer, TestBatchedWrites) { +TEST_P(QuicSpdySessionTestServer, TestBatchedWrites) { session_.set_writev_consumes_all_data(true); TestStream* stream2 = session_.CreateOutgoingDynamicStream(); TestStream* stream4 = session_.CreateOutgoingDynamicStream(); @@ -545,7 +539,7 @@ TEST_P(QuicSessionTestServer, TestBatchedWrites) { session_.OnCanWrite(); } -TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) { +TEST_P(QuicSpdySessionTestServer, OnCanWriteBundlesStreams) { // Encryption needs to be established before data can be sent. CryptoHandshakeMessage msg; MockPacketWriter* writer = static_cast<MockPacketWriter*>( @@ -592,7 +586,7 @@ TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) { EXPECT_FALSE(session_.WillingAndAbleToWrite()); } -TEST_P(QuicSessionTestServer, OnCanWriteCongestionControlBlocks) { +TEST_P(QuicSpdySessionTestServer, OnCanWriteCongestionControlBlocks) { session_.set_writev_consumes_all_data(true); InSequence s; @@ -638,7 +632,7 @@ TEST_P(QuicSessionTestServer, OnCanWriteCongestionControlBlocks) { EXPECT_FALSE(session_.WillingAndAbleToWrite()); } -TEST_P(QuicSessionTestServer, OnCanWriteWriterBlocks) { +TEST_P(QuicSpdySessionTestServer, OnCanWriteWriterBlocks) { // Drive congestion control manually in order to ensure that // application-limited signaling is handled correctly. MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; @@ -664,7 +658,7 @@ TEST_P(QuicSessionTestServer, OnCanWriteWriterBlocks) { EXPECT_TRUE(session_.WillingAndAbleToWrite()); } -TEST_P(QuicSessionTestServer, BufferedHandshake) { +TEST_P(QuicSpdySessionTestServer, BufferedHandshake) { session_.set_writev_consumes_all_data(true); EXPECT_FALSE(session_.HasPendingHandshake()); // Default value. @@ -711,7 +705,7 @@ TEST_P(QuicSessionTestServer, BufferedHandshake) { EXPECT_FALSE(session_.HasPendingHandshake()); // Crypto stream wrote. } -TEST_P(QuicSessionTestServer, OnCanWriteWithClosedStream) { +TEST_P(QuicSpdySessionTestServer, OnCanWriteWithClosedStream) { session_.set_writev_consumes_all_data(true); TestStream* stream2 = session_.CreateOutgoingDynamicStream(); TestStream* stream4 = session_.CreateOutgoingDynamicStream(); @@ -723,10 +717,8 @@ TEST_P(QuicSessionTestServer, OnCanWriteWithClosedStream) { CloseStream(stream6->id()); InSequence s; - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); EXPECT_CALL(*stream2, OnCanWrite()).WillOnce(Invoke([this, stream2]() { session_.SendStreamData(stream2); })); @@ -737,7 +729,8 @@ TEST_P(QuicSessionTestServer, OnCanWriteWithClosedStream) { EXPECT_FALSE(session_.WillingAndAbleToWrite()); } -TEST_P(QuicSessionTestServer, OnCanWriteLimitsNumWritesIfFlowControlBlocked) { +TEST_P(QuicSpdySessionTestServer, + OnCanWriteLimitsNumWritesIfFlowControlBlocked) { // Drive congestion control manually in order to ensure that // application-limited signaling is handled correctly. MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; @@ -753,7 +746,6 @@ TEST_P(QuicSessionTestServer, OnCanWriteLimitsNumWritesIfFlowControlBlocked) { // Mark the crypto and headers streams as write blocked, we expect them to be // allowed to write later. session_.MarkConnectionLevelWriteBlocked(kCryptoStreamId); - session_.MarkConnectionLevelWriteBlocked(kHeadersStreamId); // Create a data stream, and although it is write blocked we never expect it // to be allowed to write as we are connection level flow control blocked. @@ -765,8 +757,10 @@ TEST_P(QuicSessionTestServer, OnCanWriteLimitsNumWritesIfFlowControlBlocked) { // connection flow control blocked. TestCryptoStream* crypto_stream = session_.GetMutableCryptoStream(); EXPECT_CALL(*crypto_stream, OnCanWrite()); + QuicSpdySessionPeer::SetHeadersStream(&session_, nullptr); TestHeadersStream* headers_stream = new TestHeadersStream(&session_); QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream); + session_.MarkConnectionLevelWriteBlocked(kHeadersStreamId); EXPECT_CALL(*headers_stream, OnCanWrite()); // After the crypto and header streams perform a write, the connection will be @@ -777,52 +771,35 @@ TEST_P(QuicSessionTestServer, OnCanWriteLimitsNumWritesIfFlowControlBlocked) { EXPECT_FALSE(session_.WillingAndAbleToWrite()); } -TEST_P(QuicSessionTestServer, SendGoAway) { +TEST_P(QuicSpdySessionTestServer, SendGoAway) { MockPacketWriter* writer = static_cast<MockPacketWriter*>( QuicConnectionPeer::GetWriter(session_.connection())); EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce( - Invoke(connection_, &MockQuicConnection::ReallySendControlFrame)); - } else { - EXPECT_CALL(*connection_, SendGoAway(_, _, _)) - .WillOnce(Invoke(connection_, &MockQuicConnection::ReallySendGoAway)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce( + Invoke(connection_, &MockQuicConnection::ReallySendControlFrame)); session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); EXPECT_TRUE(session_.goaway_sent()); const QuicStreamId kTestStreamId = 5u; - if (session_.use_control_frame_manager()) { EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); EXPECT_CALL(*connection_, OnStreamReset(kTestStreamId, QUIC_STREAM_PEER_GOING_AWAY)) .Times(0); - } else { - EXPECT_CALL(*connection_, - SendRstStream(kTestStreamId, QUIC_STREAM_PEER_GOING_AWAY, 0)) - .Times(0); - } EXPECT_TRUE(session_.GetOrCreateDynamicStream(kTestStreamId)); } -TEST_P(QuicSessionTestServer, DoNotSendGoAwayTwice) { - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); - } else { - EXPECT_CALL(*connection_, SendGoAway(QUIC_PEER_GOING_AWAY, kHeadersStreamId, - "Going Away.")) - .Times(1); - } +TEST_P(QuicSpdySessionTestServer, DoNotSendGoAwayTwice) { + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); EXPECT_TRUE(session_.goaway_sent()); session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); } -TEST_P(QuicSessionTestServer, InvalidGoAway) { +TEST_P(QuicSpdySessionTestServer, InvalidGoAway) { QuicGoAwayFrame go_away(kInvalidControlFrameId, QUIC_PEER_GOING_AWAY, session_.next_outgoing_stream_id(), ""); session_.OnGoAway(go_away); @@ -830,7 +807,7 @@ TEST_P(QuicSessionTestServer, InvalidGoAway) { // Test that server session will send a connectivity probe in response to a // connectivity probe on the same path. -TEST_P(QuicSessionTestServer, ServerReplyToConnecitivityProbe) { +TEST_P(QuicSpdySessionTestServer, ServerReplyToConnecitivityProbe) { QuicSocketAddress old_peer_address = QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort); EXPECT_EQ(old_peer_address, session_.peer_address()); @@ -852,7 +829,7 @@ TEST_P(QuicSessionTestServer, ServerReplyToConnecitivityProbe) { EXPECT_EQ(old_peer_address, session_.peer_address()); } -TEST_P(QuicSessionTestServer, IncreasedTimeoutAfterCryptoHandshake) { +TEST_P(QuicSpdySessionTestServer, IncreasedTimeoutAfterCryptoHandshake) { EXPECT_EQ(kInitialIdleTimeoutSecs + 3, QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); CryptoHandshakeMessage msg; @@ -861,19 +838,15 @@ TEST_P(QuicSessionTestServer, IncreasedTimeoutAfterCryptoHandshake) { QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds()); } -TEST_P(QuicSessionTestServer, RstStreamBeforeHeadersDecompressed) { +TEST_P(QuicSpdySessionTestServer, RstStreamBeforeHeadersDecompressed) { // Send two bytes of payload. QuicStreamFrame data1(GetNthClientInitiatedId(0), false, 0, QuicStringPiece("HT")); session_.OnStreamFrame(data1); EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams()); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(GetNthClientInitiatedId(0), _)); - } else { - EXPECT_CALL(*connection_, SendRstStream(GetNthClientInitiatedId(0), _, _)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(GetNthClientInitiatedId(0), _)); QuicRstStreamFrame rst1(kInvalidControlFrameId, GetNthClientInitiatedId(0), QUIC_ERROR_PROCESSING_STREAM, 0); session_.OnRstStream(rst1); @@ -882,7 +855,7 @@ TEST_P(QuicSessionTestServer, RstStreamBeforeHeadersDecompressed) { EXPECT_TRUE(connection_->connected()); } -TEST_P(QuicSessionTestServer, OnStreamFrameFinStaticStreamId) { +TEST_P(QuicSpdySessionTestServer, OnStreamFrameFinStaticStreamId) { // Send two bytes of payload. QuicStreamFrame data1(kCryptoStreamId, true, 0, QuicStringPiece("HT")); EXPECT_CALL(*connection_, @@ -892,7 +865,7 @@ TEST_P(QuicSessionTestServer, OnStreamFrameFinStaticStreamId) { session_.OnStreamFrame(data1); } -TEST_P(QuicSessionTestServer, OnRstStreamStaticStreamId) { +TEST_P(QuicSpdySessionTestServer, OnRstStreamStaticStreamId) { // Send two bytes of payload. QuicRstStreamFrame rst1(kInvalidControlFrameId, kCryptoStreamId, QUIC_ERROR_PROCESSING_STREAM, 0); @@ -903,7 +876,7 @@ TEST_P(QuicSessionTestServer, OnRstStreamStaticStreamId) { session_.OnRstStream(rst1); } -TEST_P(QuicSessionTestServer, OnStreamFrameInvalidStreamId) { +TEST_P(QuicSpdySessionTestServer, OnStreamFrameInvalidStreamId) { // Send two bytes of payload. QuicStreamFrame data1(kInvalidStreamId, true, 0, QuicStringPiece("HT")); EXPECT_CALL(*connection_, @@ -913,7 +886,7 @@ TEST_P(QuicSessionTestServer, OnStreamFrameInvalidStreamId) { session_.OnStreamFrame(data1); } -TEST_P(QuicSessionTestServer, OnRstStreamInvalidStreamId) { +TEST_P(QuicSpdySessionTestServer, OnRstStreamInvalidStreamId) { // Send two bytes of payload. QuicRstStreamFrame rst1(kInvalidControlFrameId, kInvalidStreamId, QUIC_ERROR_PROCESSING_STREAM, 0); @@ -924,7 +897,7 @@ TEST_P(QuicSessionTestServer, OnRstStreamInvalidStreamId) { session_.OnRstStream(rst1); } -TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedStream) { +TEST_P(QuicSpdySessionTestServer, HandshakeUnblocksFlowControlBlockedStream) { // Test that if a stream is flow control blocked, then on receipt of the SHLO // containing a suitable send window offset, the stream becomes unblocked. @@ -938,40 +911,25 @@ TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedStream) { EXPECT_FALSE(stream2->flow_controller()->IsBlocked()); EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(AtLeast(1)); - } else { - EXPECT_CALL(*connection_, SendBlocked(_)).Times(AtLeast(1)); - EXPECT_CALL(*connection_, SendBlocked(0)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(AtLeast(1)); stream2->WriteOrBufferBody(body, false, nullptr); EXPECT_TRUE(stream2->flow_controller()->IsBlocked()); EXPECT_TRUE(session_.IsConnectionFlowControlBlocked()); EXPECT_TRUE(session_.IsStreamFlowControlBlocked()); - if (!session_.session_unblocks_stream()) { - // The handshake message will call OnCanWrite, so the stream can resume - // writing. - EXPECT_CALL(*stream2, OnCanWrite()); - } // Now complete the crypto handshake, resulting in an increased flow control // send window. CryptoHandshakeMessage msg; session_.GetMutableCryptoStream()->OnHandshakeMessage(msg); - if (session_.session_unblocks_stream()) { - EXPECT_TRUE( - QuicSessionPeer::IsStreamWriteBlocked(&session_, stream2->id())); - } else { - EXPECT_FALSE( - QuicSessionPeer::IsStreamWriteBlocked(&session_, stream2->id())); - } + EXPECT_TRUE(QuicSessionPeer::IsStreamWriteBlocked(&session_, stream2->id())); // Stream is now unblocked. EXPECT_FALSE(stream2->flow_controller()->IsBlocked()); EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); } -TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) { +TEST_P(QuicSpdySessionTestServer, + HandshakeUnblocksFlowControlBlockedCryptoStream) { // Test that if the crypto stream is flow control blocked, then if the SHLO // contains a larger send window offset, the stream becomes unblocked. session_.set_writev_consumes_all_data(true); @@ -984,13 +942,8 @@ TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) { EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); - } else { - // Write until the crypto stream is flow control blocked. - EXPECT_CALL(*connection_, SendBlocked(kCryptoStreamId)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); for (QuicStreamId i = 0; !crypto_stream->flow_controller()->IsBlocked() && i < 1000u; i++) { EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); @@ -1011,22 +964,12 @@ TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) { EXPECT_FALSE(session_.HasDataToWrite()); EXPECT_TRUE(crypto_stream->HasBufferedData()); - if (!session_.session_unblocks_stream()) { - // The handshake message will call OnCanWrite, so the stream can - // resume writing. - EXPECT_CALL(*crypto_stream, OnCanWrite()); - } // Now complete the crypto handshake, resulting in an increased flow control // send window. CryptoHandshakeMessage msg; session_.GetMutableCryptoStream()->OnHandshakeMessage(msg); - if (session_.session_unblocks_stream()) { - EXPECT_TRUE( - QuicSessionPeer::IsStreamWriteBlocked(&session_, kCryptoStreamId)); - } else { - EXPECT_FALSE( - QuicSessionPeer::IsStreamWriteBlocked(&session_, kCryptoStreamId)); - } + EXPECT_TRUE( + QuicSessionPeer::IsStreamWriteBlocked(&session_, kCryptoStreamId)); // Stream is now unblocked and will no longer have buffered data. EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked()); EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); @@ -1039,7 +982,7 @@ TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) { // NOTE: It's not possible to use the standard MAYBE_ convention to disable // this test on iOS because when this test gets instantiated it ends up with // various names that are dependent on the parameters passed. -TEST_P(QuicSessionTestServer, +TEST_P(QuicSpdySessionTestServer, HandshakeUnblocksFlowControlBlockedHeadersStream) { // Test that if the header stream is flow control blocked, then if the SHLO // contains a larger send window offset, the stream becomes unblocked. @@ -1055,12 +998,8 @@ TEST_P(QuicSessionTestServer, EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); QuicStreamId stream_id = 5; // Write until the header stream is flow control blocked. - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); - } else { - EXPECT_CALL(*connection_, SendBlocked(kHeadersStreamId)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); SpdyHeaderBlock headers; while (!headers_stream->flow_controller()->IsBlocked() && stream_id < 2000) { EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); @@ -1090,19 +1029,14 @@ TEST_P(QuicSessionTestServer, EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); - if (session_.session_unblocks_stream()) { - EXPECT_TRUE(headers_stream->HasBufferedData()); - EXPECT_TRUE( - QuicSessionPeer::IsStreamWriteBlocked(&session_, kHeadersStreamId)); - } else { - EXPECT_FALSE(headers_stream->HasBufferedData()); - EXPECT_FALSE( - QuicSessionPeer::IsStreamWriteBlocked(&session_, kHeadersStreamId)); - } + EXPECT_TRUE(headers_stream->HasBufferedData()); + EXPECT_TRUE( + QuicSessionPeer::IsStreamWriteBlocked(&session_, kHeadersStreamId)); } #endif // !defined(OS_IOS) -TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstOutOfOrder) { +TEST_P(QuicSpdySessionTestServer, + ConnectionFlowControlAccountingRstOutOfOrder) { // Test that when we receive an out of order stream RST we correctly adjust // our connection level flow control receive window. // On close, the stream should mark as consumed all bytes between the highest @@ -1112,21 +1046,10 @@ TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstOutOfOrder) { const QuicStreamOffset kByteOffset = 1 + kInitialSessionFlowControlWindowForTest / 2; - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(2) - .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); - EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); - } else { - // Expect no stream WINDOW_UPDATE frames, as stream read side closed. - EXPECT_CALL(*connection_, SendWindowUpdate(stream->id(), _)).Times(0); - // We do expect a connection level WINDOW_UPDATE when the stream is reset. - EXPECT_CALL(*connection_, - SendWindowUpdate( - 0, kInitialSessionFlowControlWindowForTest + kByteOffset)); - - EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(2) + .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream->id(), QUIC_STREAM_CANCELLED, kByteOffset); session_.OnRstStream(rst_frame); @@ -1134,7 +1057,8 @@ TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstOutOfOrder) { EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed()); } -TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAndLocalReset) { +TEST_P(QuicSpdySessionTestServer, + ConnectionFlowControlAccountingFinAndLocalReset) { // Test the situation where we receive a FIN on a stream, and before we fully // consume all the data from the sequencer buffer we locally RST the stream. // The bytes between highest consumed byte, and the final byte offset that we @@ -1154,18 +1078,14 @@ TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAndLocalReset) { stream->flow_controller()->highest_received_byte_offset()); // Reset stream locally. - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); - } else { - EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); stream->Reset(QUIC_STREAM_CANCELLED); EXPECT_EQ(kByteOffset + frame.data_length, session_.flow_controller()->bytes_consumed()); } -TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAfterRst) { +TEST_P(QuicSpdySessionTestServer, ConnectionFlowControlAccountingFinAfterRst) { // Test that when we RST the stream (and tear down stream state), and then // receive a FIN from the peer, we correctly adjust our connection level flow // control receive window. @@ -1182,12 +1102,8 @@ TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAfterRst) { // Reset our stream: this results in the stream being closed locally. TestStream* stream = session_.CreateOutgoingDynamicStream(); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); - } else { - EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); stream->Reset(QUIC_STREAM_CANCELLED); // Now receive a response from the peer with a FIN. We should handle this by @@ -1207,7 +1123,7 @@ TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAfterRst) { session_.flow_controller()->highest_received_byte_offset()); } -TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstAfterRst) { +TEST_P(QuicSpdySessionTestServer, ConnectionFlowControlAccountingRstAfterRst) { // Test that when we RST the stream (and tear down stream state), and then // receive a RST from the peer, we correctly adjust our connection level flow // control receive window. @@ -1224,12 +1140,8 @@ TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstAfterRst) { // Reset our stream: this results in the stream being closed locally. TestStream* stream = session_.CreateOutgoingDynamicStream(); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); - } else { - EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); stream->Reset(QUIC_STREAM_CANCELLED); EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream)); @@ -1247,7 +1159,7 @@ TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstAfterRst) { session_.flow_controller()->highest_received_byte_offset()); } -TEST_P(QuicSessionTestServer, InvalidStreamFlowControlWindowInHandshake) { +TEST_P(QuicSpdySessionTestServer, InvalidStreamFlowControlWindowInHandshake) { // Test that receipt of an invalid (< default) stream flow control window from // the peer results in the connection being torn down. const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1; @@ -1259,7 +1171,7 @@ TEST_P(QuicSessionTestServer, InvalidStreamFlowControlWindowInHandshake) { session_.OnConfigNegotiated(); } -TEST_P(QuicSessionTestServer, InvalidSessionFlowControlWindowInHandshake) { +TEST_P(QuicSpdySessionTestServer, InvalidSessionFlowControlWindowInHandshake) { // Test that receipt of an invalid (< default) session flow control window // from the peer results in the connection being torn down. const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1; @@ -1272,7 +1184,7 @@ TEST_P(QuicSessionTestServer, InvalidSessionFlowControlWindowInHandshake) { } // Test negotiation of custom server initial flow control window. -TEST_P(QuicSessionTestServer, CustomFlowControlWindow) { +TEST_P(QuicSpdySessionTestServer, CustomFlowControlWindow) { QuicTagVector copt; copt.push_back(kIFW7); QuicConfigPeer::SetReceivedConnectionOptions(session_.config(), copt); @@ -1282,7 +1194,7 @@ TEST_P(QuicSessionTestServer, CustomFlowControlWindow) { session_.flow_controller())); } -TEST_P(QuicSessionTestServer, FlowControlWithInvalidFinalOffset) { +TEST_P(QuicSpdySessionTestServer, FlowControlWithInvalidFinalOffset) { // Test that if we receive a stream RST with a highest byte offset that // violates flow control, that we close the connection. const uint64_t kLargeOffset = kInitialSessionFlowControlWindowForTest + 1; @@ -1292,12 +1204,8 @@ TEST_P(QuicSessionTestServer, FlowControlWithInvalidFinalOffset) { // Check that stream frame + FIN results in connection close. TestStream* stream = session_.CreateOutgoingDynamicStream(); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); - } else { - EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); stream->Reset(QUIC_STREAM_CANCELLED); QuicStreamFrame frame(stream->id(), true, kLargeOffset, QuicStringPiece()); session_.OnStreamFrame(frame); @@ -1308,7 +1216,7 @@ TEST_P(QuicSessionTestServer, FlowControlWithInvalidFinalOffset) { session_.OnRstStream(rst_frame); } -TEST_P(QuicSessionTestServer, WindowUpdateUnblocksHeadersStream) { +TEST_P(QuicSpdySessionTestServer, WindowUpdateUnblocksHeadersStream) { // Test that a flow control blocked headers stream gets unblocked on recipt of // a WINDOW_UPDATE frame. @@ -1331,7 +1239,8 @@ TEST_P(QuicSessionTestServer, WindowUpdateUnblocksHeadersStream) { EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); } -TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseServerRejectStream) { +TEST_P(QuicSpdySessionTestServer, + TooManyUnfinishedStreamsCauseServerRejectStream) { // If a buggy/malicious peer creates too many streams that are not ended // with a FIN or RST then we send an RST to refuse streams. const QuicStreamId kMaxStreams = 5; @@ -1345,26 +1254,15 @@ TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseServerRejectStream) { QuicStreamFrame data1(i, false, 0, QuicStringPiece("HT")); session_.OnStreamFrame(data1); // EXPECT_EQ(1u, session_.GetNumOpenStreams()); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); - EXPECT_CALL(*connection_, OnStreamReset(i, _)); - } else { - EXPECT_CALL(*connection_, SendRstStream(i, _, _)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); + EXPECT_CALL(*connection_, OnStreamReset(i, _)); session_.CloseStream(i); } - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); - EXPECT_CALL(*connection_, - OnStreamReset(kFinalStreamId, QUIC_REFUSED_STREAM)) - .Times(1); - } else { - EXPECT_CALL(*connection_, - SendRstStream(kFinalStreamId, QUIC_REFUSED_STREAM, _)) - .Times(1); - } + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); + EXPECT_CALL(*connection_, OnStreamReset(kFinalStreamId, QUIC_REFUSED_STREAM)) + .Times(1); // Create one more data streams to exceed limit of open stream. QuicStreamFrame data1(kFinalStreamId, false, 0, QuicStringPiece("HT")); session_.OnStreamFrame(data1); @@ -1374,17 +1272,12 @@ TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseServerRejectStream) { session_.PostProcessAfterData(); } -TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) { +TEST_P(QuicSpdySessionTestServer, DrainingStreamsDoNotCountAsOpened) { // Verify that a draining stream (which has received a FIN but not consumed // it) does not count against the open quota (because it is closed from the // protocol point of view). - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); - EXPECT_CALL(*connection_, OnStreamReset(_, QUIC_REFUSED_STREAM)).Times(0); - } else { - EXPECT_CALL(*connection_, SendRstStream(_, QUIC_REFUSED_STREAM, _)) - .Times(0); - } + EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); + EXPECT_CALL(*connection_, OnStreamReset(_, QUIC_REFUSED_STREAM)).Times(0); const QuicStreamId kMaxStreams = 5; QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); @@ -1405,7 +1298,7 @@ TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) { session_.PostProcessAfterData(); } -TEST_P(QuicSessionTestServer, TestMaxIncomingAndOutgoingStreamsAllowed) { +TEST_P(QuicSpdySessionTestServer, TestMaxIncomingAndOutgoingStreamsAllowed) { // Tests that on server side, the value of max_open_incoming/outgoing streams // are setup correctly during negotiation. // The value for outgoing stream is limited to negotiated value and for @@ -1421,16 +1314,17 @@ TEST_P(QuicSessionTestServer, TestMaxIncomingAndOutgoingStreamsAllowed) { kDefaultMaxStreamsPerConnection); } -class QuicSessionTestClient : public QuicSessionTestBase { +class QuicSpdySessionTestClient : public QuicSpdySessionTestBase { protected: - QuicSessionTestClient() : QuicSessionTestBase(Perspective::IS_CLIENT) {} + QuicSpdySessionTestClient() + : QuicSpdySessionTestBase(Perspective::IS_CLIENT) {} }; INSTANTIATE_TEST_CASE_P(Tests, - QuicSessionTestClient, + QuicSpdySessionTestClient, ::testing::ValuesIn(AllSupportedVersions())); -TEST_P(QuicSessionTestClient, AvailableStreamsClient) { +TEST_P(QuicSpdySessionTestClient, AvailableStreamsClient) { ASSERT_TRUE(session_.GetOrCreateDynamicStream(6) != nullptr); // Both 2 and 4 should be available. EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 2)); @@ -1441,7 +1335,7 @@ TEST_P(QuicSessionTestClient, AvailableStreamsClient) { EXPECT_FALSE(QuicSessionPeer::IsStreamAvailable(&session_, 5)); } -TEST_P(QuicSessionTestClient, RecordFinAfterReadSideClosed) { +TEST_P(QuicSpdySessionTestClient, RecordFinAfterReadSideClosed) { // Verify that an incoming FIN is recorded in a stream object even if the read // side has been closed. This prevents an entry from being made in // locally_closed_streams_highest_offset_ (which will never be deleted). @@ -1457,12 +1351,8 @@ TEST_P(QuicSessionTestClient, RecordFinAfterReadSideClosed) { EXPECT_TRUE(stream->fin_received()); // Reset stream locally. - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); - } else { - EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); stream->Reset(QUIC_STREAM_CANCELLED); EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream)); @@ -1479,7 +1369,7 @@ TEST_P(QuicSessionTestClient, RecordFinAfterReadSideClosed) { QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(&session_).size()); } -TEST_P(QuicSessionTestClient, TestMaxIncomingAndOutgoingStreamsAllowed) { +TEST_P(QuicSpdySessionTestClient, TestMaxIncomingAndOutgoingStreamsAllowed) { // Tests that on client side, the value of max_open_incoming/outgoing streams // are setup correctly during negotiation. // When flag is true, the value for outgoing stream is limited to negotiated @@ -1491,7 +1381,7 @@ TEST_P(QuicSessionTestClient, TestMaxIncomingAndOutgoingStreamsAllowed) { kDefaultMaxStreamsPerConnection); } -TEST_P(QuicSessionTestClient, EnableDHDTThroughConnectionOption) { +TEST_P(QuicSpdySessionTestClient, EnableDHDTThroughConnectionOption) { QuicTagVector copt; copt.push_back(kDHDT); QuicConfigPeer::SetConnectionOptionsToSend(session_.config(), copt); @@ -1501,7 +1391,8 @@ TEST_P(QuicSessionTestClient, EnableDHDTThroughConnectionOption) { 0UL); } -TEST_P(QuicSessionTestClient, WritePriority) { +TEST_P(QuicSpdySessionTestClient, WritePriority) { + QuicSpdySessionPeer::SetHeadersStream(&session_, nullptr); TestHeadersStream* headers_stream = new TestHeadersStream(&session_); QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream); @@ -1536,27 +1427,29 @@ TEST_P(QuicSessionTestClient, WritePriority) { } } -TEST_P(QuicSessionTestServer, ZombieStreams) { +TEST_P(QuicSpdySessionTestServer, ZombieStreams) { TestStream* stream2 = session_.CreateOutgoingDynamicStream(); QuicStreamPeer::SetStreamBytesWritten(3, stream2); EXPECT_TRUE(stream2->IsWaitingForAcks()); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(2, _)); + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(2, _)); + session_.CloseStream(2); + if (GetQuicReloadableFlag(quic_reset_stream_is_not_zombie)) { + EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), 2)); + ASSERT_EQ(1u, session_.closed_streams()->size()); + EXPECT_EQ(2u, session_.closed_streams()->front()->id()); } else { - EXPECT_CALL(*connection_, SendRstStream(2, _, _)); + EXPECT_TRUE(QuicContainsKey(session_.zombie_streams(), 2)); + EXPECT_TRUE(session_.closed_streams()->empty()); } - session_.CloseStream(2); - EXPECT_TRUE(QuicContainsKey(session_.zombie_streams(), 2)); - EXPECT_TRUE(session_.closed_streams()->empty()); session_.OnStreamDoneWaitingForAcks(2); EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), 2)); EXPECT_EQ(1u, session_.closed_streams()->size()); EXPECT_EQ(2u, session_.closed_streams()->front()->id()); } -TEST_P(QuicSessionTestServer, OnStreamFrameLost) { +TEST_P(QuicSpdySessionTestServer, OnStreamFrameLost) { QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); InSequence s; @@ -1619,7 +1512,7 @@ TEST_P(QuicSessionTestServer, OnStreamFrameLost) { EXPECT_FALSE(session_.WillingAndAbleToWrite()); } -TEST_P(QuicSessionTestServer, DonotRetransmitDataOfClosedStreams) { +TEST_P(QuicSpdySessionTestServer, DonotRetransmitDataOfClosedStreams) { QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); InSequence s; @@ -1643,12 +1536,8 @@ TEST_P(QuicSessionTestServer, DonotRetransmitDataOfClosedStreams) { session_.MarkConnectionLevelWriteBlocked(stream6->id()); // Reset stream 4 locally. - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(stream4->id(), _)); - } else { - EXPECT_CALL(*connection_, SendRstStream(stream4->id(), _, _)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream4->id(), _)); stream4->Reset(QUIC_STREAM_CANCELLED); // Verify stream 4 is removed from streams with lost data list. @@ -1656,16 +1545,14 @@ TEST_P(QuicSessionTestServer, DonotRetransmitDataOfClosedStreams) { EXPECT_CALL(*stream6, HasPendingRetransmission()).WillOnce(Return(false)); EXPECT_CALL(*stream2, OnCanWrite()); EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(false)); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); EXPECT_CALL(*stream2, OnCanWrite()); EXPECT_CALL(*stream6, OnCanWrite()); session_.OnCanWrite(); } -TEST_P(QuicSessionTestServer, RetransmitFrames) { +TEST_P(QuicSpdySessionTestServer, RetransmitFrames) { QuicConnectionPeer::SetSessionDecidesWhatToWrite(connection_); MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>; QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm); @@ -1674,11 +1561,9 @@ TEST_P(QuicSessionTestServer, RetransmitFrames) { TestStream* stream2 = session_.CreateOutgoingDynamicStream(); TestStream* stream4 = session_.CreateOutgoingDynamicStream(); TestStream* stream6 = session_.CreateOutgoingDynamicStream(); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); - session_.SendWindowUpdate(stream2->id(), 9); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); + session_.SendWindowUpdate(stream2->id(), 9); QuicStreamFrame frame1(stream2->id(), false, 0, 9); QuicStreamFrame frame2(stream4->id(), false, 0, 9); @@ -1692,17 +1577,15 @@ TEST_P(QuicSessionTestServer, RetransmitFrames) { EXPECT_FALSE(session_.WillingAndAbleToWrite()); EXPECT_CALL(*stream2, RetransmitStreamData(_, _, _)).WillOnce(Return(true)); - if (session_.use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); EXPECT_CALL(*stream4, RetransmitStreamData(_, _, _)).WillOnce(Return(true)); EXPECT_CALL(*stream6, RetransmitStreamData(_, _, _)).WillOnce(Return(true)); EXPECT_CALL(*send_algorithm, OnApplicationLimited(_)); session_.RetransmitFrames(frames, TLP_RETRANSMISSION); } -TEST_P(QuicSessionTestServer, OnPriorityFrame) { +TEST_P(QuicSpdySessionTestServer, OnPriorityFrame) { QuicStreamId stream_id = GetNthClientInitiatedId(0); TestStream* stream = session_.CreateIncomingDynamicStream(stream_id); session_.OnPriorityFrame(stream_id, kV3HighestPriority); diff --git a/chromium/net/quic/core/quic_spdy_stream.cc b/chromium/net/quic/core/quic_spdy_stream.cc index 016587ca85c..48c17cdd8d5 100644 --- a/chromium/net/quic/core/quic_spdy_stream.cc +++ b/chromium/net/quic/core/quic_spdy_stream.cc @@ -26,23 +26,25 @@ namespace net { " ") QuicSpdyStream::QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session) - : QuicStream(id, spdy_session), + : QuicStream(id, spdy_session, /*is_static=*/false), spdy_session_(spdy_session), visitor_(nullptr), headers_decompressed_(false), - priority_(kDefaultPriority), trailers_decompressed_(false), trailers_consumed_(false) { DCHECK_NE(kCryptoStreamId, id); // Don't receive any callbacks from the sequencer until headers // are complete. sequencer()->SetBlockedUntilFlush(); - spdy_session_->RegisterStreamPriority(id, priority_); + if (!session()->register_streams_early()) { + spdy_session_->RegisterStreamPriority(id, /*is_static=*/false, priority()); + } } QuicSpdyStream::~QuicSpdyStream() { - if (spdy_session_ != nullptr) { - spdy_session_->UnregisterStreamPriority(id()); + if (spdy_session_ != nullptr && !session()->register_streams_early()) { + spdy_session_->UnregisterStreamPriority(id(), + /*is_static=*/false); } } @@ -51,7 +53,7 @@ size_t QuicSpdyStream::WriteHeaders( bool fin, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { size_t bytes_written = spdy_session_->WriteHeaders( - id(), std::move(header_block), fin, priority_, std::move(ack_listener)); + id(), std::move(header_block), fin, priority(), std::move(ack_listener)); if (fin) { // TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent. set_fin_sent(true); @@ -87,8 +89,9 @@ size_t QuicSpdyStream::WriteTrailers( // Write the trailing headers with a FIN, and close stream for writing: // trailers are the last thing to be sent on a stream. const bool kFin = true; - size_t bytes_written = spdy_session_->WriteHeaders( - id(), std::move(trailer_block), kFin, priority_, std::move(ack_listener)); + size_t bytes_written = + spdy_session_->WriteHeaders(id(), std::move(trailer_block), kFin, + priority(), std::move(ack_listener)); set_fin_sent(kFin); // Trailers are the last thing to be sent on a stream, but if there is still @@ -137,12 +140,6 @@ void QuicSpdyStream::ConsumeHeaderList() { } } -void QuicSpdyStream::SetPriority(SpdyPriority priority) { - DCHECK_EQ(0u, stream_bytes_written()); - priority_ = priority; - spdy_session_->UpdateStreamPriority(id(), priority); -} - void QuicSpdyStream::OnStreamHeadersPriority(SpdyPriority priority) { DCHECK_EQ(Perspective::IS_SERVER, session()->connection()->perspective()); SetPriority(priority); @@ -308,10 +305,6 @@ bool QuicSpdyStream::FinishedReadingTrailers() const { } } -SpdyPriority QuicSpdyStream::priority() const { - return priority_; -} - void QuicSpdyStream::ClearSession() { spdy_session_ = nullptr; } diff --git a/chromium/net/quic/core/quic_spdy_stream.h b/chromium/net/quic/core/quic_spdy_stream.h index 48e92200021..947b323bf5c 100644 --- a/chromium/net/quic/core/quic_spdy_stream.h +++ b/chromium/net/quic/core/quic_spdy_stream.h @@ -35,12 +35,6 @@ class QuicStreamPeer; class QuicSpdySession; -// This is somewhat arbitrary. It's possible, but unlikely, we will either fail -// to set a priority client-side, or cancel a stream before stripping the -// priority from the wire server-side. In either case, start out with a -// priority in the middle. -const SpdyPriority kDefaultPriority = 3; - // A QUIC stream that can send and receive HTTP2 (SPDY) headers. class QUIC_EXPORT_PRIVATE QuicSpdyStream : public QuicStream { public: @@ -164,12 +158,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream : public QuicStream { // been received and there are no trailers. bool FinishedReadingTrailers() const; - SpdyPriority priority() const; - - // Sets priority_ to priority. This should only be called before bytes are - // written to the server. - void SetPriority(SpdyPriority priority); - // Called when owning session is getting deleted to avoid subsequent // use of the spdy_session_ member. void ClearSession(); @@ -202,8 +190,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream : public QuicStream { Visitor* visitor_; // True if the headers have been completely decompressed. bool headers_decompressed_; - // The priority of the stream, once parsed. - SpdyPriority priority_; // Contains a copy of the decompressed header (name, value) pairs until they // are consumed via Readv. QuicHeaderList header_list_; diff --git a/chromium/net/quic/core/quic_spdy_stream_test.cc b/chromium/net/quic/core/quic_spdy_stream_test.cc index 1b524942177..10b596c3880 100644 --- a/chromium/net/quic/core/quic_spdy_stream_test.cc +++ b/chromium/net/quic/core/quic_spdy_stream_test.cc @@ -126,6 +126,7 @@ class QuicSpdyStreamTest : public QuicTestWithParam<ParsedQuicVersion> { SupportedVersions(GetParam())); session_ = QuicMakeUnique<testing::StrictMock<MockQuicSpdySession>>(connection_); + session_->Initialize(); stream_ = new TestStream(GetNthClientInitiatedId(0), session_.get(), stream_should_process_data); session_->ActivateStream(QuicWrapUnique(stream_)); @@ -436,11 +437,7 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlBlocked) { const uint64_t kOverflow = 15; QuicString body(kWindow + kOverflow, 'a'); - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - } else { - EXPECT_CALL(*connection_, SendBlocked(GetNthClientInitiatedId(0))); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillOnce(Return(QuicConsumedData(kWindow, true))); stream_->WriteOrBufferData(body, false, nullptr); @@ -527,15 +524,7 @@ TEST_P(QuicSpdyStreamTest, StreamFlowControlWindowUpdate) { // window of kWindow bytes. QuicStreamFrame frame2(GetNthClientInitiatedId(0), false, kWindow / 3, QuicStringPiece(body)); - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - } else { - EXPECT_CALL(*connection_, - SendWindowUpdate(GetNthClientInitiatedId(0), - QuicFlowControllerPeer::ReceiveWindowOffset( - stream_->flow_controller()) + - 2 * kWindow / 3)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); stream_->OnStreamFrame(frame2); EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowSize( stream_->flow_controller())); @@ -584,18 +573,7 @@ TEST_P(QuicSpdyStreamTest, ConnectionFlowControlWindowUpdate) { // Now receive a further single byte on one stream - again this does not // trigger a stream WINDOW_UPDATE, but now the connection flow control window // is over half full and thus a connection WINDOW_UPDATE is sent. - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)); - } else { - EXPECT_CALL(*connection_, SendWindowUpdate(GetNthClientInitiatedId(0), _)) - .Times(0); - EXPECT_CALL(*connection_, SendWindowUpdate(GetNthClientInitiatedId(1), _)) - .Times(0); - EXPECT_CALL(*connection_, - SendWindowUpdate(0, QuicFlowControllerPeer::ReceiveWindowOffset( - session_->flow_controller()) + - 1 + kWindow / 2)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)); QuicStreamFrame frame3(GetNthClientInitiatedId(0), false, (kWindow / 4), QuicStringPiece("a")); stream_->OnStreamFrame(frame3); diff --git a/chromium/net/quic/core/quic_stream.cc b/chromium/net/quic/core/quic_stream.cc index 2ca58558bef..72e15671f23 100644 --- a/chromium/net/quic/core/quic_stream.cc +++ b/chromium/net/quic/core/quic_stream.cc @@ -13,6 +13,8 @@ #include "net/quic/platform/api/quic_str_cat.h" #include "net/quic/platform/api/quic_string.h" +using net::SpdyPriority; + namespace net { #define ENDPOINT \ @@ -40,10 +42,14 @@ size_t GetReceivedFlowControlWindow(QuicSession* session) { } // namespace -QuicStream::QuicStream(QuicStreamId id, QuicSession* session) +// static +const SpdyPriority QuicStream::kDefaultPriority; + +QuicStream::QuicStream(QuicStreamId id, QuicSession* session, bool is_static) : sequencer_(this, session->connection()->clock()), id_(id), session_(session), + priority_(kDefaultPriority), stream_bytes_read_(0), stream_error_(QUIC_STREAM_NO_ERROR), connection_error_(QUIC_NO_ERROR), @@ -72,9 +78,12 @@ QuicStream::QuicStream(QuicStreamId id, QuicSession* session) ack_listener_(nullptr), send_buffer_( session->connection()->helper()->GetStreamSendBufferAllocator()), - buffered_data_threshold_( - GetQuicFlag(FLAGS_quic_buffered_data_threshold)) { + buffered_data_threshold_(GetQuicFlag(FLAGS_quic_buffered_data_threshold)), + is_static_(is_static) { SetFromConfig(); + if (session_->register_streams_early()) { + session_->RegisterStreamPriority(id, is_static_, priority_); + } } QuicStream::~QuicStream() { @@ -85,6 +94,9 @@ QuicStream::~QuicStream() { << send_buffer_.stream_bytes_outstanding() << ", fin_outstanding: " << fin_outstanding_; } + if (session_ != nullptr && session_->register_streams_early()) { + session_->UnregisterStreamPriority(id(), is_static_); + } } void QuicStream::SetFromConfig() {} @@ -215,6 +227,16 @@ void QuicStream::CloseConnectionWithDetails(QuicErrorCode error, error, details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); } +SpdyPriority QuicStream::priority() const { + return priority_; +} + +void QuicStream::SetPriority(SpdyPriority priority) { + DCHECK_EQ(0u, stream_bytes_written()); + priority_ = priority; + session_->UpdateStreamPriority(id(), priority); +} + void QuicStream::WriteOrBufferData( QuicStringPiece data, bool fin, @@ -263,24 +285,7 @@ void QuicStream::WriteOrBufferData( void QuicStream::OnCanWrite() { if (HasPendingRetransmission()) { - const bool session_unblocks_stream = session_->session_unblocks_stream(); WritePendingRetransmission(); - if (session_unblocks_stream) { - // Exit early to allow other streams to write pending retransmissions if - // any. - return; - } - if (HasPendingRetransmission()) { - // Stream did not finish retransmission, session will unblock this stream - // later. - return; - } - const bool fin_only = !HasBufferedData() && fin_buffered_ && !fin_sent_; - if ((!flow_controller_.IsBlocked() && HasBufferedData()) || fin_only) { - // Stream finished retransmission. If there is new data which can be sent, - // tell the session to unblock this stream later. - session_->MarkConnectionLevelWriteBlocked(id_); - } // Exit early to allow other streams to write pending retransmissions if // any. return; @@ -374,7 +379,6 @@ QuicConsumedData QuicStream::WritevData(const struct iovec* iov, } QuicConsumedData QuicStream::WriteMemSlices(QuicMemSliceSpan span, bool fin) { - DCHECK(session_->can_use_slices()); QuicConsumedData consumed_data(0, false); if (span.empty() && !fin) { QUIC_BUG << "span.empty() && !fin"; @@ -448,13 +452,13 @@ void QuicStream::CloseReadSide() { if (read_side_closed_) { return; } - QUIC_DLOG(INFO) << ENDPOINT << "Done reading from stream " << id(); + QUIC_DVLOG(1) << ENDPOINT << "Done reading from stream " << id(); read_side_closed_ = true; sequencer_.ReleaseBuffer(); if (write_side_closed_) { - QUIC_DLOG(INFO) << ENDPOINT << "Closing stream " << id(); + QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << id(); session_->CloseStream(id()); } } @@ -463,11 +467,11 @@ void QuicStream::CloseWriteSide() { if (write_side_closed_) { return; } - QUIC_DLOG(INFO) << ENDPOINT << "Done writing to stream " << id(); + QUIC_DVLOG(1) << ENDPOINT << "Done writing to stream " << id(); write_side_closed_ = true; if (read_side_closed_) { - QUIC_DLOG(INFO) << ENDPOINT << "Closing stream " << id(); + QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << id(); session_->CloseStream(id()); } } @@ -486,7 +490,7 @@ HandshakeProtocol QuicStream::handshake_protocol() const { } void QuicStream::StopReading() { - QUIC_DLOG(INFO) << ENDPOINT << "Stop reading from stream " << id(); + QUIC_DVLOG(1) << ENDPOINT << "Stop reading from stream " << id(); sequencer_.StopReading(); } @@ -503,6 +507,10 @@ void QuicStream::OnClose() { // written on this stream before termination. Done here if needed, using a // RST_STREAM frame. QUIC_DLOG(INFO) << ENDPOINT << "Sending RST_STREAM in OnClose: " << id(); + if (GetQuicReloadableFlag(quic_reset_stream_is_not_zombie)) { + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_reset_stream_is_not_zombie); + session_->OnStreamDoneWaitingForAcks(id_); + } session_->SendRstStream(id(), QUIC_RST_ACKNOWLEDGEMENT, stream_bytes_written()); rst_sent_ = true; @@ -524,18 +532,8 @@ void QuicStream::OnClose() { void QuicStream::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) { if (flow_controller_.UpdateSendWindowOffset(frame.byte_offset)) { - if (session_->session_unblocks_stream()) { - QUIC_FLAG_COUNT(quic_reloadable_flag_quic_streams_unblocked_by_session2); - // Let session unblock this stream. - session_->MarkConnectionLevelWriteBlocked(id_); - } else { - // Writing can be done again! - // TODO(rjshade): This does not respect priorities (e.g. multiple - // outstanding POSTs are unblocked on arrival of - // SHLO with initial window). - // As long as the connection is not flow control blocked, write on! - OnCanWrite(); - } + // Let session unblock this stream. + session_->MarkConnectionLevelWriteBlocked(id_); } } @@ -578,12 +576,8 @@ void QuicStream::AddBytesConsumed(QuicByteCount bytes) { void QuicStream::UpdateSendWindowOffset(QuicStreamOffset new_window) { if (flow_controller_.UpdateSendWindowOffset(new_window)) { - if (session_->session_unblocks_stream()) { - // Let session unblock this stream. - session_->MarkConnectionLevelWriteBlocked(id_); - } else { - OnCanWrite(); - } + // Let session unblock this stream. + session_->MarkConnectionLevelWriteBlocked(id_); } } @@ -601,13 +595,13 @@ bool QuicStream::OnStreamFrameAcked(QuicStreamOffset offset, QuicByteCount newly_acked_length = 0; if (!send_buffer_.OnStreamDataAcked(offset, data_length, &newly_acked_length)) { - RecordInternalErrorLocation(QUIC_STREAM_1); + RecordInternalErrorLocation(QUIC_STREAM_ACKED_UNSENT_DATA); CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, "Trying to ack unsent data."); return false; } if (!fin_sent_ && fin_acked) { - RecordInternalErrorLocation(QUIC_STREAM_2); + RecordInternalErrorLocation(QUIC_STREAM_ACKED_UNSENT_FIN); CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, "Trying to ack unsent fin."); return false; diff --git a/chromium/net/quic/core/quic_stream.h b/chromium/net/quic/core/quic_stream.h index adc027992e1..f8c75afe7da 100644 --- a/chromium/net/quic/core/quic_stream.h +++ b/chromium/net/quic/core/quic_stream.h @@ -34,6 +34,7 @@ #include "net/quic/platform/api/quic_reference_counted.h" #include "net/quic/platform/api/quic_string.h" #include "net/quic/platform/api/quic_string_piece.h" +#include "net/spdy/core/spdy_protocol.h" namespace net { @@ -45,7 +46,19 @@ class QuicSession; class QUIC_EXPORT_PRIVATE QuicStream { public: - QuicStream(QuicStreamId id, QuicSession* session); + // This is somewhat arbitrary. It's possible, but unlikely, we will either + // fail to set a priority client-side, or cancel a stream before stripping the + // priority from the wire server-side. In either case, start out with a + // priority in the middle. + static const SpdyPriority kDefaultPriority = 3; + static_assert(kDefaultPriority == + (kV3LowestPriority + kV3HighestPriority) / 2, + "Unexpected value of kDefaultPriority"); + + // Creates a new stream with stream_id |id| associated with |session|. If + // |is_static| is true, then the stream will be given precedence + // over other streams when determing what streams should write next. + QuicStream(QuicStreamId id, QuicSession* session, bool is_static); virtual ~QuicStream(); @@ -93,6 +106,12 @@ class QUIC_EXPORT_PRIVATE QuicStream { virtual void CloseConnectionWithDetails(QuicErrorCode error, const QuicString& details); + SpdyPriority priority() const; + + // Sets priority_ to priority. This should only be called before bytes are + // written to the server. + void SetPriority(SpdyPriority priority); + // Returns true if this stream is still waiting for acks of sent data. // This will return false if all data has been acked, or if the stream // is no longer interested in data being acked (which happens when @@ -338,6 +357,8 @@ class QUIC_EXPORT_PRIVATE QuicStream { QuicStreamId id_; // Pointer to the owning QuicSession object. QuicSession* session_; + // The priority of the stream, once parsed. + SpdyPriority priority_; // Bytes read refers to payload bytes only: they do not include framing, // encryption overhead etc. uint64_t stream_bytes_read_; @@ -410,6 +431,10 @@ class QUIC_EXPORT_PRIVATE QuicStream { // Latched value of FLAGS_quic_buffered_data_threshold. const QuicByteCount buffered_data_threshold_; + // If true, then this stream has precedence over other streams for write + // scheduling. + const bool is_static_; + DISALLOW_COPY_AND_ASSIGN(QuicStream); }; diff --git a/chromium/net/quic/core/quic_stream_send_buffer.cc b/chromium/net/quic/core/quic_stream_send_buffer.cc index d92205c4575..ac1ab6ef1bd 100644 --- a/chromium/net/quic/core/quic_stream_send_buffer.cc +++ b/chromium/net/quic/core/quic_stream_send_buffer.cc @@ -15,6 +15,16 @@ namespace net { +namespace { + +struct CompareOffset { + bool operator()(const BufferedSlice& slice, QuicStreamOffset offset) const { + return slice.offset + slice.slice.length() < offset; + } +}; + +} // namespace + BufferedSlice::BufferedSlice(QuicMemSlice mem_slice, QuicStreamOffset offset) : slice(std::move(mem_slice)), offset(offset) {} @@ -35,7 +45,11 @@ QuicStreamSendBuffer::QuicStreamSendBuffer(QuicBufferAllocator* allocator) stream_bytes_written_(0), stream_bytes_outstanding_(0), write_index_(-1), - use_write_index_(GetQuicReloadableFlag(quic_use_write_index)) {} + free_mem_slice_out_of_order_( + GetQuicReloadableFlag(quic_free_mem_slice_out_of_order)), + enable_fast_path_on_data_acked_( + free_mem_slice_out_of_order_ && + GetQuicReloadableFlag(quic_fast_path_on_stream_data_acked)) {} QuicStreamSendBuffer::~QuicStreamSendBuffer() {} @@ -81,32 +95,6 @@ void QuicStreamSendBuffer::OnStreamDataConsumed(size_t bytes_consumed) { bool QuicStreamSendBuffer::WriteStreamData(QuicStreamOffset offset, QuicByteCount data_length, QuicDataWriter* writer) { - if (use_write_index_) { - return WriteStreamDataWithIndex(offset, data_length, writer); - } - for (const BufferedSlice& slice : buffered_slices_) { - if (data_length == 0 || offset < slice.offset) { - break; - } - if (offset >= slice.offset + slice.slice.length()) { - continue; - } - QuicByteCount slice_offset = offset - slice.offset; - QuicByteCount copy_length = - std::min(data_length, slice.slice.length() - slice_offset); - if (!writer->WriteBytes(slice.slice.data() + slice_offset, copy_length)) { - return false; - } - offset += copy_length; - data_length -= copy_length; - } - - return data_length == 0; -} - -bool QuicStreamSendBuffer::WriteStreamDataWithIndex(QuicStreamOffset offset, - QuicByteCount data_length, - QuicDataWriter* writer) { bool write_index_hit = false; QuicDeque<BufferedSlice>::iterator slice_it = write_index_ == -1 @@ -121,7 +109,6 @@ bool QuicStreamSendBuffer::WriteStreamDataWithIndex(QuicStreamOffset offset, // Determine if write actually happens at indexed slice. if (offset >= slice_it->offset) { write_index_hit = true; - QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_use_write_index, 1, 2); } else { // Write index missed, move iterator to the beginning. slice_it = buffered_slices_.begin(); @@ -172,6 +159,36 @@ bool QuicStreamSendBuffer::OnStreamDataAcked( if (data_length == 0) { return true; } + if (enable_fast_path_on_data_acked_) { + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_fast_path_on_stream_data_acked); + bool is_disjoint = false; + if (GetQuicReloadableFlag(quic_fast_is_disjoint)) { + is_disjoint = + bytes_acked_.Empty() || offset >= bytes_acked_.rbegin()->max(); + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_fast_is_disjoint); + } + if (is_disjoint || bytes_acked_.IsDisjoint(Interval<QuicStreamOffset>( + offset, offset + data_length))) { + // Optimization for the typical case, when all data is newly acked. + if (stream_bytes_outstanding_ < data_length) { + return false; + } + bytes_acked_.Add(offset, offset + data_length); + *newly_acked_length = data_length; + stream_bytes_outstanding_ -= data_length; + pending_retransmissions_.Difference(offset, offset + data_length); + if (!FreeMemSlices(offset, offset + data_length)) { + return false; + } + CleanUpBufferedSlices(); + return true; + } + // Exit if no new data gets acked. + if (bytes_acked_.Contains(offset, offset + data_length)) { + return true; + } + } + // Execute the slow path if newly acked data fill in existing holes. QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length); newly_acked.Difference(bytes_acked_); for (const auto& interval : newly_acked) { @@ -183,25 +200,34 @@ bool QuicStreamSendBuffer::OnStreamDataAcked( stream_bytes_outstanding_ -= *newly_acked_length; bytes_acked_.Add(offset, offset + data_length); pending_retransmissions_.Difference(offset, offset + data_length); + if (free_mem_slice_out_of_order_) { + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_free_mem_slice_out_of_order); + if (newly_acked.Empty()) { + return true; + } + if (!FreeMemSlices(newly_acked.begin()->min(), + newly_acked.rbegin()->max())) { + return false; + } + CleanUpBufferedSlices(); + return true; + } while (!buffered_slices_.empty() && bytes_acked_.Contains(buffered_slices_.front().offset, buffered_slices_.front().offset + buffered_slices_.front().slice.length())) { // Remove data which stops waiting for acks. Please note, data can be // acked out of order, but send buffer is cleaned up in order. - if (use_write_index_) { - QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_use_write_index, 2, 2); - QUIC_BUG_IF(write_index_ == 0) - << "Fail to advance current_write_slice_. It points to the slice " - "whose data has all be written and ACK'ed or ignored. " - "current_write_slice_ offset " - << buffered_slices_[write_index_].offset << " length " - << buffered_slices_[write_index_].slice.length(); - if (write_index_ > 0) { - // If write index is pointing to any slice, reduce the index as the - // slices are all shifted to the left by one. - --write_index_; - } + QUIC_BUG_IF(write_index_ == 0) + << "Fail to advance current_write_slice_. It points to the slice " + "whose data has all be written and ACK'ed or ignored. " + "current_write_slice_ offset " + << buffered_slices_[write_index_].offset << " length " + << buffered_slices_[write_index_].slice.length(); + if (write_index_ > 0) { + // If write index is pointing to any slice, reduce the index as the + // slices are all shifted to the left by one. + --write_index_; } buffered_slices_.pop_front(); } @@ -247,6 +273,50 @@ StreamPendingRetransmission QuicStreamSendBuffer::NextPendingRetransmission() return {0, 0}; } +bool QuicStreamSendBuffer::FreeMemSlices(QuicStreamOffset start, + QuicStreamOffset end) { + DCHECK(free_mem_slice_out_of_order_); + // Find it, such that buffered_slices_[it - 1].end < start <= + // buffered_slices_[it].end. + auto it = std::lower_bound(buffered_slices_.begin(), buffered_slices_.end(), + start, CompareOffset()); + if (it == buffered_slices_.end() || it->slice.empty()) { + QUIC_DLOG(ERROR) << "Offset " << start + << " does not exist or it has already been acked."; + return false; + } + for (; it != buffered_slices_.end(); ++it) { + if (it->offset >= end) { + break; + } + if (!it->slice.empty() && + bytes_acked_.Contains(it->offset, it->offset + it->slice.length())) { + it->slice.Reset(); + } + } + return true; +} + +void QuicStreamSendBuffer::CleanUpBufferedSlices() { + DCHECK(free_mem_slice_out_of_order_); + while (!buffered_slices_.empty() && buffered_slices_.front().slice.empty()) { + // Remove data which stops waiting for acks. Please note, mem slices can + // be released out of order, but send buffer is cleaned up in order. + QUIC_BUG_IF(write_index_ == 0) + << "Fail to advance current_write_slice_. It points to the slice " + "whose data has all be written and ACK'ed or ignored. " + "current_write_slice_ offset " + << buffered_slices_[write_index_].offset << " length " + << buffered_slices_[write_index_].slice.length(); + if (write_index_ > 0) { + // If write index is pointing to any slice, reduce the index as the + // slices are all shifted to the left by one. + --write_index_; + } + buffered_slices_.pop_front(); + } +} + bool QuicStreamSendBuffer::IsStreamDataOutstanding( QuicStreamOffset offset, QuicByteCount data_length) const { diff --git a/chromium/net/quic/core/quic_stream_send_buffer.h b/chromium/net/quic/core/quic_stream_send_buffer.h index 30a12700f11..ff8d552b83c 100644 --- a/chromium/net/quic/core/quic_stream_send_buffer.h +++ b/chromium/net/quic/core/quic_stream_send_buffer.h @@ -123,14 +123,13 @@ class QUIC_EXPORT_PRIVATE QuicStreamSendBuffer { friend class test::QuicStreamSendBufferPeer; friend class test::QuicStreamPeer; - // Another version of WriteStreamData() to be able to start writing from - // write_index_ points to instead of searching through the slices to find the - // place to write. - // TODO(danzh): inline this method into WriteStreamData() after - // quic_reloadable_flag_quic_use_write_index is deprecated. - bool WriteStreamDataWithIndex(QuicStreamOffset offset, - QuicByteCount data_length, - QuicDataWriter* writer); + // Called when data within offset [start, end) gets acked. Frees fully + // acked buffered slices if any. Returns false if the corresponding data does + // not exist or has been acked. + bool FreeMemSlices(QuicStreamOffset start, QuicStreamOffset end); + + // Cleanup empty slices in order from buffered_slices_. + void CleanUpBufferedSlices(); QuicDeque<BufferedSlice> buffered_slices_; @@ -155,8 +154,12 @@ class QUIC_EXPORT_PRIVATE QuicStreamSendBuffer { // time. -1 if send buffer is empty or all data has been written. int32_t write_index_; - // Latched value of quic_reloadable_flag_quic_stream_send_buffer_write_index. - const bool use_write_index_; + // Latched value of quic_reloadable_flag_quic_free_mem_slice_out_of_order. + const bool free_mem_slice_out_of_order_; + + // Latched value of quic_reloadable_flag_quic_free_mem_slice_out_of_order and + // quic_reloadable_flag_quic_fast_path_on_stream_data_acked. + const bool enable_fast_path_on_data_acked_; }; } // namespace net diff --git a/chromium/net/quic/core/quic_stream_send_buffer_test.cc b/chromium/net/quic/core/quic_stream_send_buffer_test.cc index fc7abc262b8..a83f5260888 100644 --- a/chromium/net/quic/core/quic_stream_send_buffer_test.cc +++ b/chromium/net/quic/core/quic_stream_send_buffer_test.cc @@ -105,12 +105,8 @@ TEST_F(QuicStreamSendBufferTest, CopyDataToBuffer) { // Invalid data copy. QuicDataWriter writer3(4000, buf, HOST_BYTE_ORDER); EXPECT_FALSE(send_buffer_.WriteStreamData(3000, 1024, &writer3)); - if (GetQuicReloadableFlag(quic_use_write_index)) { - EXPECT_DFATAL(send_buffer_.WriteStreamData(0, 4000, &writer3), - "Writer fails to write."); - } else { - EXPECT_FALSE(send_buffer_.WriteStreamData(0, 4000, &writer3)); - } + EXPECT_DFATAL(send_buffer_.WriteStreamData(0, 4000, &writer3), + "Writer fails to write."); send_buffer_.OnStreamDataConsumed(3840); EXPECT_EQ(3840u, send_buffer_.stream_bytes_written()); @@ -188,6 +184,40 @@ TEST_F(QuicStreamSendBufferTest, AckStreamDataMultipleTimes) { EXPECT_FALSE(send_buffer_.OnStreamDataAcked(4000, 100, &newly_acked_length)); } +TEST_F(QuicStreamSendBufferTest, AckStreamDataOutOfOrder) { + WriteAllData(); + QuicByteCount newly_acked_length; + EXPECT_TRUE(send_buffer_.OnStreamDataAcked(500, 1000, &newly_acked_length)); + EXPECT_EQ(1000u, newly_acked_length); + EXPECT_EQ(4u, send_buffer_.size()); + EXPECT_EQ(3840u, QuicStreamSendBufferPeer::TotalLength(&send_buffer_)); + + EXPECT_TRUE(send_buffer_.OnStreamDataAcked(1200, 1000, &newly_acked_length)); + EXPECT_EQ(700u, newly_acked_length); + EXPECT_EQ(4u, send_buffer_.size()); + if (GetQuicReloadableFlag(quic_free_mem_slice_out_of_order)) { + // Slice 2 gets fully acked. + EXPECT_EQ(2816u, QuicStreamSendBufferPeer::TotalLength(&send_buffer_)); + } else { + EXPECT_EQ(3840u, QuicStreamSendBufferPeer::TotalLength(&send_buffer_)); + } + + EXPECT_TRUE(send_buffer_.OnStreamDataAcked(2000, 1840, &newly_acked_length)); + EXPECT_EQ(1640u, newly_acked_length); + EXPECT_EQ(4u, send_buffer_.size()); + if (GetQuicReloadableFlag(quic_free_mem_slice_out_of_order)) { + // Slices 3 and 4 get fully acked. + EXPECT_EQ(1024u, QuicStreamSendBufferPeer::TotalLength(&send_buffer_)); + } else { + EXPECT_EQ(3840u, QuicStreamSendBufferPeer::TotalLength(&send_buffer_)); + } + + EXPECT_TRUE(send_buffer_.OnStreamDataAcked(0, 1000, &newly_acked_length)); + EXPECT_EQ(500u, newly_acked_length); + EXPECT_EQ(0u, send_buffer_.size()); + EXPECT_EQ(0u, QuicStreamSendBufferPeer::TotalLength(&send_buffer_)); +} + TEST_F(QuicStreamSendBufferTest, PendingRetransmission) { WriteAllData(); EXPECT_TRUE(send_buffer_.IsStreamDataOutstanding(0, 3840)); @@ -230,9 +260,6 @@ TEST_F(QuicStreamSendBufferTest, PendingRetransmission) { } TEST_F(QuicStreamSendBufferTest, CurrentWriteIndex) { - if (!GetQuicReloadableFlag(quic_use_write_index)) { - return; - } char buf[4000]; QuicDataWriter writer(4000, buf, HOST_BYTE_ORDER); // With data buffered, index points to the 1st slice of data. diff --git a/chromium/net/quic/core/quic_stream_sequencer_buffer.cc b/chromium/net/quic/core/quic_stream_sequencer_buffer.cc index f978b59a588..ac3a42e73dd 100644 --- a/chromium/net/quic/core/quic_stream_sequencer_buffer.cc +++ b/chromium/net/quic/core/quic_stream_sequencer_buffer.cc @@ -103,7 +103,40 @@ QuicErrorCode QuicStreamSequencerBuffer::OnStreamData( RecordInternalErrorLocation(QUIC_STREAM_SEQUENCER_BUFFER); return QUIC_INTERNAL_ERROR; } - + if (GetQuicReloadableFlag(quic_fast_path_on_stream_data) && + (bytes_received_.Empty() || + starting_offset >= bytes_received_.rbegin()->max() || + bytes_received_.IsDisjoint(Interval<QuicStreamOffset>( + starting_offset, starting_offset + size)))) { + // Optimization for the typical case, when all data is newly received. + QUIC_FLAG_COUNT(quic_reloadable_flag_quic_fast_path_on_stream_data); + if (!bytes_received_.Empty() && + starting_offset == bytes_received_.rbegin()->max()) { + // Extend the right edge of last interval. + // TODO(fayang): Encapsulate this into a future version of QuicIntervalSet + // if this is more efficient than Add. + const_cast<Interval<QuicPacketNumber>*>(&(*bytes_received_.rbegin())) + ->SetMax(starting_offset + size); + } else { + bytes_received_.Add(starting_offset, starting_offset + size); + if (bytes_received_.Size() >= kMaxNumDataIntervalsAllowed) { + // This frame is going to create more intervals than allowed. Stop + // processing. + *error_details = "Too many data intervals received for this stream."; + return QUIC_TOO_MANY_STREAM_DATA_INTERVALS; + } + } + size_t bytes_copy = 0; + if (!CopyStreamData(starting_offset, data, &bytes_copy, error_details)) { + return QUIC_STREAM_SEQUENCER_INVALID_STATE; + } + *bytes_buffered += bytes_copy; + frame_arrival_time_map_.insert( + std::make_pair(starting_offset, FrameInfo(size, timestamp))); + num_bytes_buffered_ += *bytes_buffered; + return QUIC_NO_ERROR; + } + // Slow path, received data overlaps with received data. QuicIntervalSet<QuicStreamOffset> newly_received(starting_offset, starting_offset + size); newly_received.Difference(bytes_received_); diff --git a/chromium/net/quic/core/quic_stream_sequencer_test.cc b/chromium/net/quic/core/quic_stream_sequencer_test.cc index 4ec52a03d16..3d608e4ff45 100644 --- a/chromium/net/quic/core/quic_stream_sequencer_test.cc +++ b/chromium/net/quic/core/quic_stream_sequencer_test.cc @@ -34,7 +34,8 @@ namespace test { class MockStream : public QuicStream { public: - MockStream(QuicSession* session, QuicStreamId id) : QuicStream(id, session) {} + MockStream(QuicSession* session, QuicStreamId id) + : QuicStream(id, session, /*is_static=*/false) {} MOCK_METHOD0(OnFinRead, void()); MOCK_METHOD0(OnDataAvailable, void()); diff --git a/chromium/net/quic/core/quic_stream_test.cc b/chromium/net/quic/core/quic_stream_test.cc index af56b2effae..7b7d1a5429c 100644 --- a/chromium/net/quic/core/quic_stream_test.cc +++ b/chromium/net/quic/core/quic_stream_test.cc @@ -50,7 +50,7 @@ const bool kShouldNotProcessData = false; class TestStream : public QuicStream { public: TestStream(QuicStreamId id, QuicSession* session, bool should_process_data) - : QuicStream(id, session) {} + : QuicStream(id, session, /*is_static=*/false) {} void OnDataAvailable() override {} @@ -123,7 +123,11 @@ class QuicStreamTest : public QuicTestWithParam<bool> { .Times(AnyNumber()); write_blocked_list_ = QuicSessionPeer::GetWriteBlockedStreams(session_.get()); - write_blocked_list_->RegisterStream(kTestStreamId, kV3HighestPriority); + if (!session_->register_streams_early()) { + write_blocked_list_->RegisterStream(kTestStreamId, + /*is_static_stream=*/false, + kV3HighestPriority); + } } bool fin_sent() { return QuicStreamPeer::FinSent(stream_); } @@ -134,7 +138,7 @@ class QuicStreamTest : public QuicTestWithParam<bool> { } bool HasWriteBlockedStreams() { - return write_blocked_list_->HasWriteBlockedCryptoOrHeadersStream() || + return write_blocked_list_->HasWriteBlockedSpecialStream() || write_blocked_list_->HasWriteBlockedDataStreams(); } @@ -173,7 +177,7 @@ TEST_F(QuicStreamTest, WriteAllData) { 1 + QuicPacketCreator::StreamFramePacketOverhead( connection_->transport_version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, - PACKET_6BYTE_PACKET_NUMBER, 0u); + PACKET_4BYTE_PACKET_NUMBER, 0u); connection_->SetMaxPacketLength(length); EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _)) @@ -254,7 +258,7 @@ TEST_F(QuicStreamTest, WriteOrBufferData) { 1 + QuicPacketCreator::StreamFramePacketOverhead( connection_->transport_version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, - PACKET_6BYTE_PACKET_NUMBER, 0u); + PACKET_4BYTE_PACKET_NUMBER, 0u); connection_->SetMaxPacketLength(length); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) @@ -457,13 +461,9 @@ TEST_F(QuicStreamTest, StopReadingSendsFlowControl) { EXPECT_CALL(*connection_, CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _)) .Times(0); - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(this, &QuicStreamTest::ClearControlFrame)); - } else { - EXPECT_CALL(*connection_, SendWindowUpdate(_, _)).Times(AtLeast(1)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(AtLeast(1)) + .WillRepeatedly(Invoke(this, &QuicStreamTest::ClearControlFrame)); QuicString data(1000, 'x'); for (QuicStreamOffset offset = 0; @@ -821,7 +821,7 @@ TEST_F(QuicStreamTest, RstFrameReceivedStreamFinishSending) { QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(), QUIC_STREAM_CANCELLED, 1234); stream_->OnStreamReset(rst_frame); - // Stream stops waiting for acks as it has unacked data. + // Stream still waits for acks as it finishes sending and has unacked data. EXPECT_TRUE(stream_->IsWaitingForAcks()); EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); } @@ -969,9 +969,6 @@ TEST_F(QuicStreamTest, WriteMemSlices) { set_initial_flow_control_window_bytes(500000); Initialize(kShouldProcessData); - if (!session_->can_use_slices()) { - return; - } char data[1024]; std::vector<std::pair<char*, size_t>> buffers; buffers.push_back(std::make_pair(data, QUIC_ARRAYSIZE(data))); @@ -1034,9 +1031,6 @@ TEST_F(QuicStreamTest, WriteMemSlices) { TEST_F(QuicStreamTest, WriteMemSlicesReachStreamLimit) { SetQuicReloadableFlag(quic_stream_too_long, true); Initialize(kShouldProcessData); - if (!session_->can_use_slices()) { - return; - } QuicStreamPeer::SetStreamBytesWritten(kMaxStreamLength - 5u, stream_); char data[5]; std::vector<std::pair<char*, size_t>> buffers; @@ -1215,12 +1209,8 @@ TEST_F(QuicStreamTest, MarkConnectionLevelWriteBlockedOnWindowUpdateFrame) { EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce(Invoke(this, &QuicStreamTest::ClearControlFrame)); - } else { - EXPECT_CALL(*connection_, SendBlocked(stream_->id())); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(this, &QuicStreamTest::ClearControlFrame)); QuicString data(1024, '.'); stream_->WriteOrBufferData(data, false, nullptr); EXPECT_FALSE(HasWriteBlockedStreams()); @@ -1229,20 +1219,14 @@ TEST_F(QuicStreamTest, MarkConnectionLevelWriteBlockedOnWindowUpdateFrame) { 1234); stream_->OnWindowUpdateFrame(window_update); - if (session_->session_unblocks_stream()) { - // Verify stream is marked connection level write blocked. - EXPECT_TRUE(HasWriteBlockedStreams()); - EXPECT_TRUE(stream_->HasBufferedData()); - } else { - EXPECT_FALSE(HasWriteBlockedStreams()); - EXPECT_FALSE(stream_->HasBufferedData()); - } + // Verify stream is marked connection level write blocked. + EXPECT_TRUE(HasWriteBlockedStreams()); + EXPECT_TRUE(stream_->HasBufferedData()); } // Regression test for b/73282665. TEST_F(QuicStreamTest, MarkConnectionLevelWriteBlockedOnWindowUpdateFrameWithNoBufferedData) { - SetQuicReloadableFlag(quic_streams_unblocked_by_session2, true); // Set a small initial flow control window size. const uint32_t kSmallWindow = 100; set_initial_flow_control_window_bytes(kSmallWindow); @@ -1251,12 +1235,8 @@ TEST_F(QuicStreamTest, QuicString data(kSmallWindow, '.'); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); - if (session_->use_control_frame_manager()) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce(Invoke(this, &QuicStreamTest::ClearControlFrame)); - } else { - EXPECT_CALL(*connection_, SendBlocked(stream_->id())); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(this, &QuicStreamTest::ClearControlFrame)); stream_->WriteOrBufferData(data, false, nullptr); EXPECT_FALSE(HasWriteBlockedStreams()); diff --git a/chromium/net/quic/core/quic_types.h b/chromium/net/quic/core/quic_types.h index d237227e047..9671b45eaed 100644 --- a/chromium/net/quic/core/quic_types.h +++ b/chromium/net/quic/core/quic_types.h @@ -33,6 +33,12 @@ typedef uint64_t QuicIetfStreamDataLength; typedef uint64_t QuicIetfStreamId; typedef uint64_t QuicIetfStreamOffset; +const size_t kQuicPathFrameBufferSize = 8; +typedef std::array<uint8_t, kQuicPathFrameBufferSize> QuicPathFrameBuffer; + +// Application error code used in the QUIC Stop Sending frame. +typedef uint16_t QuicApplicationErrorCode; + // A struct for functions which consume data payloads and fins. struct QUIC_EXPORT_PRIVATE QuicConsumedData { QuicConsumedData(size_t bytes_consumed, bool fin_consumed); @@ -66,9 +72,17 @@ enum QuicAsyncStatus { enum WriteStatus { WRITE_STATUS_OK, WRITE_STATUS_BLOCKED, + // To make the IsWriteError(WriteStatus) function work properly: + // - Non-errors MUST be added before WRITE_STATUS_ERROR. + // - Errors MUST be added after WRITE_STATUS_ERROR. WRITE_STATUS_ERROR, + WRITE_STATUS_MSG_TOO_BIG, }; +inline bool IsWriteError(WriteStatus status) { + return status >= WRITE_STATUS_ERROR; +} + // A struct used to return the result of write calls including either the number // of bytes written or the error code, depending upon the status. struct QUIC_EXPORT_PRIVATE WriteResult { @@ -156,8 +170,9 @@ enum QuicIetfFrameType : int8_t { IETF_STREAM_ID_BLOCKED = 0x0a, IETF_NEW_CONNECTION_ID = 0x0b, IETF_STOP_SENDING = 0x0c, - IETF_PONG = 0x0d, - IETF_ACK = 0x0e, + IETF_ACK = 0x0d, + IETF_PATH_CHALLENGE = 0x0e, + IETF_PATH_RESPONSE = 0x0f, // the low-3 bits of the stream frame type value are actually flags // declaring what parts of the frame are/are-not present, as well as // some other control information. The code would then do something diff --git a/chromium/net/quic/core/quic_unacked_packet_map.cc b/chromium/net/quic/core/quic_unacked_packet_map.cc index 678bc5334b8..a70ac7f3b4e 100644 --- a/chromium/net/quic/core/quic_unacked_packet_map.cc +++ b/chromium/net/quic/core/quic_unacked_packet_map.cc @@ -17,6 +17,7 @@ QuicUnackedPacketMap::QuicUnackedPacketMap() least_unacked_(1), bytes_in_flight_(0), pending_crypto_packet_count_(0), + last_crypto_packet_sent_time_(QuicTime::Zero()), session_notifier_(nullptr), session_decides_what_to_write_(false) {} @@ -63,6 +64,7 @@ void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet, if (old_packet_number == 0) { if (has_crypto_handshake) { ++pending_crypto_packet_count_; + last_crypto_packet_sent_time_ = sent_time; } packet->retransmittable_frames.swap( @@ -302,6 +304,10 @@ QuicTime QuicUnackedPacketMap::GetLastPacketSentTime() const { return QuicTime::Zero(); } +QuicTime QuicUnackedPacketMap::GetLastCryptoPacketSentTime() const { + return last_crypto_packet_sent_time_; +} + size_t QuicUnackedPacketMap::GetNumUnackedPacketsDebugOnly() const { size_t unacked_packet_count = 0; QuicPacketNumber packet_number = least_unacked_; diff --git a/chromium/net/quic/core/quic_unacked_packet_map.h b/chromium/net/quic/core/quic_unacked_packet_map.h index 0bafe98f6b1..30091975f5d 100644 --- a/chromium/net/quic/core/quic_unacked_packet_map.h +++ b/chromium/net/quic/core/quic_unacked_packet_map.h @@ -128,6 +128,9 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { // Returns the time that the last unacked packet was sent. QuicTime GetLastPacketSentTime() const; + // Returns the time that the last unacked crypto packet was sent. + QuicTime GetLastCryptoPacketSentTime() const; + // Returns the number of unacked packets. size_t GetNumUnackedPacketsDebugOnly() const; @@ -213,6 +216,9 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { // Number of retransmittable crypto handshake packets. size_t pending_crypto_packet_count_; + // Time that the last unacked crypto packet was sent. + QuicTime last_crypto_packet_sent_time_; + // Receives notifications of frames being retransmitted or acknowledged. SessionNotifierInterface* session_notifier_; diff --git a/chromium/net/quic/core/quic_utils.cc b/chromium/net/quic/core/quic_utils.cc index 49ec2198baa..c5c00e77d61 100644 --- a/chromium/net/quic/core/quic_utils.cc +++ b/chromium/net/quic/core/quic_utils.cc @@ -13,6 +13,7 @@ #include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_prefetch.h" #include "net/quic/platform/api/quic_string.h" +#include "net/quic/platform/api/quic_uint128.h" namespace net { namespace { @@ -27,9 +28,9 @@ namespace { #endif #ifdef QUIC_UTIL_HAS_UINT128 -uint128 IncrementalHashFast(uint128 uhash, QuicStringPiece data) { +QuicUint128 IncrementalHashFast(QuicUint128 uhash, QuicStringPiece data) { // This code ends up faster than the naive implementation for 2 reasons: - // 1. uint128 from base/int128.h is sufficiently complicated that the compiler + // 1. QuicUint128 is sufficiently complicated that the compiler // cannot transform the multiplication by kPrime into a shift-multiply-add; // it has go through all of the instructions for a 128-bit multiply. // 2. Because there are so fewer instructions (around 13), the hot loop fits @@ -37,13 +38,14 @@ uint128 IncrementalHashFast(uint128 uhash, QuicStringPiece data) { // kPrime = 309485009821345068724781371 static const __uint128_t kPrime = (static_cast<__uint128_t>(16777216) << 64) + 315; - __uint128_t xhash = (static_cast<__uint128_t>(Uint128High64(uhash)) << 64) + - Uint128Low64(uhash); + auto hi = QuicUint128High64(uhash); + auto lo = QuicUint128Low64(uhash); + __uint128_t xhash = (static_cast<__uint128_t>(hi) << 64) + lo; const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data()); for (size_t i = 0; i < data.length(); ++i) { xhash = (xhash ^ octets[i]) * kPrime; } - return MakeUint128( + return MakeQuicUint128( static_cast<uint64_t>(xhash >> 64), static_cast<uint64_t>(xhash & UINT64_C(0xFFFFFFFFFFFFFFFF))); } @@ -51,19 +53,19 @@ uint128 IncrementalHashFast(uint128 uhash, QuicStringPiece data) { #ifndef QUIC_UTIL_HAS_UINT128 // Slow implementation of IncrementalHash. In practice, only used by Chromium. -uint128 IncrementalHashSlow(uint128 hash, QuicStringPiece data) { +QuicUint128 IncrementalHashSlow(QuicUint128 hash, QuicStringPiece data) { // kPrime = 309485009821345068724781371 - static const uint128 kPrime = MakeUint128(16777216, 315); + static const uint128 kPrime = MakeQuicUint128(16777216, 315); const uint8_t* octets = reinterpret_cast<const uint8_t*>(data.data()); for (size_t i = 0; i < data.length(); ++i) { - hash = hash ^ MakeUint128(0, octets[i]); + hash = hash ^ MakeQuicUint128(0, octets[i]); hash = hash * kPrime; } return hash; } #endif -uint128 IncrementalHash(uint128 hash, QuicStringPiece data) { +QuicUint128 IncrementalHash(QuicUint128 hash, QuicStringPiece data) { #ifdef QUIC_UTIL_HAS_UINT128 return IncrementalHashFast(hash, data); #else @@ -91,27 +93,27 @@ uint64_t QuicUtils::FNV1a_64_Hash(QuicStringPiece data) { } // static -uint128 QuicUtils::FNV1a_128_Hash(QuicStringPiece data) { +QuicUint128 QuicUtils::FNV1a_128_Hash(QuicStringPiece data) { return FNV1a_128_Hash_Three(data, QuicStringPiece(), QuicStringPiece()); } // static -uint128 QuicUtils::FNV1a_128_Hash_Two(QuicStringPiece data1, - QuicStringPiece data2) { +QuicUint128 QuicUtils::FNV1a_128_Hash_Two(QuicStringPiece data1, + QuicStringPiece data2) { return FNV1a_128_Hash_Three(data1, data2, QuicStringPiece()); } // static -uint128 QuicUtils::FNV1a_128_Hash_Three(QuicStringPiece data1, - QuicStringPiece data2, - QuicStringPiece data3) { +QuicUint128 QuicUtils::FNV1a_128_Hash_Three(QuicStringPiece data1, + QuicStringPiece data2, + QuicStringPiece data3) { // The two constants are defined as part of the hash algorithm. // see http://www.isthe.com/chongo/tech/comp/fnv/ // kOffset = 144066263297769815596495629667062367629 - const uint128 kOffset = - MakeUint128(UINT64_C(7809847782465536322), UINT64_C(7113472399480571277)); + const QuicUint128 kOffset = MakeQuicUint128(UINT64_C(7809847782465536322), + UINT64_C(7113472399480571277)); - uint128 hash = IncrementalHash(kOffset, data1); + QuicUint128 hash = IncrementalHash(kOffset, data1); if (data2.empty()) { return hash; } @@ -124,9 +126,9 @@ uint128 QuicUtils::FNV1a_128_Hash_Three(QuicStringPiece data1, } // static -void QuicUtils::SerializeUint128Short(uint128 v, uint8_t* out) { - const uint64_t lo = Uint128Low64(v); - const uint64_t hi = Uint128High64(v); +void QuicUtils::SerializeUint128Short(QuicUint128 v, uint8_t* out) { + const uint64_t lo = QuicUint128Low64(v); + const uint64_t hi = QuicUint128High64(v); // This assumes that the system is little-endian. memcpy(out, &lo, sizeof(lo)); memcpy(out + sizeof(lo), &hi, sizeof(hi) / 2); @@ -175,6 +177,21 @@ QuicString QuicUtils::AddressChangeTypeToString(AddressChangeType type) { return "INVALID_ADDRESS_CHANGE_TYPE"; } +const char* QuicUtils::SentPacketStateToString(SentPacketState state) { + switch (state) { + RETURN_STRING_LITERAL(OUTSTANDING); + RETURN_STRING_LITERAL(NEVER_SENT); + RETURN_STRING_LITERAL(ACKED); + RETURN_STRING_LITERAL(UNACKABLE); + RETURN_STRING_LITERAL(HANDSHAKE_RETRANSMITTED); + RETURN_STRING_LITERAL(LOST); + RETURN_STRING_LITERAL(TLP_RETRANSMITTED); + RETURN_STRING_LITERAL(RTO_RETRANSMITTED); + RETURN_STRING_LITERAL(PROBE_RETRANSMITTED); + } + return "INVALID_SENT_PACKET_STATE"; +} + // static AddressChangeType QuicUtils::DetermineAddressChangeType( const QuicSocketAddress& old_address, diff --git a/chromium/net/quic/core/quic_utils.h b/chromium/net/quic/core/quic_utils.h index 9790c41f727..a891beba292 100644 --- a/chromium/net/quic/core/quic_utils.h +++ b/chromium/net/quic/core/quic_utils.h @@ -9,7 +9,6 @@ #include <cstdint> #include "base/macros.h" -#include "net/base/int128.h" #include "net/base/iovec.h" #include "net/quic/core/quic_error_codes.h" #include "net/quic/core/quic_types.h" @@ -17,6 +16,7 @@ #include "net/quic/platform/api/quic_socket_address.h" #include "net/quic/platform/api/quic_string.h" #include "net/quic/platform/api/quic_string_piece.h" +#include "net/quic/platform/api/quic_uint128.h" namespace net { @@ -28,22 +28,22 @@ class QUIC_EXPORT_PRIVATE QuicUtils { // Returns the 128 bit FNV1a hash of the data. See // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param - static uint128 FNV1a_128_Hash(QuicStringPiece data); + static QuicUint128 FNV1a_128_Hash(QuicStringPiece data); // Returns the 128 bit FNV1a hash of the two sequences of data. See // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param - static uint128 FNV1a_128_Hash_Two(QuicStringPiece data1, - QuicStringPiece data2); + static QuicUint128 FNV1a_128_Hash_Two(QuicStringPiece data1, + QuicStringPiece data2); // Returns the 128 bit FNV1a hash of the three sequences of data. See // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param - static uint128 FNV1a_128_Hash_Three(QuicStringPiece data1, - QuicStringPiece data2, - QuicStringPiece data3); + static QuicUint128 FNV1a_128_Hash_Three(QuicStringPiece data1, + QuicStringPiece data2, + QuicStringPiece data3); // SerializeUint128 writes the first 96 bits of |v| in little-endian form // to |out|. - static void SerializeUint128Short(uint128 v, uint8_t* out); + static void SerializeUint128Short(QuicUint128 v, uint8_t* out); // Returns the level of encryption as a char* static const char* EncryptionLevelToString(EncryptionLevel level); @@ -54,6 +54,9 @@ class QUIC_EXPORT_PRIVATE QuicUtils { // Returns AddressChangeType as a std::string. static QuicString AddressChangeTypeToString(AddressChangeType type); + // Returns SentPacketState as a char*. + static const char* SentPacketStateToString(SentPacketState state); + // Determines and returns change type of address change from |old_address| to // |new_address|. static AddressChangeType DetermineAddressChangeType( diff --git a/chromium/net/quic/core/quic_utils_test.cc b/chromium/net/quic/core/quic_utils_test.cc index a27f90f145f..c797937742c 100644 --- a/chromium/net/quic/core/quic_utils_test.cc +++ b/chromium/net/quic/core/quic_utils_test.cc @@ -73,17 +73,17 @@ TEST_F(QuicUtilsTest, DetermineAddressChangeType) { QuicUtils::DetermineAddressChangeType(old_address, new_address)); } -uint128 IncrementalHashReference(const void* data, size_t len) { +QuicUint128 IncrementalHashReference(const void* data, size_t len) { // The two constants are defined as part of the hash algorithm. // see http://www.isthe.com/chongo/tech/comp/fnv/ // hash = 144066263297769815596495629667062367629 - uint128 hash = - MakeUint128(UINT64_C(7809847782465536322), UINT64_C(7113472399480571277)); + QuicUint128 hash = MakeQuicUint128(UINT64_C(7809847782465536322), + UINT64_C(7113472399480571277)); // kPrime = 309485009821345068724781371 - const uint128 kPrime = MakeUint128(16777216, 315); + const QuicUint128 kPrime = MakeQuicUint128(16777216, 315); const uint8_t* octets = reinterpret_cast<const uint8_t*>(data); for (size_t i = 0; i < len; ++i) { - hash = hash ^ MakeUint128(0, octets[i]); + hash = hash ^ MakeQuicUint128(0, octets[i]); hash = hash * kPrime; } return hash; diff --git a/chromium/net/quic/core/quic_versions.cc b/chromium/net/quic/core/quic_versions.cc index bac51f16959..f3094a1497e 100644 --- a/chromium/net/quic/core/quic_versions.cc +++ b/chromium/net/quic/core/quic_versions.cc @@ -25,6 +25,16 @@ QuicVersionLabel MakeVersionLabel(char a, char b, char c, char d) { } // namespace +ParsedQuicVersion::ParsedQuicVersion(HandshakeProtocol handshake_protocol, + QuicTransportVersion transport_version) + : handshake_protocol(handshake_protocol), + transport_version(transport_version) { + if (handshake_protocol == PROTOCOL_TLS1_3 && + !FLAGS_quic_supports_tls_handshake) { + QUIC_BUG << "TLS use attempted when not enabled"; + } +} + std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version) { os << ParsedQuicVersionToString(version); return os; @@ -37,9 +47,6 @@ QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) { proto = 'Q'; break; case PROTOCOL_TLS1_3: - if (!FLAGS_quic_supports_tls_handshake) { - QUIC_BUG << "TLS use attempted when not enabled"; - } proto = 'T'; break; default: diff --git a/chromium/net/quic/core/quic_versions.h b/chromium/net/quic/core/quic_versions.h index e2b45fece26..2f97db34a62 100644 --- a/chromium/net/quic/core/quic_versions.h +++ b/chromium/net/quic/core/quic_versions.h @@ -52,14 +52,12 @@ enum HandshakeProtocol { // A parsed QUIC version label which determines that handshake protocol // and the transport version. -struct ParsedQuicVersion { +struct QUIC_EXPORT_PRIVATE ParsedQuicVersion { HandshakeProtocol handshake_protocol; QuicTransportVersion transport_version; ParsedQuicVersion(HandshakeProtocol handshake_protocol, - QuicTransportVersion transport_version) - : handshake_protocol(handshake_protocol), - transport_version(transport_version) {} + QuicTransportVersion transport_version); ParsedQuicVersion(const ParsedQuicVersion& other) : handshake_protocol(other.handshake_protocol), diff --git a/chromium/net/quic/core/quic_write_blocked_list.cc b/chromium/net/quic/core/quic_write_blocked_list.cc index 32f23cf3eb9..f5e9775df80 100644 --- a/chromium/net/quic/core/quic_write_blocked_list.cc +++ b/chromium/net/quic/core/quic_write_blocked_list.cc @@ -4,12 +4,15 @@ #include "net/quic/core/quic_write_blocked_list.h" +#include "net/quic/platform/api/quic_flags.h" + namespace net { -QuicWriteBlockedList::QuicWriteBlockedList() +QuicWriteBlockedList::QuicWriteBlockedList(bool register_static_streams) : last_priority_popped_(0), crypto_stream_blocked_(false), - headers_stream_blocked_(false) { + headers_stream_blocked_(false), + register_static_streams_(register_static_streams) { memset(batch_write_stream_id_, 0, sizeof(batch_write_stream_id_)); memset(bytes_left_for_batch_write_, 0, sizeof(bytes_left_for_batch_write_)); } diff --git a/chromium/net/quic/core/quic_write_blocked_list.h b/chromium/net/quic/core/quic_write_blocked_list.h index a2b6033d1a4..1a5b3d4b354 100644 --- a/chromium/net/quic/core/quic_write_blocked_list.h +++ b/chromium/net/quic/core/quic_write_blocked_list.h @@ -11,6 +11,7 @@ #include "base/macros.h" #include "net/quic/core/quic_packets.h" #include "net/quic/platform/api/quic_export.h" +#include "net/quic/platform/api/quic_map_util.h" #include "net/spdy/core/priority_write_scheduler.h" namespace net { @@ -23,57 +24,100 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList { typedef PriorityWriteScheduler<QuicStreamId> QuicPriorityWriteScheduler; public: - QuicWriteBlockedList(); + explicit QuicWriteBlockedList(bool register_static_streams); ~QuicWriteBlockedList(); bool HasWriteBlockedDataStreams() const { return priority_write_scheduler_.HasReadyStreams(); } - bool HasWriteBlockedCryptoOrHeadersStream() const { + bool HasWriteBlockedSpecialStream() const { + if (register_static_streams_) { + for (const auto& stream : static_streams_) { + if (stream.second) { + return true; + } + } + return false; + } return crypto_stream_blocked_ || headers_stream_blocked_; } - size_t NumBlockedStreams() const { - size_t num_blocked = priority_write_scheduler_.NumReadyStreams(); - if (crypto_stream_blocked_) { - ++num_blocked; - } - if (headers_stream_blocked_) { - ++num_blocked; + size_t NumBlockedSpecialStreams() const { + size_t num_blocked = 0; + if (register_static_streams_) { + for (const auto& stream : static_streams_) { + if (stream.second) { + ++num_blocked; + } + } + } else { + if (crypto_stream_blocked_) { + ++num_blocked; + } + if (headers_stream_blocked_) { + ++num_blocked; + } } - return num_blocked; } + size_t NumBlockedStreams() const { + return NumBlockedSpecialStreams() + + priority_write_scheduler_.NumReadyStreams(); + } + bool ShouldYield(QuicStreamId id) const { - if (id == kCryptoStreamId) { - return false; // The crypto stream yields to none. - } - if (crypto_stream_blocked_) { - return true; // If the crypto stream is blocked, all other streams yield. - } - if (id == kHeadersStreamId) { - return false; // The crypto stream isn't blocked so headers won't yield. + if (register_static_streams_) { + for (const auto& stream : static_streams_) { + if (stream.first == id) { + // Static streams should never yield to data streams, or to lower + // priority static stream. + return false; + } + if (stream.second) { + return true; // All data streams yield to static streams. + } + } + } else { + if (id == kCryptoStreamId) { + return false; // The crypto stream yields to none. + } + if (crypto_stream_blocked_) { + return true; // If the crypto stream is blocked, all other streams + // yield. + } + if (id == kHeadersStreamId) { + return false; // The crypto stream isn't blocked so headers won't + // yield. + } + if (headers_stream_blocked_) { + return true; // All data streams yield to the headers stream. + } } - if (headers_stream_blocked_) { - return true; // All data streams yield to the headers stream. - } - return priority_write_scheduler_.ShouldYield(id); } // Pops the highest priorty stream, special casing crypto and headers streams. // Latches the most recently popped data stream for batch writing purposes. QuicStreamId PopFront() { - if (crypto_stream_blocked_) { - crypto_stream_blocked_ = false; - return kCryptoStreamId; - } - - if (headers_stream_blocked_) { - headers_stream_blocked_ = false; - return kHeadersStreamId; + if (register_static_streams_) { + for (auto& stream : static_streams_) { + if (stream.second) { + stream.second = false; + return stream.first; + } + } + } else { + if (crypto_stream_blocked_) { + crypto_stream_blocked_ = false; + return kCryptoStreamId; + } + + if (headers_stream_blocked_) { + headers_stream_blocked_ = false; + return kHeadersStreamId; + } } const auto id_and_precedence = @@ -97,16 +141,34 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList { return id; } - void RegisterStream(QuicStreamId stream_id, SpdyPriority priority) { + void RegisterStream(QuicStreamId stream_id, + bool is_static_stream, + SpdyPriority priority) { + if (register_static_streams_ && is_static_stream) { + DCHECK(!priority_write_scheduler_.StreamRegistered(stream_id)); + DCHECK(!QuicContainsKey(static_streams_, stream_id)); + DCHECK(static_streams_.empty() || + stream_id > static_streams_.back().first) + << "stream_id: " << stream_id + << " last static stream: " << static_streams_.back().first; + static_streams_[stream_id] = false; + return; + } + DCHECK(!priority_write_scheduler_.StreamRegistered(stream_id)); priority_write_scheduler_.RegisterStream(stream_id, SpdyStreamPrecedence(priority)); } - void UnregisterStream(QuicStreamId stream_id) { + void UnregisterStream(QuicStreamId stream_id, bool is_static) { + if (register_static_streams_ && is_static) { + static_streams_.erase(stream_id); + return; + } priority_write_scheduler_.UnregisterStream(stream_id); } void UpdateStreamPriority(QuicStreamId stream_id, SpdyPriority new_priority) { + DCHECK(!QuicContainsKey(static_streams_, stream_id)); priority_write_scheduler_.UpdateStreamPrecedence( stream_id, SpdyStreamPrecedence(new_priority)); } @@ -125,16 +187,24 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList { // the list for its priority level. // Headers and crypto streams are special cased to always resume first. void AddStream(QuicStreamId stream_id) { - if (stream_id == kCryptoStreamId) { - // TODO(avd) Add DCHECK(!crypto_stream_blocked_) - crypto_stream_blocked_ = true; - return; - } - - if (stream_id == kHeadersStreamId) { - // TODO(avd) Add DCHECK(!headers_stream_blocked_); - headers_stream_blocked_ = true; - return; + if (register_static_streams_) { + auto it = static_streams_.find(stream_id); + if (it != static_streams_.end()) { + it->second = true; + return; + } + } else { + if (stream_id == kCryptoStreamId) { + // TODO(avd) Add DCHECK(!crypto_stream_blocked_) + crypto_stream_blocked_ = true; + return; + } + + if (stream_id == kHeadersStreamId) { + // TODO(avd) Add DCHECK(!headers_stream_blocked_); + headers_stream_blocked_ = true; + return; + } } bool push_front = stream_id == batch_write_stream_id_[last_priority_popped_] && @@ -145,19 +215,25 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList { // This function is used for debugging and test only. Returns true if stream // with |stream_id| is write blocked. bool IsStreamBlocked(QuicStreamId stream_id) const { - if (stream_id == kCryptoStreamId) { - return crypto_stream_blocked_; - } - - if (stream_id == kHeadersStreamId) { - return headers_stream_blocked_; + if (register_static_streams_) { + auto it = static_streams_.find(stream_id); + if (it != static_streams_.end()) { + return it->second; + } + } else { + if (stream_id == kCryptoStreamId) { + return crypto_stream_blocked_; + } + + if (stream_id == kHeadersStreamId) { + return headers_stream_blocked_; + } } return priority_write_scheduler_.IsStreamReady(stream_id); } - bool crypto_stream_blocked() const { return crypto_stream_blocked_; } - bool headers_stream_blocked() const { return headers_stream_blocked_; } + bool register_static_streams() const { return register_static_streams_; } private: QuicPriorityWriteScheduler priority_write_scheduler_; @@ -177,6 +253,10 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList { bool crypto_stream_blocked_; bool headers_stream_blocked_; + // Latched value of quic_reloadable_flag_quic_register_static_streams. + const bool register_static_streams_; + QuicLinkedHashMapImpl<QuicStreamId, bool> static_streams_; + DISALLOW_COPY_AND_ASSIGN(QuicWriteBlockedList); }; diff --git a/chromium/net/quic/core/quic_write_blocked_list_test.cc b/chromium/net/quic/core/quic_write_blocked_list_test.cc index 91d0313b3ff..44da95eeb37 100644 --- a/chromium/net/quic/core/quic_write_blocked_list_test.cc +++ b/chromium/net/quic/core/quic_write_blocked_list_test.cc @@ -7,25 +7,27 @@ #include "net/quic/platform/api/quic_test.h" #include "net/quic/test_tools/quic_test_utils.h" -using net::kV3LowestPriority; -using net::kV3HighestPriority; +// using kV3HighestPriority; +// using kV3LowestPriority; namespace net { namespace test { namespace { -class QuicWriteBlockedListTest : public QuicTest {}; +class QuicWriteBlockedListTest : public QuicTestWithParam<bool> {}; -TEST_F(QuicWriteBlockedListTest, PriorityOrder) { - QuicWriteBlockedList write_blocked_list; +INSTANTIATE_TEST_CASE_P(Tests, QuicWriteBlockedListTest, testing::Bool()); + +TEST_P(QuicWriteBlockedListTest, PriorityOrder) { + QuicWriteBlockedList write_blocked_list(GetParam()); // Mark streams blocked in roughly reverse priority order, and // verify that streams are sorted. - write_blocked_list.RegisterStream(40, kV3LowestPriority); - write_blocked_list.RegisterStream(23, kV3HighestPriority); - write_blocked_list.RegisterStream(17, kV3HighestPriority); - write_blocked_list.RegisterStream(kHeadersStreamId, kV3HighestPriority); - write_blocked_list.RegisterStream(kCryptoStreamId, kV3HighestPriority); + write_blocked_list.RegisterStream(40, false, kV3LowestPriority); + write_blocked_list.RegisterStream(23, false, kV3HighestPriority); + write_blocked_list.RegisterStream(17, false, kV3HighestPriority); + write_blocked_list.RegisterStream(kCryptoStreamId, true, kV3HighestPriority); + write_blocked_list.RegisterStream(kHeadersStreamId, true, kV3HighestPriority); write_blocked_list.AddStream(40); EXPECT_TRUE(write_blocked_list.IsStreamBlocked(40)); @@ -39,13 +41,16 @@ TEST_F(QuicWriteBlockedListTest, PriorityOrder) { EXPECT_TRUE(write_blocked_list.IsStreamBlocked(kCryptoStreamId)); EXPECT_EQ(5u, write_blocked_list.NumBlockedStreams()); - EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream()); + EXPECT_TRUE(write_blocked_list.HasWriteBlockedSpecialStream()); + EXPECT_EQ(2u, write_blocked_list.NumBlockedSpecialStreams()); EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams()); // The Crypto stream is highest priority. EXPECT_EQ(kCryptoStreamId, write_blocked_list.PopFront()); + EXPECT_EQ(1u, write_blocked_list.NumBlockedSpecialStreams()); EXPECT_FALSE(write_blocked_list.IsStreamBlocked(kCryptoStreamId)); // Followed by the Headers stream. EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront()); + EXPECT_EQ(0u, write_blocked_list.NumBlockedSpecialStreams()); EXPECT_FALSE(write_blocked_list.IsStreamBlocked(kHeadersStreamId)); // Streams with same priority are popped in the order they were inserted. EXPECT_EQ(23u, write_blocked_list.PopFront()); @@ -57,61 +62,61 @@ TEST_F(QuicWriteBlockedListTest, PriorityOrder) { EXPECT_FALSE(write_blocked_list.IsStreamBlocked(40)); EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams()); - EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream()); + EXPECT_FALSE(write_blocked_list.HasWriteBlockedSpecialStream()); EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams()); } -TEST_F(QuicWriteBlockedListTest, CryptoStream) { - QuicWriteBlockedList write_blocked_list; - write_blocked_list.RegisterStream(kCryptoStreamId, kV3HighestPriority); +TEST_P(QuicWriteBlockedListTest, CryptoStream) { + QuicWriteBlockedList write_blocked_list(GetParam()); + write_blocked_list.RegisterStream(kCryptoStreamId, true, kV3HighestPriority); write_blocked_list.AddStream(kCryptoStreamId); EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams()); - EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream()); + EXPECT_TRUE(write_blocked_list.HasWriteBlockedSpecialStream()); EXPECT_EQ(kCryptoStreamId, write_blocked_list.PopFront()); EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams()); - EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream()); + EXPECT_FALSE(write_blocked_list.HasWriteBlockedSpecialStream()); } -TEST_F(QuicWriteBlockedListTest, HeadersStream) { - QuicWriteBlockedList write_blocked_list; - write_blocked_list.RegisterStream(kHeadersStreamId, kV3HighestPriority); +TEST_P(QuicWriteBlockedListTest, HeadersStream) { + QuicWriteBlockedList write_blocked_list(GetParam()); + write_blocked_list.RegisterStream(kHeadersStreamId, true, kV3HighestPriority); write_blocked_list.AddStream(kHeadersStreamId); EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams()); - EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream()); + EXPECT_TRUE(write_blocked_list.HasWriteBlockedSpecialStream()); EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront()); EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams()); - EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream()); + EXPECT_FALSE(write_blocked_list.HasWriteBlockedSpecialStream()); } -TEST_F(QuicWriteBlockedListTest, VerifyHeadersStream) { - QuicWriteBlockedList write_blocked_list; - write_blocked_list.RegisterStream(5, kV3HighestPriority); - write_blocked_list.RegisterStream(kHeadersStreamId, kV3HighestPriority); +TEST_P(QuicWriteBlockedListTest, VerifyHeadersStream) { + QuicWriteBlockedList write_blocked_list(GetParam()); + write_blocked_list.RegisterStream(5, false, kV3HighestPriority); + write_blocked_list.RegisterStream(kHeadersStreamId, true, kV3HighestPriority); write_blocked_list.AddStream(5); write_blocked_list.AddStream(kHeadersStreamId); EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams()); - EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream()); + EXPECT_TRUE(write_blocked_list.HasWriteBlockedSpecialStream()); EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams()); // In newer QUIC versions, there is a headers stream which is // higher priority than data streams. EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront()); EXPECT_EQ(5u, write_blocked_list.PopFront()); EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams()); - EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream()); + EXPECT_FALSE(write_blocked_list.HasWriteBlockedSpecialStream()); EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams()); } -TEST_F(QuicWriteBlockedListTest, NoDuplicateEntries) { +TEST_P(QuicWriteBlockedListTest, NoDuplicateEntries) { // Test that QuicWriteBlockedList doesn't allow duplicate entries. - QuicWriteBlockedList write_blocked_list; + QuicWriteBlockedList write_blocked_list(GetParam()); // Try to add a stream to the write blocked list multiple times at the same // priority. const QuicStreamId kBlockedId = kHeadersStreamId + 2; - write_blocked_list.RegisterStream(kBlockedId, kV3HighestPriority); + write_blocked_list.RegisterStream(kBlockedId, false, kV3HighestPriority); write_blocked_list.AddStream(kBlockedId); write_blocked_list.AddStream(kBlockedId); write_blocked_list.AddStream(kBlockedId); @@ -126,15 +131,15 @@ TEST_F(QuicWriteBlockedListTest, NoDuplicateEntries) { EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams()); } -TEST_F(QuicWriteBlockedListTest, BatchingWrites) { - QuicWriteBlockedList write_blocked_list; +TEST_P(QuicWriteBlockedListTest, BatchingWrites) { + QuicWriteBlockedList write_blocked_list(GetParam()); const QuicStreamId id1 = kHeadersStreamId + 2; const QuicStreamId id2 = id1 + 2; const QuicStreamId id3 = id2 + 2; - write_blocked_list.RegisterStream(id1, kV3LowestPriority); - write_blocked_list.RegisterStream(id2, kV3LowestPriority); - write_blocked_list.RegisterStream(id3, kV3HighestPriority); + write_blocked_list.RegisterStream(id1, false, kV3LowestPriority); + write_blocked_list.RegisterStream(id2, false, kV3LowestPriority); + write_blocked_list.RegisterStream(id3, false, kV3HighestPriority); write_blocked_list.AddStream(id1); write_blocked_list.AddStream(id2); @@ -179,16 +184,16 @@ TEST_F(QuicWriteBlockedListTest, BatchingWrites) { EXPECT_EQ(id1, write_blocked_list.PopFront()); } -TEST_F(QuicWriteBlockedListTest, Ceding) { - QuicWriteBlockedList write_blocked_list; +TEST_P(QuicWriteBlockedListTest, Ceding) { + QuicWriteBlockedList write_blocked_list(GetParam()); - write_blocked_list.RegisterStream(15, kV3HighestPriority); - write_blocked_list.RegisterStream(16, kV3HighestPriority); - write_blocked_list.RegisterStream(5, 5); - write_blocked_list.RegisterStream(4, 5); - write_blocked_list.RegisterStream(7, 7); - write_blocked_list.RegisterStream(kHeadersStreamId, kV3HighestPriority); - write_blocked_list.RegisterStream(kCryptoStreamId, kV3HighestPriority); + write_blocked_list.RegisterStream(15, false, kV3HighestPriority); + write_blocked_list.RegisterStream(16, false, kV3HighestPriority); + write_blocked_list.RegisterStream(5, false, 5); + write_blocked_list.RegisterStream(4, false, 5); + write_blocked_list.RegisterStream(7, false, 7); + write_blocked_list.RegisterStream(kCryptoStreamId, true, kV3HighestPriority); + write_blocked_list.RegisterStream(kHeadersStreamId, true, kV3HighestPriority); // When nothing is on the list, nothing yields. EXPECT_FALSE(write_blocked_list.ShouldYield(5)); diff --git a/chromium/net/quic/core/tls_client_handshaker.cc b/chromium/net/quic/core/tls_client_handshaker.cc index 76bf14622ff..eb5c40d5985 100644 --- a/chromium/net/quic/core/tls_client_handshaker.cc +++ b/chromium/net/quic/core/tls_client_handshaker.cc @@ -60,6 +60,13 @@ bssl::UniquePtr<SSL_CTX> TlsClientHandshaker::CreateSslCtx() { } bool TlsClientHandshaker::CryptoConnect() { + CrypterPair crypters; + CryptoUtils::CreateTlsInitialCrypters(Perspective::IS_CLIENT, + session()->connection_id(), &crypters); + session()->connection()->SetEncrypter(ENCRYPTION_NONE, + std::move(crypters.encrypter)); + session()->connection()->SetDecrypter(ENCRYPTION_NONE, + std::move(crypters.decrypter)); state_ = STATE_HANDSHAKE_RUNNING; // Configure certificate verification. // TODO(nharper): This only verifies certs on initial connection, not on @@ -180,16 +187,21 @@ void TlsClientHandshaker::FinishHandshake() { } QUIC_LOG(INFO) << "Client: setting crypters"; - QuicEncrypter* initial_encrypter = CreateEncrypter(client_secret); - session()->connection()->SetEncrypter(ENCRYPTION_INITIAL, initial_encrypter); - QuicEncrypter* encrypter = CreateEncrypter(client_secret); - session()->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE, encrypter); - - QuicDecrypter* initial_decrypter = CreateDecrypter(server_secret); - session()->connection()->SetDecrypter(ENCRYPTION_INITIAL, initial_decrypter); - QuicDecrypter* decrypter = CreateDecrypter(server_secret); + std::unique_ptr<QuicEncrypter> initial_encrypter = + CreateEncrypter(client_secret); + session()->connection()->SetEncrypter(ENCRYPTION_INITIAL, + std::move(initial_encrypter)); + std::unique_ptr<QuicEncrypter> encrypter = CreateEncrypter(client_secret); + session()->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE, + std::move(encrypter)); + + std::unique_ptr<QuicDecrypter> initial_decrypter = + CreateDecrypter(server_secret); + session()->connection()->SetDecrypter(ENCRYPTION_INITIAL, + std::move(initial_decrypter)); + std::unique_ptr<QuicDecrypter> decrypter = CreateDecrypter(server_secret); session()->connection()->SetAlternativeDecrypter(ENCRYPTION_FORWARD_SECURE, - decrypter, true); + std::move(decrypter), true); session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); diff --git a/chromium/net/quic/core/tls_handshaker.cc b/chromium/net/quic/core/tls_handshaker.cc index 06b95ec5090..032dece493f 100644 --- a/chromium/net/quic/core/tls_handshaker.cc +++ b/chromium/net/quic/core/tls_handshaker.cc @@ -7,8 +7,8 @@ #include "base/no_destructor.h" #include "net/quic/core/quic_crypto_stream.h" #include "net/quic/core/tls_client_handshaker.h" -#include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_arraysize.h" +#include "net/quic/platform/api/quic_singleton.h" namespace net { @@ -23,9 +23,8 @@ namespace { class SslIndexSingleton { public: - static const SslIndexSingleton* GetInstance() { - static const base::NoDestructor<SslIndexSingleton> instance; - return instance.get(); + static SslIndexSingleton* GetInstance() { + return QuicSingleton<SslIndexSingleton>::get(); } int HandshakerIndex() const { return ssl_ex_data_index_handshaker_; } @@ -37,7 +36,7 @@ class SslIndexSingleton { CHECK_LE(0, ssl_ex_data_index_handshaker_); } - friend class base::NoDestructor<SslIndexSingleton>; + friend QuicSingletonFriend<SslIndexSingleton>; int ssl_ex_data_index_handshaker_; @@ -70,37 +69,21 @@ bool TlsHandshaker::DeriveSecrets(std::vector<uint8_t>* client_secret_out, QUIC_ARRAYSIZE(kServerLabel) - 1, nullptr, 0, 0) == 1); } -namespace { - -template <class QuicCrypter> -void SetKeyAndIV(const EVP_MD* prf, - const std::vector<uint8_t>& pp_secret, - QuicCrypter* crypter) { - std::vector<uint8_t> key = CryptoUtils::HkdfExpandLabel( - prf, pp_secret, "key", crypter->GetKeySize()); - std::vector<uint8_t> iv = - CryptoUtils::HkdfExpandLabel(prf, pp_secret, "iv", crypter->GetIVSize()); - crypter->SetKey( - QuicStringPiece(reinterpret_cast<char*>(key.data()), key.size())); - crypter->SetIV( - QuicStringPiece(reinterpret_cast<char*>(iv.data()), iv.size())); -} - -} // namespace - -QuicEncrypter* TlsHandshaker::CreateEncrypter( +std::unique_ptr<QuicEncrypter> TlsHandshaker::CreateEncrypter( const std::vector<uint8_t>& pp_secret) { - QuicEncrypter* encrypter = QuicEncrypter::CreateFromCipherSuite( - SSL_CIPHER_get_id(SSL_get_current_cipher(ssl()))); - SetKeyAndIV(Prf(), pp_secret, encrypter); + std::unique_ptr<QuicEncrypter> encrypter = + QuicEncrypter::CreateFromCipherSuite( + SSL_CIPHER_get_id(SSL_get_current_cipher(ssl()))); + CryptoUtils::SetKeyAndIV(Prf(), pp_secret, encrypter.get()); return encrypter; } -QuicDecrypter* TlsHandshaker::CreateDecrypter( +std::unique_ptr<QuicDecrypter> TlsHandshaker::CreateDecrypter( const std::vector<uint8_t>& pp_secret) { - QuicDecrypter* decrypter = QuicDecrypter::CreateFromCipherSuite( - SSL_CIPHER_get_id(SSL_get_current_cipher(ssl()))); - SetKeyAndIV(Prf(), pp_secret, decrypter); + std::unique_ptr<QuicDecrypter> decrypter = + QuicDecrypter::CreateFromCipherSuite( + SSL_CIPHER_get_id(SSL_get_current_cipher(ssl()))); + CryptoUtils::SetKeyAndIV(Prf(), pp_secret, decrypter.get()); return decrypter; } diff --git a/chromium/net/quic/core/tls_handshaker.h b/chromium/net/quic/core/tls_handshaker.h index c542be36aff..963f129f953 100644 --- a/chromium/net/quic/core/tls_handshaker.h +++ b/chromium/net/quic/core/tls_handshaker.h @@ -65,8 +65,10 @@ class QUIC_EXPORT_PRIVATE TlsHandshaker : public QuicTlsAdapter::Visitor { bool DeriveSecrets(std::vector<uint8_t>* client_secret_out, std::vector<uint8_t>* server_secret_out); - QuicEncrypter* CreateEncrypter(const std::vector<uint8_t>& pp_secret); - QuicDecrypter* CreateDecrypter(const std::vector<uint8_t>& pp_secret); + std::unique_ptr<QuicEncrypter> CreateEncrypter( + const std::vector<uint8_t>& pp_secret); + std::unique_ptr<QuicDecrypter> CreateDecrypter( + const std::vector<uint8_t>& pp_secret); SSL* ssl() { return ssl_.get(); } QuicCryptoStream* stream() { return stream_; } diff --git a/chromium/net/quic/core/tls_handshaker_test.cc b/chromium/net/quic/core/tls_handshaker_test.cc index 27821c30999..de84861321d 100644 --- a/chromium/net/quic/core/tls_handshaker_test.cc +++ b/chromium/net/quic/core/tls_handshaker_test.cc @@ -251,13 +251,15 @@ class TlsHandshakerTest : public QuicTest { server_conn_(new MockQuicConnection(&conn_helper_, &alarm_factory_, Perspective::IS_SERVER)), - client_session_(client_conn_), - server_session_(server_conn_), - client_stream_(&client_session_), - server_stream_( - new TestQuicCryptoServerStream(&server_session_, &proof_source_)) { - EXPECT_FALSE(client_stream_.encryption_established()); - EXPECT_FALSE(client_stream_.handshake_confirmed()); + client_session_(client_conn_, /*create_mock_crypto_stream=*/false), + server_session_(server_conn_, /*create_mock_crypto_stream=*/false) { + client_stream_ = new TestQuicCryptoClientStream(&client_session_); + client_session_.SetCryptoStream(client_stream_); + server_stream_ = + new TestQuicCryptoServerStream(&server_session_, &proof_source_); + server_session_.SetCryptoStream(server_stream_); + EXPECT_FALSE(client_stream_->encryption_established()); + EXPECT_FALSE(client_stream_->handshake_confirmed()); EXPECT_FALSE(server_stream_->encryption_established()); EXPECT_FALSE(server_stream_->handshake_confirmed()); } @@ -269,19 +271,19 @@ class TlsHandshakerTest : public QuicTest { MockQuicSession client_session_; MockQuicSession server_session_; - TestQuicCryptoClientStream client_stream_; FakeProofSource proof_source_; - std::unique_ptr<TestQuicCryptoServerStream> server_stream_; + TestQuicCryptoClientStream* client_stream_; + TestQuicCryptoServerStream* server_stream_; }; TEST_F(TlsHandshakerTest, CryptoHandshake) { EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - client_stream_.CryptoConnect(); - MoveStreamFrames(&client_stream_, server_stream_.get()); + client_stream_->CryptoConnect(); + MoveStreamFrames(client_stream_, server_stream_); - EXPECT_TRUE(client_stream_.handshake_confirmed()); - EXPECT_TRUE(client_stream_.encryption_established()); + EXPECT_TRUE(client_stream_->handshake_confirmed()); + EXPECT_TRUE(client_stream_->encryption_established()); EXPECT_TRUE(server_stream_->handshake_confirmed()); EXPECT_TRUE(server_stream_->encryption_established()); } @@ -295,16 +297,16 @@ TEST_F(TlsHandshakerTest, HandshakeWithAsyncProofSource) { proof_source->Activate(); // Start handshake. - client_stream_.CryptoConnect(); - MoveStreamFrames(&client_stream_, server_stream_.get()); + client_stream_->CryptoConnect(); + MoveStreamFrames(client_stream_, server_stream_); ASSERT_EQ(proof_source->NumPendingCallbacks(), 1); proof_source->InvokePendingCallback(0); - MoveStreamFrames(&client_stream_, server_stream_.get()); + MoveStreamFrames(client_stream_, server_stream_); - EXPECT_TRUE(client_stream_.handshake_confirmed()); - EXPECT_TRUE(client_stream_.encryption_established()); + EXPECT_TRUE(client_stream_->handshake_confirmed()); + EXPECT_TRUE(client_stream_->encryption_established()); EXPECT_TRUE(server_stream_->handshake_confirmed()); EXPECT_TRUE(server_stream_->encryption_established()); } @@ -318,11 +320,11 @@ TEST_F(TlsHandshakerTest, CancelPendingProofSource) { proof_source->Activate(); // Start handshake. - client_stream_.CryptoConnect(); - MoveStreamFrames(&client_stream_, server_stream_.get()); + client_stream_->CryptoConnect(); + MoveStreamFrames(client_stream_, server_stream_); ASSERT_EQ(proof_source->NumPendingCallbacks(), 1); - server_stream_.reset(); + server_stream_ = nullptr; proof_source->InvokePendingCallback(0); } @@ -332,27 +334,27 @@ TEST_F(TlsHandshakerTest, HandshakeWithAsyncProofVerifier) { EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); // Enable FakeProofVerifier to capture call to VerifyCertChain and run it // asynchronously. - FakeProofVerifier* proof_verifier = client_stream_.GetFakeProofVerifier(); + FakeProofVerifier* proof_verifier = client_stream_->GetFakeProofVerifier(); proof_verifier->Activate(); // Start handshake. - client_stream_.CryptoConnect(); - MoveStreamFrames(&client_stream_, server_stream_.get()); + client_stream_->CryptoConnect(); + MoveStreamFrames(client_stream_, server_stream_); ASSERT_EQ(proof_verifier->NumPendingCallbacks(), 1u); proof_verifier->InvokePendingCallback(0); - MoveStreamFrames(&client_stream_, server_stream_.get()); + MoveStreamFrames(client_stream_, server_stream_); - EXPECT_TRUE(client_stream_.handshake_confirmed()); - EXPECT_TRUE(client_stream_.encryption_established()); + EXPECT_TRUE(client_stream_->handshake_confirmed()); + EXPECT_TRUE(client_stream_->encryption_established()); EXPECT_TRUE(server_stream_->handshake_confirmed()); EXPECT_TRUE(server_stream_->encryption_established()); } TEST_F(TlsHandshakerTest, ClientConnectionClosedOnTlsAlert) { // Have client send ClientHello. - client_stream_.CryptoConnect(); + client_stream_->CryptoConnect(); EXPECT_CALL(*client_conn_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); // Send fake "internal_error" fatal TLS alert from server to client. @@ -366,11 +368,11 @@ TEST_F(TlsHandshakerTest, ClientConnectionClosedOnTlsAlert) { 80, // AlertDescription internal_error }; QuicStreamFrame alert(kCryptoStreamId, false, - client_stream_.stream_bytes_read(), + client_stream_->stream_bytes_read(), QuicStringPiece(alert_msg, QUIC_ARRAYSIZE(alert_msg))); - client_stream_.OnStreamFrame(alert); + client_stream_->OnStreamFrame(alert); - EXPECT_FALSE(client_stream_.handshake_confirmed()); + EXPECT_FALSE(client_stream_->handshake_confirmed()); } TEST_F(TlsHandshakerTest, ServerConnectionClosedOnTlsAlert) { diff --git a/chromium/net/quic/core/tls_server_handshaker.cc b/chromium/net/quic/core/tls_server_handshaker.cc index f0f6a4e5fbc..17db9f02f47 100644 --- a/chromium/net/quic/core/tls_server_handshaker.cc +++ b/chromium/net/quic/core/tls_server_handshaker.cc @@ -60,6 +60,13 @@ TlsServerHandshaker::TlsServerHandshaker(QuicCryptoStream* stream, : TlsHandshaker(stream, session, ssl_ctx), proof_source_(proof_source), crypto_negotiated_params_(new QuicCryptoNegotiatedParameters) { + CrypterPair crypters; + CryptoUtils::CreateTlsInitialCrypters(Perspective::IS_SERVER, + session->connection_id(), &crypters); + session->connection()->SetEncrypter(ENCRYPTION_NONE, + std::move(crypters.encrypter)); + session->connection()->SetDecrypter(ENCRYPTION_NONE, + std::move(crypters.decrypter)); // Set callback to provide SNI. // SSL_CTX_set_tlsext_servername_callback(ssl_ctx, SelectCertificateCallback); @@ -195,16 +202,21 @@ void TlsServerHandshaker::FinishHandshake() { } QUIC_LOG(INFO) << "Server: setting crypters"; - QuicEncrypter* initial_encrypter = CreateEncrypter(server_secret); - session()->connection()->SetEncrypter(ENCRYPTION_INITIAL, initial_encrypter); - QuicEncrypter* encrypter = CreateEncrypter(server_secret); - session()->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE, encrypter); - - QuicDecrypter* initial_decrypter = CreateDecrypter(client_secret); - session()->connection()->SetDecrypter(ENCRYPTION_INITIAL, initial_decrypter); - QuicDecrypter* decrypter = CreateDecrypter(client_secret); + std::unique_ptr<QuicEncrypter> initial_encrypter = + CreateEncrypter(server_secret); + session()->connection()->SetEncrypter(ENCRYPTION_INITIAL, + std::move(initial_encrypter)); + std::unique_ptr<QuicEncrypter> encrypter = CreateEncrypter(server_secret); + session()->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE, + std::move(encrypter)); + + std::unique_ptr<QuicDecrypter> initial_decrypter = + CreateDecrypter(client_secret); + session()->connection()->SetDecrypter(ENCRYPTION_INITIAL, + std::move(initial_decrypter)); + std::unique_ptr<QuicDecrypter> decrypter = CreateDecrypter(client_secret); session()->connection()->SetAlternativeDecrypter(ENCRYPTION_FORWARD_SECURE, - decrypter, true); + std::move(decrypter), true); session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); diff --git a/chromium/net/quic/http/decoder/quic_http_frame_decoder_adapter.cc b/chromium/net/quic/http/decoder/quic_http_frame_decoder_adapter.cc index 7bbfc68e9c3..6f70e0c9c71 100644 --- a/chromium/net/quic/http/decoder/quic_http_frame_decoder_adapter.cc +++ b/chromium/net/quic/http/decoder/quic_http_frame_decoder_adapter.cc @@ -22,6 +22,7 @@ #include "net/quic/http/decoder/quic_http_frame_decoder_listener.h" #include "net/quic/http/quic_http_constants.h" #include "net/quic/http/quic_http_structures.h" +#include "net/quic/platform/api/quic_flags.h" #include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/platform/api/quic_string_utils.h" #include "net/spdy/core/hpack/hpack_decoder_adapter.h" @@ -450,7 +451,13 @@ void QuicHttpDecoderAdapter::OnSetting( } return; } - visitor()->OnSetting(setting_id, setting_fields.value); + // TODO(quic): Consider whether to add support for handling unknown SETTINGS + // IDs, which currently cause a connection close. + if (GetQuicRestartFlag(http2_propagate_unknown_settings)) { + visitor()->OnSetting(setting_id, setting_fields.value); + } else { + visitor()->OnSettingOld(setting_id, setting_fields.value); + } } void QuicHttpDecoderAdapter::OnSettingsEnd() { diff --git a/chromium/net/quic/http/quic_http_structures.h b/chromium/net/quic/http/quic_http_structures.h index 10c7d9e0d44..eb3f7a91ecb 100644 --- a/chromium/net/quic/http/quic_http_structures.h +++ b/chromium/net/quic/http/quic_http_structures.h @@ -249,7 +249,6 @@ QUIC_EXPORT_PRIVATE std::ostream& operator<<( struct QuicHttpPingFields { static constexpr size_t EncodedSize() { return 8; } - // TODO(jamessynge): Rename opaque_bytes to opaque_bytes. uint8_t opaque_bytes[8]; }; diff --git a/chromium/net/quic/http/tools/quic_http_random_util.cc b/chromium/net/quic/http/tools/quic_http_random_util.cc index 7e7b259ba8d..afe4d064ce3 100644 --- a/chromium/net/quic/http/tools/quic_http_random_util.cc +++ b/chromium/net/quic/http/tools/quic_http_random_util.cc @@ -51,22 +51,6 @@ size_t GenerateUniformInRange(size_t lo, size_t hi, QuicTestRandomBase* rng) { return lo + rng->Rand64() % (hi - lo); } -// Here "word" means something that starts with a lower-case letter, and has -// zero or more additional characters that are numbers or lower-case letters. -QuicString GenerateQuicHttpHeaderName(size_t len, QuicTestRandomBase* rng) { - QuicStringPiece alpha_lc = "abcdefghijklmnopqrstuvwxyz"; - // If the name is short, just make it one word. - if (len < 8) { - return RandomString(rng, len, alpha_lc); - } - // If the name is longer, ensure it starts with a word, and after that may - // have any character in alphanumdash_lc. 4 is arbitrary, could be as low - // as 1. - QuicStringPiece alphanumdash_lc = "abcdefghijklmnopqrstuvwxyz0123456789-"; - return RandomString(rng, 4, alpha_lc) + - RandomString(rng, len - 4, alphanumdash_lc); -} - QuicString GenerateWebSafeString(size_t len, QuicTestRandomBase* rng) { return RandomString(rng, len, kWebsafe64); } diff --git a/chromium/net/quic/http/tools/quic_http_random_util.h b/chromium/net/quic/http/tools/quic_http_random_util.h index da0245a4da5..1d6788a6ffd 100644 --- a/chromium/net/quic/http/tools/quic_http_random_util.h +++ b/chromium/net/quic/http/tools/quic_http_random_util.h @@ -16,15 +16,10 @@ namespace test { // Returns a random integer in the range [lo, hi). size_t GenerateUniformInRange(size_t lo, size_t hi, QuicTestRandomBase* rng); -// Generate a std::string with the allowed character set for HTTP/2 / -// HPQUIC_HTTP_ACK header names. -QuicString GenerateQuicHttpHeaderName(size_t len, QuicTestRandomBase* rng); - -// Generate a std::string with the web-safe std::string character set of -// specified len. +// Generate a string with the web-safe string character set of specified len. QuicString GenerateWebSafeString(size_t len, QuicTestRandomBase* rng); -// Generate a std::string with the web-safe std::string character set of length +// Generate a string with the web-safe string character set of length // [lo, hi). QuicString GenerateWebSafeString(size_t lo, size_t hi, QuicTestRandomBase* rng); diff --git a/chromium/net/quic/platform/api/quic_logging.h b/chromium/net/quic/platform/api/quic_logging.h index 14b1bffa3d6..798bfbf8252 100644 --- a/chromium/net/quic/platform/api/quic_logging.h +++ b/chromium/net/quic/platform/api/quic_logging.h @@ -13,6 +13,8 @@ // they would simply be translated to LOG. #define QUIC_DVLOG(verbose_level) QUIC_DVLOG_IMPL(verbose_level) +#define QUIC_DVLOG_IF(verbose_level, condition) \ + QUIC_DVLOG_IF_IMPL(verbose_level, condition) #define QUIC_DLOG(severity) QUIC_DLOG_IMPL(severity) #define QUIC_DLOG_IF(severity, condition) QUIC_DLOG_IF_IMPL(severity, condition) #define QUIC_VLOG(verbose_level) QUIC_VLOG_IMPL(verbose_level) diff --git a/chromium/net/quic/platform/api/quic_mem_slice.h b/chromium/net/quic/platform/api/quic_mem_slice.h index 11205af5c1d..ba0c03bb17a 100644 --- a/chromium/net/quic/platform/api/quic_mem_slice.h +++ b/chromium/net/quic/platform/api/quic_mem_slice.h @@ -41,6 +41,10 @@ class QUIC_EXPORT_PRIVATE QuicMemSlice { ~QuicMemSlice() = default; + // Release the underlying reference. Further access the memory will result in + // undefined behavior. + void Reset() { impl_.Reset(); } + // Returns a const char pointer to underlying data buffer. const char* data() const { return impl_.data(); } // Returns the length of underlying data buffer. diff --git a/chromium/net/quic/platform/api/quic_singleton.h b/chromium/net/quic/platform/api/quic_singleton.h new file mode 100644 index 00000000000..f9d393f8a89 --- /dev/null +++ b/chromium/net/quic/platform/api/quic_singleton.h @@ -0,0 +1,48 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_PLATFORM_API_QUIC_SINGLETON_H_ +#define NET_QUIC_PLATFORM_API_QUIC_SINGLETON_H_ + +#include "net/quic/platform/impl/quic_singleton_impl.h" + +namespace net { + +// Singleton utility. Example usage: +// +// In your header: +// #include "net/quic/platform/api/quic_singleton.h" +// class Foo { +// public: +// static Foo* GetInstance(); +// void Bar() { ... } +// private: +// Foo() { ... } +// friend net::QuicSingletonFriend<Foo>; +// }; +// +// In your source file: +// Foo* Foo::GetInstance() { +// return net::QuicSingleton<Foo>::get(); +// } +// +// To use the singleton: +// Foo::GetInstance()->Bar(); +// +// NOTE: The method accessing Singleton<T>::get() has to be named as GetInstance +// and it is important that Foo::GetInstance() is not inlined in the +// header. This makes sure that when source files from multiple targets include +// this header they don't end up with different copies of the inlined code +// creating multiple copies of the singleton. +template <typename T> +using QuicSingleton = QuicSingletonImpl<T>; + +// Type that a class using QuicSingleton must declare as a friend, in order for +// QuicSingleton to be able to access the class's private constructor. +template <typename T> +using QuicSingletonFriend = QuicSingletonFriendImpl<T>; + +} // namespace net + +#endif // NET_QUIC_PLATFORM_API_QUIC_SINGLETON_H_ diff --git a/chromium/net/quic/platform/api/quic_singleton_test.cc b/chromium/net/quic/platform/api/quic_singleton_test.cc new file mode 100644 index 00000000000..e6a2ec5e628 --- /dev/null +++ b/chromium/net/quic/platform/api/quic_singleton_test.cc @@ -0,0 +1,32 @@ +// Copyright (c) 2018 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/platform/api/quic_singleton.h" + +#include "net/quic/platform/api/quic_test.h" + +namespace net { +namespace test { +namespace { + +class Foo { + public: + static Foo* GetInstance() { return net::QuicSingleton<Foo>::get(); } + + private: + Foo() = default; + friend net::QuicSingletonFriend<Foo>; +}; + +class QuicSingletonTest : public QuicTest {}; + +TEST_F(QuicSingletonTest, Get) { + Foo* f1 = Foo::GetInstance(); + Foo* f2 = Foo::GetInstance(); + EXPECT_EQ(f1, f2); +} + +} // namespace +} // namespace test +} // namespace net diff --git a/chromium/net/quic/platform/api/quic_test.h b/chromium/net/quic/platform/api/quic_test.h index b976b452a52..ca0b71e6564 100644 --- a/chromium/net/quic/platform/api/quic_test.h +++ b/chromium/net/quic/platform/api/quic_test.h @@ -7,6 +7,8 @@ #include "net/quic/platform/impl/quic_test_impl.h" +using QuicFlagSaver = QuicFlagSaverImpl; + // Defines the base classes to be used in QUIC tests. using QuicTest = QuicTestImpl; template <class T> diff --git a/chromium/net/quic/platform/api/quic_uint128.h b/chromium/net/quic/platform/api/quic_uint128.h new file mode 100644 index 00000000000..afe252c3ba0 --- /dev/null +++ b/chromium/net/quic/platform/api/quic_uint128.h @@ -0,0 +1,19 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_PLATFORM_API_QUIC_UINT128_H_ +#define NET_QUIC_PLATFORM_API_QUIC_UINT128_H_ + +#include "net/quic/platform/impl/quic_uint128_impl.h" + +namespace net { + +using QuicUint128 = QuicUint128Impl; +#define MakeQuicUint128(hi, lo) MakeQuicUint128Impl(hi, lo); +#define QuicUint128Low64(x) QuicUint128Low64Impl(x); +#define QuicUint128High64(x) QuicUint128High64Impl(x); + +} // namespace net + +#endif // NET_QUIC_PLATFORM_API_QUIC_UINT128_H_ diff --git a/chromium/net/quic/platform/impl/quic_logging_impl.h b/chromium/net/quic/platform/impl/quic_logging_impl.h index 37aa990b365..fb9add316fb 100644 --- a/chromium/net/quic/platform/impl/quic_logging_impl.h +++ b/chromium/net/quic/platform/impl/quic_logging_impl.h @@ -42,6 +42,8 @@ #define QUIC_CHROMIUM_DLOG_IF_DFATAL(condition) DLOG_IF(DFATAL, condition) #define QUIC_DVLOG_IMPL(verbose_level) DVLOG(verbose_level) +#define QUIC_DVLOG_IF_IMPL(verbose_level, condition) \ + DVLOG_IF(verbose_level, condition) #if defined(OS_WIN) // wingdi.h defines ERROR to be 0. When we call QUIC_DLOG(ERROR), it gets diff --git a/chromium/net/quic/platform/impl/quic_mem_slice_impl.cc b/chromium/net/quic/platform/impl/quic_mem_slice_impl.cc index 5fdeb24a408..e82fcf1493c 100644 --- a/chromium/net/quic/platform/impl/quic_mem_slice_impl.cc +++ b/chromium/net/quic/platform/impl/quic_mem_slice_impl.cc @@ -34,6 +34,11 @@ QuicMemSliceImpl& QuicMemSliceImpl::operator=(QuicMemSliceImpl&& other) { QuicMemSliceImpl::~QuicMemSliceImpl() = default; +void QuicMemSliceImpl::Reset() { + io_buffer_ = nullptr; + length_ = 0; +} + const char* QuicMemSliceImpl::data() const { if (io_buffer_ == nullptr) { return nullptr; diff --git a/chromium/net/quic/platform/impl/quic_mem_slice_impl.h b/chromium/net/quic/platform/impl/quic_mem_slice_impl.h index 43b9aad460a..1acf9f7b3f9 100644 --- a/chromium/net/quic/platform/impl/quic_mem_slice_impl.h +++ b/chromium/net/quic/platform/impl/quic_mem_slice_impl.h @@ -34,6 +34,10 @@ class QUIC_EXPORT_PRIVATE QuicMemSliceImpl { ~QuicMemSliceImpl(); + // Release the underlying reference. Further access the memory will result in + // undefined behavior. + void Reset(); + // Returns a char pointer to underlying data buffer. const char* data() const; // Returns the length of underlying data buffer. diff --git a/chromium/net/quic/platform/impl/quic_singleton_impl.h b/chromium/net/quic/platform/impl/quic_singleton_impl.h new file mode 100644 index 00000000000..9c02071cc53 --- /dev/null +++ b/chromium/net/quic/platform/impl/quic_singleton_impl.h @@ -0,0 +1,20 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_PLATFORM_IMPL_QUIC_SINGLETON_IMPL_H_ +#define NET_QUIC_PLATFORM_IMPL_QUIC_SINGLETON_IMPL_H_ + +#include "base/memory/singleton.h" + +namespace net { + +template <typename T> +using QuicSingletonImpl = base::Singleton<T, base::DefaultSingletonTraits<T>>; + +template <typename T> +using QuicSingletonFriendImpl = base::DefaultSingletonTraits<T>; + +} // namespace net + +#endif // NET_QUIC_PLATFORM_IMPL_QUIC_SINGLETON_IMPL_H_ diff --git a/chromium/net/quic/platform/impl/quic_test_impl.cc b/chromium/net/quic/platform/impl/quic_test_impl.cc index dc1709b2856..6e22a9f5922 100644 --- a/chromium/net/quic/platform/impl/quic_test_impl.cc +++ b/chromium/net/quic/platform/impl/quic_test_impl.cc @@ -4,20 +4,14 @@ #include "net/quic/platform/impl/quic_test_impl.h" -#include "base/logging.h" -#include "net/quic/platform/api/quic_flags.h" - -QuicFlagSaver::QuicFlagSaver() { -#define QUIC_FLAG(type, flag, value) \ - CHECK_EQ(value, flag) \ - << "Flag set to an unexpected value. A prior test is likely " \ - << "setting a flag without using a QuicFlagSaver"; +QuicFlagSaverImpl::QuicFlagSaverImpl() { +#define QUIC_FLAG(type, flag, value) saved_##flag##_ = flag; #include "net/quic/core/quic_flags_list.h" #undef QUIC_FLAG } -QuicFlagSaver::~QuicFlagSaver() { -#define QUIC_FLAG(type, flag, value) flag = value; +QuicFlagSaverImpl::~QuicFlagSaverImpl() { +#define QUIC_FLAG(type, flag, value) flag = saved_##flag##_; #include "net/quic/core/quic_flags_list.h" #undef QUIC_FLAG } diff --git a/chromium/net/quic/platform/impl/quic_test_impl.h b/chromium/net/quic/platform/impl/quic_test_impl.h index 6be16527516..98ae8760cc2 100644 --- a/chromium/net/quic/platform/impl/quic_test_impl.h +++ b/chromium/net/quic/platform/impl/quic_test_impl.h @@ -5,26 +5,49 @@ #ifndef NET_QUIC_PLATFORM_IMPL_QUIC_TEST_IMPL_H_ #define NET_QUIC_PLATFORM_IMPL_QUIC_TEST_IMPL_H_ +#include "base/logging.h" +#include "net/quic/platform/api/quic_flags.h" #include "testing/gmock/include/gmock/gmock.h" // IWYU pragma: export #include "testing/gtest/include/gtest/gtest.h" // IWYU pragma: export -// When constructed, checks that all QUIC flags have their correct default -// values and when destructed, restores those values. -class QuicFlagSaver { +// When constructed, saves the current values of all QUIC flags. When +// destructed, restores all QUIC flags to the saved values. +class QuicFlagSaverImpl { public: - QuicFlagSaver(); - ~QuicFlagSaver(); + QuicFlagSaverImpl(); + ~QuicFlagSaverImpl(); + + private: +#define QUIC_FLAG(type, flag, value) type saved_##flag##_; +#include "net/quic/core/quic_flags_list.h" +#undef QUIC_FLAG +}; + +// Checks if all QUIC flags are on their default values on construction. +class QuicFlagChecker { + public: + QuicFlagChecker() { +#define QUIC_FLAG(type, flag, value) \ + CHECK_EQ(value, flag) \ + << "Flag set to an unexpected value. A prior test is likely " \ + << "setting a flag without using a QuicFlagSaver. Use QuicTest to " \ + "avoid this issue."; +#include "net/quic/core/quic_flags_list.h" +#undef QUIC_FLAG + } }; class QuicTestImpl : public ::testing::Test { private: - QuicFlagSaver flags_; // Save/restore all QUIC flag values. + QuicFlagChecker checker_; + QuicFlagSaverImpl saver_; // Save/restore all QUIC flag values. }; template <class T> class QuicTestWithParamImpl : public ::testing::TestWithParam<T> { private: - QuicFlagSaver flags_; // Save/restore all QUIC flag values. + QuicFlagChecker checker_; + QuicFlagSaverImpl saver_; // Save/restore all QUIC flag values. }; #endif // NET_QUIC_PLATFORM_IMPL_QUIC_TEST_IMPL_H_ diff --git a/chromium/net/quic/platform/impl/quic_uint128_impl.h b/chromium/net/quic/platform/impl/quic_uint128_impl.h new file mode 100644 index 00000000000..cad9a6eea7d --- /dev/null +++ b/chromium/net/quic/platform/impl/quic_uint128_impl.h @@ -0,0 +1,19 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_PLATFORM_IMPL_QUIC_UINT128_IMPL_H_ +#define NET_QUIC_PLATFORM_IMPL_QUIC_UINT128_IMPL_H_ + +#include "net/base/int128.h" + +namespace net { + +using QuicUint128Impl = uint128; +#define MakeQuicUint128Impl(hi, lo) MakeUint128(hi, lo) +#define QuicUint128Low64Impl(x) Uint128Low64(x); +#define QuicUint128High64Impl(x) Uint128High64(x); + +} // namespace net + +#endif // NET_QUIC_PLATFORM_IMPL_QUIC_UINT128_IMPL_H_ diff --git a/chromium/net/quic/quartc/quartc_factory.cc b/chromium/net/quic/quartc/quartc_factory.cc index 3e182fa99e1..68912accf47 100644 --- a/chromium/net/quic/quartc/quartc_factory.cc +++ b/chromium/net/quic/quartc/quartc_factory.cc @@ -106,6 +106,8 @@ QuartcFactory::~QuartcFactory() {} std::unique_ptr<QuartcSessionInterface> QuartcFactory::CreateQuartcSession( const QuartcSessionConfig& quartc_session_config) { DCHECK(quartc_session_config.packet_transport); + SetQuicReloadableFlag(quic_better_crypto_retransmission, true); + SetQuicReloadableFlag(quic_is_write_blocked, true); Perspective perspective = quartc_session_config.is_server ? Perspective::IS_SERVER @@ -121,6 +123,7 @@ std::unique_ptr<QuartcSessionInterface> QuartcFactory::CreateQuartcSession( // Note: These settings have no effect for Exoblaze builds since // SetQuicReloadableFlag() gets stubbed out. SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true); + SetQuicReloadableFlag(quic_unified_iw_options, true); for (const auto option : quartc_session_config.bbr_options) { switch (option) { case (QuartcBbrOptions::kSlowerStartup): @@ -141,6 +144,24 @@ std::unique_ptr<QuartcSessionInterface> QuartcFactory::CreateQuartcSession( case (QuartcBbrOptions::kFillUpLinkDuringProbing): quic_connection->set_fill_up_link_during_probing(true); break; + case (QuartcBbrOptions::kInitialWindow3): + copt.push_back(kIW03); + break; + case (QuartcBbrOptions::kInitialWindow10): + copt.push_back(kIW10); + break; + case (QuartcBbrOptions::kInitialWindow20): + copt.push_back(kIW20); + break; + case (QuartcBbrOptions::kInitialWindow50): + copt.push_back(kIW50); + break; + case (QuartcBbrOptions::kStartup1RTT): + copt.push_back(k1RTT); + break; + case (QuartcBbrOptions::kStartup2RTT): + copt.push_back(k2RTT); + break; } } } diff --git a/chromium/net/quic/quartc/quartc_factory_interface.h b/chromium/net/quic/quartc/quartc_factory_interface.h index 33dd6aa15ee..1007509ce45 100644 --- a/chromium/net/quic/quartc/quartc_factory_interface.h +++ b/chromium/net/quic/quartc/quartc_factory_interface.h @@ -37,6 +37,12 @@ enum class QuartcBbrOptions { // once. kFillUpLinkDuringProbing, // Sends probing retransmissions whenever we // become application limited. + kInitialWindow3, // Use a 3-packet initial congestion window. + kInitialWindow10, // Use a 10-packet initial congestion window. + kInitialWindow20, // Use a 20-packet initial congestion window. + kInitialWindow50, // Use a 50-packet initial congestion window. + kStartup1RTT, // Stay in STARTUP for 1 RTT. + kStartup2RTT, // Stay in STARTUP for 2 RTTs. }; // Used to create instances for Quartc objects such as QuartcSession. diff --git a/chromium/net/quic/quartc/quartc_session.cc b/chromium/net/quic/quartc/quartc_session.cc index 5bb483b297d..097f165d740 100644 --- a/chromium/net/quic/quartc/quartc_session.cc +++ b/chromium/net/quic/quartc/quartc_session.cc @@ -14,10 +14,6 @@ namespace net { namespace { -// Default priority for incoming QUIC streams. -// TODO(zhihuang): Determine if this value is correct. -static const SpdyPriority kDefaultPriority = 3; - // Arbitrary server port number for net::QuicCryptoClientConfig. const int kQuicServerPort = 0; @@ -165,8 +161,10 @@ QuicCryptoStream* QuartcSession::GetMutableCryptoStream() { } QuartcStream* QuartcSession::CreateOutgoingDynamicStream() { - return ActivateDataStream( - CreateDataStream(GetNextOutgoingStreamId(), kDefaultPriority)); + // Use default priority for incoming QUIC streams. + // TODO(zhihuang): Determine if this value is correct. + return ActivateDataStream(CreateDataStream(GetNextOutgoingStreamId(), + QuicStream::kDefaultPriority)); } void QuartcSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { @@ -186,7 +184,9 @@ void QuartcSession::CloseStream(QuicStreamId stream_id) { // QuicStream::OnClose), the stream is already closed so return. return; } - write_blocked_streams()->UnregisterStream(stream_id); + if (!register_streams_early()) { + write_blocked_streams()->UnregisterStream(stream_id, /*is_static=*/false); + } QuicSession::CloseStream(stream_id); } @@ -284,6 +284,11 @@ void QuartcSession::SetDelegate( DCHECK(session_delegate_); } +void QuartcSession::SetSessionVisitor(QuartcSessionVisitor* debug_visitor) { + debug_visitor->SetQuicConnection(connection_.get()); + connection_->set_debug_visitor(debug_visitor->GetConnectionVisitor()); +} + void QuartcSession::OnTransportCanWrite() { connection()->writer()->SetWritable(); if (HasDataToWrite()) { @@ -319,7 +324,7 @@ void QuartcSession::SetServerCryptoConfig( } QuicStream* QuartcSession::CreateIncomingDynamicStream(QuicStreamId id) { - return ActivateDataStream(CreateDataStream(id, kDefaultPriority)); + return ActivateDataStream(CreateDataStream(id, QuicStream::kDefaultPriority)); } std::unique_ptr<QuartcStream> QuartcSession::CreateDataStream( @@ -334,7 +339,12 @@ std::unique_ptr<QuartcStream> QuartcSession::CreateDataStream( // Register the stream to the QuicWriteBlockedList. |priority| is clamped // between 0 and 7, with 0 being the highest priority and 7 the lowest // priority. - write_blocked_streams()->RegisterStream(stream->id(), priority); + if (!register_streams_early()) { + write_blocked_streams()->RegisterStream( + stream->id(), /* is_static_stream= */ false, priority); + } else { + write_blocked_streams()->UpdateStreamPriority(stream->id(), priority); + } if (IsIncomingStream(id)) { DCHECK(session_delegate_); diff --git a/chromium/net/quic/quartc/quartc_session.h b/chromium/net/quic/quartc/quartc_session.h index a07bf22a8b2..5ead026632e 100644 --- a/chromium/net/quic/quartc/quartc_session.h +++ b/chromium/net/quic/quartc/quartc_session.h @@ -80,6 +80,8 @@ class QUIC_EXPORT_PRIVATE QuartcSession void SetDelegate(QuartcSessionInterface::Delegate* session_delegate) override; + void SetSessionVisitor(QuartcSessionVisitor* debug_visitor) override; + void OnTransportCanWrite() override; // Decrypts an incoming QUIC packet to a data stream. diff --git a/chromium/net/quic/quartc/quartc_session_interface.h b/chromium/net/quic/quartc/quartc_session_interface.h index 59233839d52..3ea50d980fd 100644 --- a/chromium/net/quic/quartc/quartc_session_interface.h +++ b/chromium/net/quic/quartc/quartc_session_interface.h @@ -14,6 +14,7 @@ #include "net/quic/core/quic_time.h" #include "net/quic/core/quic_types.h" #include "net/quic/platform/api/quic_export.h" +#include "net/quic/quartc/quartc_session_visitor_interface.h" #include "net/quic/quartc/quartc_stream_interface.h" namespace net { @@ -130,6 +131,9 @@ class QUIC_EXPORT_PRIVATE QuartcSessionInterface { // The |delegate| is not owned by QuartcSession. virtual void SetDelegate(Delegate* delegate) = 0; + + // Sets a visitor for the session. + virtual void SetSessionVisitor(QuartcSessionVisitor* debug_visitor) = 0; }; } // namespace net diff --git a/chromium/net/quic/quartc/quartc_session_test.cc b/chromium/net/quic/quartc/quartc_session_test.cc index 6117233e92f..c49d710a230 100644 --- a/chromium/net/quic/quartc/quartc_session_test.cc +++ b/chromium/net/quic/quartc/quartc_session_test.cc @@ -10,6 +10,7 @@ #include "net/quic/core/tls_client_handshaker.h" #include "net/quic/core/tls_server_handshaker.h" #include "net/quic/platform/api/quic_ptr_util.h" +#include "net/quic/platform/api/quic_test_mem_slice_vector.h" #include "net/quic/quartc/quartc_factory.h" #include "net/quic/quartc/quartc_factory_interface.h" #include "net/quic/quartc/quartc_packet_writer.h" @@ -351,7 +352,7 @@ class FakeQuartcStreamDelegate : public QuartcStreamInterface::Delegate { void OnClose(QuartcStreamInterface* stream) override {} - void OnCanWrite(QuartcStreamInterface* stream) override {} + void OnBufferChanged(QuartcStreamInterface* stream) override {} string data() { return last_received_data_; } @@ -531,9 +532,10 @@ class QuartcSessionTest : public ::testing::Test, outgoing_stream->SetDelegate(server_peer_->stream_delegate()); // Send a test message from peer 1 to peer 2. - const char kTestMessage[] = "Hello"; - outgoing_stream->Write(kTestMessage, strlen(kTestMessage), - kDefaultWriteParam); + char kTestMessage[] = "Hello"; + test::QuicTestMemSliceVector data( + {std::make_pair(kTestMessage, strlen(kTestMessage))}); + outgoing_stream->Write(data.span(), kDefaultWriteParam); RunTasks(); // Wait for peer 2 to receive messages. @@ -546,8 +548,10 @@ class QuartcSessionTest : public ::testing::Test, EXPECT_EQ(client_peer_->data(), kTestMessage); // Send a test message from peer 2 to peer 1. - const char kTestResponse[] = "Response"; - incoming->Write(kTestResponse, strlen(kTestResponse), kDefaultWriteParam); + char kTestResponse[] = "Response"; + test::QuicTestMemSliceVector response( + {std::make_pair(kTestResponse, strlen(kTestResponse))}); + incoming->Write(response.span(), kDefaultWriteParam); RunTasks(); // Wait for peer 1 to receive messages. ASSERT_TRUE(server_peer_->has_data()); diff --git a/chromium/net/quic/quartc/quartc_session_visitor_interface.h b/chromium/net/quic/quartc/quartc_session_visitor_interface.h new file mode 100644 index 00000000000..48d4521ac3b --- /dev/null +++ b/chromium/net/quic/quartc/quartc_session_visitor_interface.h @@ -0,0 +1,27 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_QUIC_QUARTC_QUARTC_SESSION_VISITOR_INTERFACE_H_ +#define NET_QUIC_QUARTC_QUARTC_SESSION_VISITOR_INTERFACE_H_ + +#include "net/quic/core/quic_connection.h" +#include "net/quic/platform/api/quic_export.h" + +namespace net { + +class QUIC_EXPORT_PRIVATE QuartcSessionVisitor { + public: + virtual ~QuartcSessionVisitor() {} + + // Sets the |QuicConnection| for this debug visitor. Called before + // |GetConnectionVisitor|. + virtual void SetQuicConnection(QuicConnection* connection) = 0; + + // Gets the |QuicConnectionDebugVisitor| associated with this Quartc visitor. + virtual QuicConnectionDebugVisitor* GetConnectionVisitor() const = 0; +}; + +} // namespace net + +#endif // NET_QUIC_QUARTC_QUARTC_SESSION_VISITOR_INTERFACE_H_ diff --git a/chromium/net/quic/quartc/quartc_stream.cc b/chromium/net/quic/quartc/quartc_stream.cc index 8aa818edb5a..adf936847a3 100644 --- a/chromium/net/quic/quartc/quartc_stream.cc +++ b/chromium/net/quic/quartc/quartc_stream.cc @@ -9,7 +9,7 @@ namespace net { QuartcStream::QuartcStream(QuicStreamId id, QuicSession* session) - : QuicStream(id, session) {} + : QuicStream(id, session, /*is_static=*/false) {} QuartcStream::~QuartcStream() {} void QuartcStream::OnDataAvailable() { @@ -35,22 +35,27 @@ void QuartcStream::OnClose() { delegate_->OnClose(this); } -void QuartcStream::OnCanWrite() { - QuicStream::OnCanWrite(); +void QuartcStream::OnStreamDataConsumed(size_t bytes_consumed) { + QuicStream::OnStreamDataConsumed(bytes_consumed); + DCHECK(delegate_); - // Don't call the delegate if the write-side is closed or a fin is buffered. - // It is already done with this stream. - if (!write_side_closed() && !fin_buffered()) { - delegate_->OnCanWrite(this); - } + delegate_->OnBufferChanged(this); +} + +void QuartcStream::OnDataBuffered( + QuicStreamOffset offset, + QuicByteCount data_length, + const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener) { + DCHECK(delegate_); + delegate_->OnBufferChanged(this); } uint32_t QuartcStream::stream_id() { return id(); } -uint64_t QuartcStream::bytes_written() { - return stream_bytes_written(); +uint64_t QuartcStream::bytes_buffered() { + return BufferedDataBytes(); } bool QuartcStream::fin_sent() { @@ -61,15 +66,8 @@ int QuartcStream::stream_error() { return QuicStream::stream_error(); } -int QuartcStream::connection_error() { - return QuicStream::connection_error(); -} - -void QuartcStream::Write(const char* data, - size_t size, - const WriteParameters& param) { - struct iovec iov = {const_cast<char*>(data), size}; - WritevData(&iov, 1, param.fin); +void QuartcStream::Write(QuicMemSliceSpan data, const WriteParameters& param) { + WriteMemSlices(data, param.fin); } void QuartcStream::FinishWriting() { diff --git a/chromium/net/quic/quartc/quartc_stream.h b/chromium/net/quic/quartc/quartc_stream.h index 8b7a777fa89..a33a176b7d2 100644 --- a/chromium/net/quic/quartc/quartc_stream.h +++ b/chromium/net/quic/quartc/quartc_stream.h @@ -25,22 +25,24 @@ class QUIC_EXPORT_PRIVATE QuartcStream : public QuicStream, void OnClose() override; - void OnCanWrite() override; + void OnStreamDataConsumed(size_t bytes_consumed) override; + + void OnDataBuffered( + QuicStreamOffset offset, + QuicByteCount data_length, + const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener) + override; // QuartcStreamInterface overrides. uint32_t stream_id() override; - uint64_t bytes_written() override; + uint64_t bytes_buffered() override; bool fin_sent() override; int stream_error() override; - int connection_error() override; - - void Write(const char* data, - size_t size, - const WriteParameters& param) override; + void Write(QuicMemSliceSpan data, const WriteParameters& param) override; void FinishWriting() override; diff --git a/chromium/net/quic/quartc/quartc_stream_interface.h b/chromium/net/quic/quartc/quartc_stream_interface.h index 304190aa662..cae57f69c44 100644 --- a/chromium/net/quic/quartc/quartc_stream_interface.h +++ b/chromium/net/quic/quartc/quartc_stream_interface.h @@ -9,6 +9,7 @@ #include <stdint.h> #include "net/quic/platform/api/quic_export.h" +#include "net/quic/platform/api/quic_mem_slice_span.h" namespace net { @@ -23,8 +24,8 @@ class QUIC_EXPORT_PRIVATE QuartcStreamInterface { // The QUIC stream ID. virtual uint32_t stream_id() = 0; - // The amount of data sent on this stream. - virtual uint64_t bytes_written() = 0; + // The amount of data buffered on this stream. + virtual uint64_t bytes_buffered() = 0; // Return true if the FIN has been sent. Used by the outgoing streams to // determine if all the data has been sent @@ -32,21 +33,16 @@ class QUIC_EXPORT_PRIVATE QuartcStreamInterface { virtual int stream_error() = 0; - virtual int connection_error() = 0; - struct WriteParameters { - WriteParameters() : fin(false) {} // |fin| is set to be true when there is no more data need to be send // through a particular stream. The receiving side will used it to determine // if the sender finish sending data. - bool fin; + bool fin = false; }; // Sends data reliably and in-order. Returns the amount sent. // Does not buffer data. - virtual void Write(const char* data, - size_t size, - const WriteParameters& param) = 0; + virtual void Write(QuicMemSliceSpan data, const WriteParameters& param) = 0; // Marks this stream as finished writing. Asynchronously sends a FIN and // closes the write-side. The stream will no longer call OnCanWrite(). @@ -83,8 +79,8 @@ class QUIC_EXPORT_PRIVATE QuartcStreamInterface { // error code. virtual void OnClose(QuartcStreamInterface* stream) = 0; - // Called when more data may be written to a stream. - virtual void OnCanWrite(QuartcStreamInterface* stream) = 0; + // Called when the contents of the stream's buffer changes. + virtual void OnBufferChanged(QuartcStreamInterface* stream) = 0; }; // The |delegate| is not owned by QuartcStream. diff --git a/chromium/net/quic/quartc/quartc_stream_test.cc b/chromium/net/quic/quartc/quartc_stream_test.cc index 27065ada2d8..5ab681beb43 100644 --- a/chromium/net/quic/quartc/quartc_stream_test.cc +++ b/chromium/net/quic/quartc/quartc_stream_test.cc @@ -9,6 +9,7 @@ #include "net/quic/core/quic_session.h" #include "net/quic/core/quic_simple_buffer_allocator.h" #include "net/quic/platform/api/quic_ptr_util.h" +#include "net/quic/platform/api/quic_test_mem_slice_vector.h" #include "net/quic/quartc/quartc_clock_interface.h" #include "net/quic/quartc/quartc_factory.h" #include "net/quic/test_tools/mock_clock.h" @@ -20,7 +21,6 @@ namespace net { namespace { -static const SpdyPriority kDefaultPriority = 3; static const QuicStreamId kStreamId = 5; static const QuartcStreamInterface::WriteParameters kDefaultParam; @@ -78,7 +78,9 @@ class MockQuicSession : public QuicSession { // Tracks whether the stream is write blocked and its priority. void RegisterReliableStream(QuicStreamId stream_id, SpdyPriority priority) { - write_blocked_streams()->RegisterStream(stream_id, priority); + write_blocked_streams()->RegisterStream(stream_id, + /*is_static_stream=*/false, + priority); } // The session take ownership of the stream. @@ -125,8 +127,8 @@ class MockQuartcStreamDelegate : public QuartcStreamInterface::Delegate { MockQuartcStreamDelegate(int id, std::string* read_buffer) : id_(id), read_buffer_(read_buffer) {} - void OnCanWrite(QuartcStreamInterface* stream) override { - ++on_can_write_callbacks_; + void OnBufferChanged(QuartcStreamInterface* stream) override { + last_bytes_buffered_ = stream->bytes_buffered(); } void OnReceived(QuartcStreamInterface* stream, @@ -140,7 +142,7 @@ class MockQuartcStreamDelegate : public QuartcStreamInterface::Delegate { bool closed() { return closed_; } - int32_t on_can_write_callbacks() { return on_can_write_callbacks_; } + uint64_t last_bytes_buffered() { return last_bytes_buffered_; } protected: uint32_t id_; @@ -148,8 +150,9 @@ class MockQuartcStreamDelegate : public QuartcStreamInterface::Delegate { std::string* read_buffer_; // Whether the QuicStream is closed. bool closed_ = false; - // How many times OnCanWrite has been called. - int32_t on_can_write_callbacks_ = 0; + + // Last amount of data observed as buffered. + uint64_t last_bytes_buffered_ = 0; }; class QuartcStreamTest : public ::testing::Test, @@ -177,7 +180,10 @@ class QuartcStreamTest : public ::testing::Test, QuicMakeUnique<MockQuartcStreamDelegate>(kStreamId, &read_buffer_); stream_ = new QuartcStream(kStreamId, session_.get()); stream_->SetDelegate(mock_stream_delegate_.get()); - session_->RegisterReliableStream(stream_->stream_id(), kDefaultPriority); + if (!session_->register_streams_early()) { + session_->RegisterReliableStream(stream_->stream_id(), + QuicStream::kDefaultPriority); + } session_->ActivateReliableStream(std::unique_ptr<QuartcStream>(stream_)); } @@ -212,42 +218,67 @@ class QuartcStreamTest : public ::testing::Test, // Write an entire string. TEST_F(QuartcStreamTest, WriteDataWhole) { CreateReliableQuicStream(); - stream_->Write("Foo bar", 7, kDefaultParam); + char message[] = "Foo bar"; + test::QuicTestMemSliceVector data({std::make_pair(message, 7)}); + stream_->Write(data.span(), kDefaultParam); EXPECT_EQ("Foo bar", write_buffer_); } // Write part of a string. TEST_F(QuartcStreamTest, WriteDataPartial) { CreateReliableQuicStream(); - stream_->Write("Foo bar", 5, kDefaultParam); + char message[] = "Foo bar"; + test::QuicTestMemSliceVector data({std::make_pair(message, 5)}); + stream_->Write(data.span(), kDefaultParam); EXPECT_EQ("Foo b", write_buffer_); } -// Test that strings are not buffered. -TEST_F(QuartcStreamTest, NoBuffer) { +// Test that a QuartcStream buffers writes correctly. +TEST_F(QuartcStreamTest, StreamBuffersData) { CreateReliableQuicStream(); + char message[] = "Foo bar"; + test::QuicTestMemSliceVector data({std::make_pair(message, 7)}); + + // The stream is not yet writable, so data will be buffered. session_->set_writable(false); - stream_->Write("Foo bar", 7, kDefaultParam); - // The data will not be buffered. + stream_->Write(data.span(), kDefaultParam); + + // Check that data is buffered. + EXPECT_TRUE(stream_->HasBufferedData()); + EXPECT_EQ(7u, stream_->bytes_buffered()); + + // Check that the stream told its delegate about the buffer change. + EXPECT_EQ(7u, mock_stream_delegate_->last_bytes_buffered()); + + // Check that none of the data was written yet. + // Note that |write_buffer_| actually holds data written by the QuicSession + // (not data buffered by the stream). EXPECT_EQ(0ul, write_buffer_.size()); + + char message1[] = "xyzzy"; + test::QuicTestMemSliceVector data1({std::make_pair(message1, 5)}); + + // More writes go into the buffer. + stream_->Write(data1.span(), kDefaultParam); + EXPECT_TRUE(stream_->HasBufferedData()); - EXPECT_EQ(0u, stream_->bytes_written()); - // The stream is writable, but there's nothing to send. + EXPECT_EQ(12u, stream_->bytes_buffered()); + EXPECT_EQ(12u, mock_stream_delegate_->last_bytes_buffered()); + EXPECT_EQ(0ul, write_buffer_.size()); + + // The stream becomes writable, so it sends the buffered data. session_->set_writable(true); stream_->OnCanWrite(); - EXPECT_EQ(7u, stream_->bytes_written()); - EXPECT_EQ(7ul, write_buffer_.size()); - EXPECT_FALSE(stream_->HasBufferedData()); - stream_->Write("xyzzy", 5, kDefaultParam); + EXPECT_FALSE(stream_->HasBufferedData()); + EXPECT_EQ(0u, stream_->bytes_buffered()); + EXPECT_EQ(0u, mock_stream_delegate_->last_bytes_buffered()); EXPECT_EQ("Foo barxyzzy", write_buffer_); - EXPECT_EQ(12u, stream_->bytes_written()); } // Finish writing to a stream. -// The stream no longer calls OnCanWrite(). It delivers the fin bit and closes -// the write-side as soon as possible. +// It delivers the fin bit and closes the write-side as soon as possible. TEST_F(QuartcStreamTest, FinishWriting) { CreateReliableQuicStream(); @@ -255,16 +286,11 @@ TEST_F(QuartcStreamTest, FinishWriting) { stream_->FinishWriting(); EXPECT_FALSE(stream_->fin_sent()); - // Fin is buffered, no callback to OnCanWrite. - stream_->OnCanWrite(); - EXPECT_EQ(0, mock_stream_delegate_->on_can_write_callbacks()); - EXPECT_FALSE(stream_->fin_sent()); - - // Fin is sent, no callback to OnCanWrite. + // Fin is sent as soon as the stream becomes writable. session_->set_writable(true); stream_->OnCanWrite(); - EXPECT_EQ(0, mock_stream_delegate_->on_can_write_callbacks()); EXPECT_TRUE(stream_->fin_sent()); + EXPECT_TRUE(stream_->write_side_closed()); } // Read an entire string. @@ -319,7 +345,8 @@ TEST_F(QuartcStreamTest, CloseOnFins) { QuartcStreamInterface::WriteParameters param; param.fin = true; - stream_->Write(nullptr, 0, param); + test::QuicTestMemSliceVector data({}); + stream_->Write(data.span(), param); // Check that the OnClose() callback occurred. EXPECT_TRUE(mock_stream_delegate_->closed()); diff --git a/chromium/net/quic/test_tools/crypto_test_utils.cc b/chromium/net/quic/test_tools/crypto_test_utils.cc index d2e4147b5e1..e451532f08e 100644 --- a/chromium/net/quic/test_tools/crypto_test_utils.cc +++ b/chromium/net/quic/test_tools/crypto_test_utils.cc @@ -623,7 +623,7 @@ uint64_t LeafCertHashForTesting() { class MockCommonCertSets : public CommonCertSets { public: MockCommonCertSets(QuicStringPiece cert, uint64_t hash, uint32_t index) - : cert_(cert.as_string()), hash_(hash), index_(index) {} + : cert_(cert), hash_(hash), index_(index) {} QuicStringPiece GetCommonHashes() const override { QUIC_BUG << "not implemented"; @@ -901,7 +901,7 @@ CryptoHandshakeMessage CreateCHLO( CryptoFramer::ConstructHandshakeMessage(msg, Perspective::IS_CLIENT)); std::unique_ptr<CryptoHandshakeMessage> parsed(CryptoFramer::ParseMessage( bytes->AsStringPiece(), Perspective::IS_CLIENT)); - CHECK(parsed.get()); + CHECK(parsed); return *parsed; } @@ -916,6 +916,13 @@ void MovePacketsForTlsHandshake(PacketSavingConnection* source_conn, PacketSavingConnection* dest_conn, Perspective dest_perspective) { SimpleQuicFramer framer(source_conn->supported_versions(), dest_perspective); + std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames; + std::vector<std::vector<char>> buffers; + + QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer()); + + SimpleQuicFramer null_encryption_framer(source_conn->supported_versions(), + dest_perspective); size_t index = *inout_packet_index; for (; index < source_conn->encrypted_packets_.size(); index++) { if (!framer.ProcessPacket(*source_conn->encrypted_packets_[index])) { @@ -923,12 +930,37 @@ void MovePacketsForTlsHandshake(PacketSavingConnection* source_conn, // the handshake is complete. Don't treat them as handshake packets. break; } + // Try to process the packet with a framer that only has the NullDecrypter + // for decryption. If ProcessPacket succeeds, that means the packet was + // encrypted with the NullEncrypter. With the TLS handshaker in use, no + // packets should ever be encrypted with the NullEncrypter, instead they're + // encrypted with an obfuscation cipher based on QUIC version and connection + // ID. + ASSERT_FALSE(null_encryption_framer.ProcessPacket( + *source_conn->encrypted_packets_[index])) + << "No TLS packets should be encrypted with the NullEncrypter"; for (const auto& stream_frame : framer.stream_frames()) { - dest_conn->OnStreamFrame(*stream_frame); + // The stream frames from SimpleQuicFramer::stream_frames() are only valid + // until the next call to ProcessPacket. This copies the stream frames to + // |stream_frames|, including making a copy of the data buffer, since a + // QuicStreamFrame does not own the data it points to. + std::vector<char> buffer(stream_frame->data_length); + memcpy(buffer.data(), stream_frame->data_buffer, + stream_frame->data_length); + auto frame = QuicMakeUnique<QuicStreamFrame>( + stream_frame->stream_id, stream_frame->fin, stream_frame->offset, + QuicStringPiece(buffer.data(), buffer.size())); + stream_frames.push_back(std::move(frame)); + buffers.push_back(std::move(buffer)); } } *inout_packet_index = index; + QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer()); + + for (const auto& stream_frame : stream_frames) { + dest_conn->OnStreamFrame(*stream_frame); + } } void MovePackets(PacketSavingConnection* source_conn, diff --git a/chromium/net/quic/test_tools/mock_crypto_client_stream.cc b/chromium/net/quic/test_tools/mock_crypto_client_stream.cc index 2ccd8f06eb6..d0ecd118e60 100644 --- a/chromium/net/quic/test_tools/mock_crypto_client_stream.cc +++ b/chromium/net/quic/test_tools/mock_crypto_client_stream.cc @@ -9,6 +9,7 @@ #include "net/quic/core/crypto/quic_decrypter.h" #include "net/quic/core/crypto/quic_encrypter.h" #include "net/quic/core/quic_spdy_client_session_base.h" +#include "net/quic/platform/api/quic_ptr_util.h" #include "net/quic/test_tools/mock_decrypter.h" #include "net/quic/test_tools/mock_encrypter.h" #include "net/quic/test_tools/quic_config_peer.h" @@ -77,14 +78,18 @@ bool MockCryptoClientStream::CryptoConnect() { } if (use_mock_crypter_) { session()->connection()->SetDecrypter( - ENCRYPTION_INITIAL, new MockDecrypter(Perspective::IS_CLIENT)); + ENCRYPTION_INITIAL, + QuicMakeUnique<MockDecrypter>(Perspective::IS_CLIENT)); session()->connection()->SetEncrypter( - ENCRYPTION_INITIAL, new MockEncrypter(Perspective::IS_CLIENT)); + ENCRYPTION_INITIAL, + QuicMakeUnique<MockEncrypter>(Perspective::IS_CLIENT)); } else { session()->connection()->SetDecrypter( - ENCRYPTION_INITIAL, new NullDecrypter(Perspective::IS_CLIENT)); + ENCRYPTION_INITIAL, + QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); session()->connection()->SetEncrypter( - ENCRYPTION_INITIAL, new NullEncrypter(Perspective::IS_CLIENT)); + ENCRYPTION_INITIAL, + QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT)); } session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); session()->OnCryptoHandshakeEvent( @@ -105,17 +110,17 @@ bool MockCryptoClientStream::CryptoConnect() { if (use_mock_crypter_) { session()->connection()->SetDecrypter( ENCRYPTION_FORWARD_SECURE, - new MockDecrypter(Perspective::IS_CLIENT)); + QuicMakeUnique<MockDecrypter>(Perspective::IS_CLIENT)); session()->connection()->SetEncrypter( ENCRYPTION_FORWARD_SECURE, - new MockEncrypter(Perspective::IS_CLIENT)); + QuicMakeUnique<MockEncrypter>(Perspective::IS_CLIENT)); } else { session()->connection()->SetDecrypter( ENCRYPTION_FORWARD_SECURE, - new NullDecrypter(Perspective::IS_CLIENT)); + QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); session()->connection()->SetEncrypter( ENCRYPTION_FORWARD_SECURE, - new NullEncrypter(Perspective::IS_CLIENT)); + QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT)); } session()->connection()->SetDefaultEncryptionLevel( ENCRYPTION_FORWARD_SECURE); @@ -163,14 +168,18 @@ void MockCryptoClientStream::SendOnCryptoHandshakeEvent( SetConfigNegotiated(); if (use_mock_crypter_) { session()->connection()->SetDecrypter( - ENCRYPTION_FORWARD_SECURE, new MockDecrypter(Perspective::IS_CLIENT)); + ENCRYPTION_FORWARD_SECURE, + QuicMakeUnique<MockDecrypter>(Perspective::IS_CLIENT)); session()->connection()->SetEncrypter( - ENCRYPTION_FORWARD_SECURE, new MockEncrypter(Perspective::IS_CLIENT)); + ENCRYPTION_FORWARD_SECURE, + QuicMakeUnique<MockEncrypter>(Perspective::IS_CLIENT)); } else { session()->connection()->SetDecrypter( - ENCRYPTION_FORWARD_SECURE, new NullDecrypter(Perspective::IS_CLIENT)); + ENCRYPTION_FORWARD_SECURE, + QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); session()->connection()->SetEncrypter( - ENCRYPTION_FORWARD_SECURE, new NullEncrypter(Perspective::IS_CLIENT)); + ENCRYPTION_FORWARD_SECURE, + QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT)); } session()->connection()->SetDefaultEncryptionLevel( ENCRYPTION_FORWARD_SECURE); diff --git a/chromium/net/quic/test_tools/quic_config_peer.cc b/chromium/net/quic/test_tools/quic_config_peer.cc index 7fa9db79013..749efbbb817 100644 --- a/chromium/net/quic/test_tools/quic_config_peer.cc +++ b/chromium/net/quic/test_tools/quic_config_peer.cc @@ -10,13 +10,6 @@ namespace net { namespace test { // static -void QuicConfigPeer::SetReceivedSocketReceiveBuffer( - QuicConfig* config, - uint32_t receive_buffer_bytes) { - config->socket_receive_buffer_.SetReceivedValue(receive_buffer_bytes); -} - -// static void QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow( QuicConfig* config, uint32_t window_bytes) { @@ -64,5 +57,11 @@ void QuicConfigPeer::SetConnectionOptionsToSend(QuicConfig* config, config->SetConnectionOptionsToSend(options); } +// static +void QuicConfigPeer::SetReceivedStatelessResetToken(QuicConfig* config, + uint128 token) { + config->stateless_reset_token_.SetReceivedValue(token); +} + } // namespace test } // namespace net diff --git a/chromium/net/quic/test_tools/quic_config_peer.h b/chromium/net/quic/test_tools/quic_config_peer.h index 9af9341add0..ece91bf7bbf 100644 --- a/chromium/net/quic/test_tools/quic_config_peer.h +++ b/chromium/net/quic/test_tools/quic_config_peer.h @@ -8,6 +8,7 @@ #include "base/macros.h" #include "net/quic/core/quic_config.h" #include "net/quic/core/quic_packets.h" +#include "net/quic/platform/api/quic_uint128.h" namespace net { @@ -17,9 +18,6 @@ namespace test { class QuicConfigPeer { public: - static void SetReceivedSocketReceiveBuffer(QuicConfig* config, - uint32_t receive_buffer_bytes); - static void SetReceivedInitialStreamFlowControlWindow(QuicConfig* config, uint32_t window_bytes); @@ -40,6 +38,8 @@ class QuicConfigPeer { static void SetConnectionOptionsToSend(QuicConfig* config, const QuicTagVector& options); + static void SetReceivedStatelessResetToken(QuicConfig* config, uint128 token); + private: DISALLOW_COPY_AND_ASSIGN(QuicConfigPeer); }; diff --git a/chromium/net/quic/test_tools/quic_connection_peer.cc b/chromium/net/quic/test_tools/quic_connection_peer.cc index d5c1ae6ca23..11e4227e493 100644 --- a/chromium/net/quic/test_tools/quic_connection_peer.cc +++ b/chromium/net/quic/test_tools/quic_connection_peer.cc @@ -98,6 +98,20 @@ void QuicConnectionPeer::SetPeerAddress(QuicConnection* connection, } // static +void QuicConnectionPeer::SetDirectPeerAddress( + QuicConnection* connection, + const QuicSocketAddress& direct_peer_address) { + connection->direct_peer_address_ = direct_peer_address; +} + +// static +void QuicConnectionPeer::SetEffectivePeerAddress( + QuicConnection* connection, + const QuicSocketAddress& effective_peer_address) { + connection->effective_peer_address_ = effective_peer_address; +} + +// static bool QuicConnectionPeer::IsSilentCloseEnabled(QuicConnection* connection) { return connection->idle_timeout_connection_close_behavior_ == ConnectionCloseBehavior::SILENT_CLOSE; @@ -172,6 +186,18 @@ QuicAlarm* QuicConnectionPeer::GetMtuDiscoveryAlarm( } // static +QuicAlarm* QuicConnectionPeer::GetRetransmittableOnWireAlarm( + QuicConnection* connection) { + return connection->retransmittable_on_wire_alarm_.get(); +} + +// static +QuicAlarm* QuicConnectionPeer::GetPathDegradingAlarm( + QuicConnection* connection) { + return connection->path_degrading_alarm_.get(); +} + +// static QuicPacketWriter* QuicConnectionPeer::GetWriter(QuicConnection* connection) { return connection->writer_; } diff --git a/chromium/net/quic/test_tools/quic_connection_peer.h b/chromium/net/quic/test_tools/quic_connection_peer.h index efcee9eb414..d67cb753b57 100644 --- a/chromium/net/quic/test_tools/quic_connection_peer.h +++ b/chromium/net/quic/test_tools/quic_connection_peer.h @@ -64,6 +64,14 @@ class QuicConnectionPeer { static void SetPeerAddress(QuicConnection* connection, const QuicSocketAddress& peer_address); + static void SetDirectPeerAddress( + QuicConnection* connection, + const QuicSocketAddress& direct_peer_address); + + static void SetEffectivePeerAddress( + QuicConnection* connection, + const QuicSocketAddress& effective_peer_address); + static bool IsSilentCloseEnabled(QuicConnection* connection); static void SwapCrypters(QuicConnection* connection, QuicFramer* framer); @@ -84,6 +92,8 @@ class QuicConnectionPeer { static QuicAlarm* GetSendAlarm(QuicConnection* connection); static QuicAlarm* GetTimeoutAlarm(QuicConnection* connection); static QuicAlarm* GetMtuDiscoveryAlarm(QuicConnection* connection); + static QuicAlarm* GetRetransmittableOnWireAlarm(QuicConnection* connection); + static QuicAlarm* GetPathDegradingAlarm(QuicConnection* connection); static QuicPacketWriter* GetWriter(QuicConnection* connection); // If |owns_writer| is true, takes ownership of |writer|. diff --git a/chromium/net/quic/test_tools/quic_framer_peer.cc b/chromium/net/quic/test_tools/quic_framer_peer.cc index e9d65f42678..37c91f6bbda 100644 --- a/chromium/net/quic/test_tools/quic_framer_peer.cc +++ b/chromium/net/quic/test_tools/quic_framer_peer.cc @@ -49,6 +49,7 @@ bool QuicFramerPeer::ProcessIetfStreamFrame(QuicFramer* framer, QuicStreamFrame* frame) { return framer->ProcessIetfStreamFrame(reader, frame_type, frame); } + // static bool QuicFramerPeer::AppendIetfStreamFrame(QuicFramer* framer, const QuicStreamFrame& frame, @@ -56,6 +57,7 @@ bool QuicFramerPeer::AppendIetfStreamFrame(QuicFramer* framer, QuicDataWriter* writer) { return framer->AppendIetfStreamFrame(frame, last_frame_in_packet, writer); } + // static bool QuicFramerPeer::ProcessIetfAckFrame(QuicFramer* framer, QuicDataReader* reader, @@ -63,11 +65,12 @@ bool QuicFramerPeer::ProcessIetfAckFrame(QuicFramer* framer, QuicAckFrame* ack_frame) { return framer->ProcessIetfAckFrame(reader, frame_type, ack_frame); } + // static -bool QuicFramerPeer::AppendIetfAckFrameAndTypeByte(QuicFramer* framer, - const QuicAckFrame& frame, - QuicDataWriter* writer) { - return framer->AppendIetfAckFrameAndTypeByte(frame, writer); +bool QuicFramerPeer::AppendIetfAckFrame(QuicFramer* framer, + const QuicAckFrame& frame, + QuicDataWriter* writer) { + return framer->AppendIetfAckFrame(frame, writer); } // static @@ -77,14 +80,7 @@ bool QuicFramerPeer::AppendIetfConnectionCloseFrame( QuicDataWriter* writer) { return framer->AppendIetfConnectionCloseFrame(frame, writer); } -// static -bool QuicFramerPeer::AppendIetfConnectionCloseFrame( - QuicFramer* framer, - const QuicIetfTransportErrorCodes code, - const string& phrase, - QuicDataWriter* writer) { - return framer->AppendIetfConnectionCloseFrame(code, phrase, writer); -} + // static bool QuicFramerPeer::AppendIetfApplicationCloseFrame( QuicFramer* framer, @@ -92,13 +88,7 @@ bool QuicFramerPeer::AppendIetfApplicationCloseFrame( QuicDataWriter* writer) { return framer->AppendIetfApplicationCloseFrame(frame, writer); } -// static -bool QuicFramerPeer::AppendIetfApplicationCloseFrame(QuicFramer* framer, - const uint16_t code, - const string& phrase, - QuicDataWriter* writer) { - return framer->AppendIetfApplicationCloseFrame(code, phrase, writer); -} + // static bool QuicFramerPeer::ProcessIetfConnectionCloseFrame( QuicFramer* framer, @@ -107,6 +97,7 @@ bool QuicFramerPeer::ProcessIetfConnectionCloseFrame( QuicConnectionCloseFrame* frame) { return framer->ProcessIetfConnectionCloseFrame(reader, frame_type, frame); } + // static bool QuicFramerPeer::ProcessIetfApplicationCloseFrame( QuicFramer* framer, @@ -117,6 +108,176 @@ bool QuicFramerPeer::ProcessIetfApplicationCloseFrame( } // static +bool QuicFramerPeer::AppendIetfPaddingFrame(QuicFramer* framer, + const QuicPaddingFrame& frame, + QuicDataWriter* writer) { + return framer->AppendIetfPaddingFrame(frame, writer); +} + +// static +void QuicFramerPeer::ProcessIetfPaddingFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicPaddingFrame* frame) { + framer->ProcessIetfPaddingFrame(reader, frame); +} + +// static +bool QuicFramerPeer::ProcessIetfPathChallengeFrame( + QuicFramer* framer, + QuicDataReader* reader, + QuicPathChallengeFrame* frame) { + return framer->ProcessIetfPathChallengeFrame(reader, frame); +} + +// static +bool QuicFramerPeer::ProcessIetfPathResponseFrame( + QuicFramer* framer, + QuicDataReader* reader, + QuicPathResponseFrame* frame) { + return framer->ProcessIetfPathResponseFrame(reader, frame); +} + +// static +bool QuicFramerPeer::AppendIetfPathChallengeFrame( + QuicFramer* framer, + const QuicPathChallengeFrame& frame, + QuicDataWriter* writer) { + return framer->AppendIetfPathChallengeFrame(frame, writer); +} + +// static +bool QuicFramerPeer::AppendIetfPathResponseFrame( + QuicFramer* framer, + const QuicPathResponseFrame& frame, + QuicDataWriter* writer) { + return framer->AppendIetfPathResponseFrame(frame, writer); +} + +// static +bool QuicFramerPeer::AppendIetfResetStreamFrame(QuicFramer* framer, + const QuicRstStreamFrame& frame, + QuicDataWriter* writer) { + return framer->AppendIetfResetStreamFrame(frame, writer); +} + +// static +bool QuicFramerPeer::ProcessIetfResetStreamFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicRstStreamFrame* frame) { + return framer->ProcessIetfResetStreamFrame(reader, frame); +} + +// static +bool QuicFramerPeer::ProcessIetfStopSendingFrame( + QuicFramer* framer, + QuicDataReader* reader, + QuicStopSendingFrame* stop_sending_frame) { + return framer->ProcessIetfStopSendingFrame(reader, stop_sending_frame); +} + +// static +bool QuicFramerPeer::AppendIetfStopSendingFrame( + QuicFramer* framer, + const QuicStopSendingFrame& stop_sending_frame, + QuicDataWriter* writer) { + return framer->AppendIetfStopSendingFrame(stop_sending_frame, writer); +} + +// Append/consume IETF-Format MAX_DATA and MAX_STREAM_DATA frames +// static +// static +bool QuicFramerPeer::AppendIetfMaxDataFrame(QuicFramer* framer, + const QuicWindowUpdateFrame& frame, + QuicDataWriter* writer) { + return framer->AppendIetfMaxDataFrame(frame, writer); +} + +// static +bool QuicFramerPeer::AppendIetfMaxStreamDataFrame( + QuicFramer* framer, + const QuicWindowUpdateFrame& frame, + QuicDataWriter* writer) { + return framer->AppendIetfMaxStreamDataFrame(frame, writer); +} + +// static +bool QuicFramerPeer::ProcessIetfMaxDataFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicWindowUpdateFrame* frame) { + return framer->ProcessIetfMaxDataFrame(reader, frame); +} + +// static +bool QuicFramerPeer::ProcessIetfMaxStreamDataFrame( + QuicFramer* framer, + QuicDataReader* reader, + QuicWindowUpdateFrame* frame) { + return framer->ProcessIetfMaxStreamDataFrame(reader, frame); +} + +// static +bool QuicFramerPeer::AppendIetfMaxStreamIdFrame( + QuicFramer* framer, + const QuicIetfMaxStreamIdFrame& frame, + QuicDataWriter* writer) { + return framer->AppendIetfMaxStreamIdFrame(frame, writer); +} + +// static +bool QuicFramerPeer::ProcessIetfMaxStreamIdFrame( + QuicFramer* framer, + QuicDataReader* reader, + QuicIetfMaxStreamIdFrame* frame) { + return framer->ProcessIetfMaxStreamIdFrame(reader, frame); +} + +// static +bool QuicFramerPeer::AppendIetfBlockedFrame(QuicFramer* framer, + const QuicIetfBlockedFrame& frame, + QuicDataWriter* writer) { + return framer->AppendIetfBlockedFrame(frame, writer); +} + +// static +bool QuicFramerPeer::ProcessIetfBlockedFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicIetfBlockedFrame* frame) { + return framer->ProcessIetfBlockedFrame(reader, frame); +} + +// static +bool QuicFramerPeer::AppendIetfStreamBlockedFrame( + QuicFramer* framer, + const QuicWindowUpdateFrame& frame, + QuicDataWriter* writer) { + return framer->AppendIetfStreamBlockedFrame(frame, writer); +} + +// static +bool QuicFramerPeer::ProcessIetfStreamBlockedFrame( + QuicFramer* framer, + QuicDataReader* reader, + QuicWindowUpdateFrame* frame) { + return framer->ProcessIetfStreamBlockedFrame(reader, frame); +} + +// static +bool QuicFramerPeer::AppendIetfStreamIdBlockedFrame( + QuicFramer* framer, + const QuicIetfStreamIdBlockedFrame& frame, + QuicDataWriter* writer) { + return framer->AppendIetfStreamIdBlockedFrame(frame, writer); +} + +// static +bool QuicFramerPeer::ProcessIetfStreamIdBlockedFrame( + QuicFramer* framer, + QuicDataReader* reader, + QuicIetfStreamIdBlockedFrame* frame) { + return framer->ProcessIetfStreamIdBlockedFrame(reader, frame); +} + +// static void QuicFramerPeer::SwapCrypters(QuicFramer* framer1, QuicFramer* framer2) { for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; i++) { framer1->encrypter_[i].swap(framer2->encrypter_[i]); diff --git a/chromium/net/quic/test_tools/quic_framer_peer.h b/chromium/net/quic/test_tools/quic_framer_peer.h index de18e9e959f..a4372d2ab12 100644 --- a/chromium/net/quic/test_tools/quic_framer_peer.h +++ b/chromium/net/quic/test_tools/quic_framer_peer.h @@ -47,19 +47,10 @@ class QuicFramerPeer { QuicFramer* framer, const QuicConnectionCloseFrame& frame, QuicDataWriter* writer); - static bool AppendIetfConnectionCloseFrame( - QuicFramer* framer, - const QuicIetfTransportErrorCodes code, - const std::string& phrase, - QuicDataWriter* writer); static bool AppendIetfApplicationCloseFrame( QuicFramer* framer, const QuicConnectionCloseFrame& frame, QuicDataWriter* writer); - static bool AppendIetfApplicationCloseFrame(QuicFramer* framer, - const uint16_t code, - const std::string& phrase, - QuicDataWriter* writer); static bool ProcessIetfConnectionCloseFrame(QuicFramer* framer, QuicDataReader* reader, const uint8_t frame_type, @@ -68,14 +59,92 @@ class QuicFramerPeer { QuicDataReader* reader, const uint8_t frame_type, QuicConnectionCloseFrame* frame); - static bool ProcessIetfAckFrame(QuicFramer* framer, QuicDataReader* reader, uint8_t frame_type, QuicAckFrame* ack_frame); - static bool AppendIetfAckFrameAndTypeByte(QuicFramer* framer, - const QuicAckFrame& frame, - QuicDataWriter* writer); + static bool AppendIetfAckFrame(QuicFramer* framer, + const QuicAckFrame& frame, + QuicDataWriter* writer); + static bool AppendIetfResetStreamFrame(QuicFramer* framer, + const QuicRstStreamFrame& frame, + QuicDataWriter* writer); + static bool ProcessIetfResetStreamFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicRstStreamFrame* frame); + + // Add/remove IETF-Format padding. + static bool AppendIetfPaddingFrame(QuicFramer* framer, + const QuicPaddingFrame& frame, + QuicDataWriter* writer); + static void ProcessIetfPaddingFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicPaddingFrame* frame); + + static bool ProcessIetfPathChallengeFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicPathChallengeFrame* frame); + static bool ProcessIetfPathResponseFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicPathResponseFrame* frame); + + static bool AppendIetfPathChallengeFrame(QuicFramer* framer, + const QuicPathChallengeFrame& frame, + QuicDataWriter* writer); + static bool AppendIetfPathResponseFrame(QuicFramer* framer, + const QuicPathResponseFrame& frame, + QuicDataWriter* writer); + + static bool ProcessIetfStopSendingFrame( + QuicFramer* framer, + QuicDataReader* reader, + QuicStopSendingFrame* stop_sending_frame); + static bool AppendIetfStopSendingFrame( + QuicFramer* framer, + const QuicStopSendingFrame& stop_sending_frame, + QuicDataWriter* writer); + + // Append/consume IETF-Format MAX_DATA and MAX_STREAM_DATA frames + static bool AppendIetfMaxDataFrame(QuicFramer* framer, + const QuicWindowUpdateFrame& frame, + QuicDataWriter* writer); + static bool AppendIetfMaxStreamDataFrame(QuicFramer* framer, + const QuicWindowUpdateFrame& frame, + QuicDataWriter* writer); + static bool ProcessIetfMaxDataFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicWindowUpdateFrame* frame); + static bool ProcessIetfMaxStreamDataFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicWindowUpdateFrame* frame); + static bool AppendIetfMaxStreamIdFrame(QuicFramer* framer, + const QuicIetfMaxStreamIdFrame& frame, + QuicDataWriter* writer); + static bool ProcessIetfMaxStreamIdFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicIetfMaxStreamIdFrame* frame); + static bool AppendIetfBlockedFrame(QuicFramer* framer, + const QuicIetfBlockedFrame& frame, + QuicDataWriter* writer); + static bool ProcessIetfBlockedFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicIetfBlockedFrame* frame); + + static bool AppendIetfStreamBlockedFrame(QuicFramer* framer, + const QuicWindowUpdateFrame& frame, + QuicDataWriter* writer); + static bool ProcessIetfStreamBlockedFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicWindowUpdateFrame* frame); + + static bool AppendIetfStreamIdBlockedFrame( + QuicFramer* framer, + const QuicIetfStreamIdBlockedFrame& frame, + QuicDataWriter* writer); + static bool ProcessIetfStreamIdBlockedFrame( + QuicFramer* framer, + QuicDataReader* reader, + QuicIetfStreamIdBlockedFrame* frame); private: DISALLOW_COPY_AND_ASSIGN(QuicFramerPeer); diff --git a/chromium/net/quic/test_tools/quic_packet_creator_peer.cc b/chromium/net/quic/test_tools/quic_packet_creator_peer.cc index b502a9b97b4..62e482a891f 100644 --- a/chromium/net/quic/test_tools/quic_packet_creator_peer.cc +++ b/chromium/net/quic/test_tools/quic_packet_creator_peer.cc @@ -11,7 +11,7 @@ namespace test { // static bool QuicPacketCreatorPeer::SendVersionInPacket(QuicPacketCreator* creator) { - return creator->send_version_in_packet_; + return creator->IncludeVersionInHeader(); } // static @@ -31,7 +31,7 @@ void QuicPacketCreatorPeer::SetPacketNumberLength( // static QuicPacketNumberLength QuicPacketCreatorPeer::GetPacketNumberLength( QuicPacketCreator* creator) { - return creator->packet_.packet_number_length; + return creator->GetPacketNumberLength(); } void QuicPacketCreatorPeer::SetPacketNumber(QuicPacketCreator* creator, diff --git a/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.cc b/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.cc index 8650eabf115..0999690a659 100644 --- a/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.cc +++ b/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.cc @@ -113,12 +113,26 @@ void QuicSentPacketManagerPeer::MarkForRetransmission( // static QuicTime::Delta QuicSentPacketManagerPeer::GetRetransmissionDelay( + const QuicSentPacketManager* sent_packet_manager, + size_t consecutive_rto_count) { + return sent_packet_manager->GetRetransmissionDelay(consecutive_rto_count); +} + +// static +QuicTime::Delta QuicSentPacketManagerPeer::GetRetransmissionDelay( const QuicSentPacketManager* sent_packet_manager) { return sent_packet_manager->GetRetransmissionDelay(); } // static QuicTime::Delta QuicSentPacketManagerPeer::GetTailLossProbeDelay( + const QuicSentPacketManager* sent_packet_manager, + size_t consecutive_tlp_count) { + return sent_packet_manager->GetTailLossProbeDelay(consecutive_tlp_count); +} + +// static +QuicTime::Delta QuicSentPacketManagerPeer::GetTailLossProbeDelay( const QuicSentPacketManager* sent_packet_manager) { return sent_packet_manager->GetTailLossProbeDelay(); } diff --git a/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.h b/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.h index 713ae888e6d..d1363ef2c7a 100644 --- a/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.h +++ b/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.h @@ -57,8 +57,14 @@ class QuicSentPacketManagerPeer { TransmissionType transmission_type); static QuicTime::Delta GetRetransmissionDelay( + const QuicSentPacketManager* sent_packet_manager, + size_t consecutive_rto_count); + static QuicTime::Delta GetRetransmissionDelay( const QuicSentPacketManager* sent_packet_manager); static QuicTime::Delta GetTailLossProbeDelay( + const QuicSentPacketManager* sent_packet_manager, + size_t consecutive_tlp_count); + static QuicTime::Delta GetTailLossProbeDelay( const QuicSentPacketManager* sent_packet_manager); static bool HasUnackedCryptoPackets( diff --git a/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.cc b/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.cc index 5ca41adbfd2..7bb4410d467 100644 --- a/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.cc +++ b/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.cc @@ -23,6 +23,17 @@ const BufferedSlice* QuicStreamSendBufferPeer::CurrentWriteSlice( } return &send_buffer->buffered_slices_[send_buffer->write_index_]; } + +// static +QuicByteCount QuicStreamSendBufferPeer::TotalLength( + QuicStreamSendBuffer* send_buffer) { + QuicByteCount length = 0; + for (const auto& slice : send_buffer->buffered_slices_) { + length += slice.slice.length(); + } + return length; +} + } // namespace test } // namespace net diff --git a/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.h b/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.h index 6b8b115e718..54c53e9c534 100644 --- a/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.h +++ b/chromium/net/quic/test_tools/quic_stream_send_buffer_peer.h @@ -18,6 +18,8 @@ class QuicStreamSendBufferPeer { static const BufferedSlice* CurrentWriteSlice( QuicStreamSendBuffer* send_buffer); + + static QuicByteCount TotalLength(QuicStreamSendBuffer* send_buffer); }; } // namespace test diff --git a/chromium/net/quic/test_tools/quic_test_utils.cc b/chromium/net/quic/test_tools/quic_test_utils.cc index c3546dfc861..60a70cca68a 100644 --- a/chromium/net/quic/test_tools/quic_test_utils.cc +++ b/chromium/net/quic/test_tools/quic_test_utils.cc @@ -233,6 +233,10 @@ bool NoOpFramerVisitor::OnBlockedFrame(const QuicBlockedFrame& frame) { return true; } +bool NoOpFramerVisitor::IsValidStatelessResetToken(uint128 token) const { + return false; +} + MockQuicConnectionVisitor::MockQuicConnectionVisitor() {} MockQuicConnectionVisitor::~MockQuicConnectionVisitor() {} @@ -374,9 +378,14 @@ void PacketSavingConnection::SendOrQueuePacket(SerializedPacket* packet) { } MockQuicSession::MockQuicSession(QuicConnection* connection) + : MockQuicSession(connection, true) {} + +MockQuicSession::MockQuicSession(QuicConnection* connection, + bool create_mock_crypto_stream) : QuicSession(connection, nullptr, DefaultQuicConfig()) { - crypto_stream_ = QuicMakeUnique<MockQuicCryptoStream>(this); - Initialize(); + if (create_mock_crypto_stream) { + crypto_stream_ = QuicMakeUnique<MockQuicCryptoStream>(this); + } ON_CALL(*this, WritevData(_, _, _, _, _)) .WillByDefault(testing::Return(QuicConsumedData(0, false))); } @@ -393,6 +402,10 @@ const QuicCryptoStream* MockQuicSession::GetCryptoStream() const { return crypto_stream_.get(); } +void MockQuicSession::SetCryptoStream(QuicCryptoStream* crypto_stream) { + crypto_stream_.reset(crypto_stream); +} + // static QuicConsumedData MockQuicSession::ConsumeData(QuicStream* stream, QuicStreamId /*id*/, @@ -432,9 +445,15 @@ CryptoMessageParser* MockQuicCryptoStream::crypto_message_parser() { } MockQuicSpdySession::MockQuicSpdySession(QuicConnection* connection) + : MockQuicSpdySession(connection, true) {} + +MockQuicSpdySession::MockQuicSpdySession(QuicConnection* connection, + bool create_mock_crypto_stream) : QuicSpdySession(connection, nullptr, DefaultQuicConfig()) { - crypto_stream_ = QuicMakeUnique<MockQuicCryptoStream>(this); - Initialize(); + if (create_mock_crypto_stream) { + crypto_stream_ = QuicMakeUnique<MockQuicCryptoStream>(this); + } + ON_CALL(*this, WritevData(_, _, _, _, _)) .WillByDefault(testing::Return(QuicConsumedData(0, false))); } @@ -451,6 +470,10 @@ const QuicCryptoStream* MockQuicSpdySession::GetCryptoStream() const { return crypto_stream_.get(); } +void MockQuicSpdySession::SetCryptoStream(QuicCryptoStream* crypto_stream) { + crypto_stream_.reset(crypto_stream); +} + size_t MockQuicSpdySession::WriteHeaders( QuicStreamId id, SpdyHeaderBlock headers, @@ -642,7 +665,7 @@ QuicEncryptedPacket* ConstructEncryptedPacket(QuicConnectionId connection_id, const string& data) { return ConstructEncryptedPacket( connection_id, version_flag, reset_flag, packet_number, data, - PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER); + PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER); } QuicEncryptedPacket* ConstructEncryptedPacket( diff --git a/chromium/net/quic/test_tools/quic_test_utils.h b/chromium/net/quic/test_tools/quic_test_utils.h index 8544ec8dbec..9d2b75a0455 100644 --- a/chromium/net/quic/test_tools/quic_test_utils.h +++ b/chromium/net/quic/test_tools/quic_test_utils.h @@ -107,7 +107,7 @@ QuicEncryptedPacket* ConstructEncryptedPacket( QuicPacketNumberLength packet_number_length); // This form assumes |connection_id_length| == PACKET_8BYTE_CONNECTION_ID, -// |packet_number_length| == PACKET_6BYTE_PACKET_NUMBER and +// |packet_number_length| == PACKET_4BYTE_PACKET_NUMBER and // |versions| == nullptr. QuicEncryptedPacket* ConstructEncryptedPacket(QuicConnectionId connection_id, bool version_flag, @@ -260,6 +260,9 @@ class MockFramerVisitor : public QuicFramerVisitorInterface { MOCK_METHOD1(OnWindowUpdateFrame, bool(const QuicWindowUpdateFrame& frame)); MOCK_METHOD1(OnBlockedFrame, bool(const QuicBlockedFrame& frame)); MOCK_METHOD0(OnPacketComplete, void()); + MOCK_CONST_METHOD1(IsValidStatelessResetToken, bool(uint128)); + MOCK_METHOD1(OnAuthenticatedIetfStatelessResetPacket, + void(const QuicIetfStatelessResetPacket&)); private: DISALLOW_COPY_AND_ASSIGN(MockFramerVisitor); @@ -295,6 +298,9 @@ class NoOpFramerVisitor : public QuicFramerVisitorInterface { bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override; bool OnBlockedFrame(const QuicBlockedFrame& frame) override; void OnPacketComplete() override {} + bool IsValidStatelessResetToken(uint128 token) const override; + void OnAuthenticatedIetfStatelessResetPacket( + const QuicIetfStatelessResetPacket& packet) override {} private: DISALLOW_COPY_AND_ASSIGN(NoOpFramerVisitor); @@ -332,6 +338,7 @@ class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface { MOCK_METHOD0(OnAckNeedsRetransmittableFrame, void()); MOCK_METHOD0(SendPing, void()); MOCK_CONST_METHOD0(AllowSelfAddressChange, bool()); + MOCK_METHOD0(OnForwardProgressConfirmed, void()); private: DISALLOW_COPY_AND_ASSIGN(MockQuicConnectionVisitor); @@ -470,11 +477,6 @@ class MockQuicConnection : public QuicConnection { bool ReallySendControlFrame(const QuicFrame& frame) { return QuicConnection::SendControlFrame(frame); } - void ReallySendGoAway(QuicErrorCode error, - QuicStreamId last_good_stream_id, - const std::string& reason) { - QuicConnection::SendGoAway(error, last_good_stream_id, reason); - } bool ReallySendConnectivityProbingPacket( QuicPacketWriter* probing_writer, @@ -511,11 +513,15 @@ class PacketSavingConnection : public MockQuicConnection { class MockQuicSession : public QuicSession { public: // Takes ownership of |connection|. + MockQuicSession(QuicConnection* connection, bool create_mock_crypto_stream); + + // Takes ownership of |connection|. explicit MockQuicSession(QuicConnection* connection); ~MockQuicSession() override; QuicCryptoStream* GetMutableCryptoStream() override; const QuicCryptoStream* GetCryptoStream() const override; + void SetCryptoStream(QuicCryptoStream* crypto_stream); MOCK_METHOD3(OnConnectionClosed, void(QuicErrorCode error, @@ -582,10 +588,14 @@ class MockQuicSpdySession : public QuicSpdySession { public: // Takes ownership of |connection|. explicit MockQuicSpdySession(QuicConnection* connection); + // Takes ownership of |connection|. + MockQuicSpdySession(QuicConnection* connection, + bool create_mock_crypto_stream); ~MockQuicSpdySession() override; QuicCryptoStream* GetMutableCryptoStream() override; const QuicCryptoStream* GetCryptoStream() const override; + void SetCryptoStream(QuicCryptoStream* crypto_stream); const SpdyHeaderBlock& GetWriteHeaders() { return write_headers_; } // From QuicSession. @@ -775,6 +785,8 @@ class MockSendAlgorithm : public SendAlgorithmInterface { MOCK_METHOD2(SetFromConfig, void(const QuicConfig& config, Perspective perspective)); MOCK_METHOD1(SetNumEmulatedConnections, void(int num_connections)); + MOCK_METHOD1(SetInitialCongestionWindowInPackets, + void(QuicPacketCount packets)); MOCK_METHOD1(SetMaxCongestionWindow, void(QuicByteCount max_congestion_window)); MOCK_METHOD5(OnCongestionEvent, @@ -858,6 +870,8 @@ class MockNetworkChangeVisitor ~MockNetworkChangeVisitor() override; MOCK_METHOD0(OnCongestionChange, void()); + // TODO(b/76462509): remove OnPathDegrading() once + // FLAGS_quic_reloadable_flag_quic_path_degrading_alarm is deprecated. MOCK_METHOD0(OnPathDegrading, void()); MOCK_METHOD1(OnPathMtuIncreased, void(QuicPacketLength)); @@ -891,8 +905,7 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor { MOCK_METHOD1(OnPacketHeader, void(const QuicPacketHeader& header)); - MOCK_METHOD1(OnSuccessfulVersionNegotiation, - void(const QuicTransportVersion&)); + MOCK_METHOD1(OnSuccessfulVersionNegotiation, void(const ParsedQuicVersion&)); MOCK_METHOD1(OnStreamFrame, void(const QuicStreamFrame&)); diff --git a/chromium/net/quic/test_tools/simple_quic_framer.cc b/chromium/net/quic/test_tools/simple_quic_framer.cc index a92c0075d01..405cfde0bdf 100644 --- a/chromium/net/quic/test_tools/simple_quic_framer.cc +++ b/chromium/net/quic/test_tools/simple_quic_framer.cc @@ -127,6 +127,16 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { void OnPacketComplete() override {} + bool IsValidStatelessResetToken(uint128 token) const override { + return false; + } + + void OnAuthenticatedIetfStatelessResetPacket( + const QuicIetfStatelessResetPacket& packet) override { + stateless_reset_packet_ = + QuicMakeUnique<QuicIetfStatelessResetPacket>(packet); + } + const QuicPacketHeader& header() const { return header_; } const std::vector<QuicAckFrame>& ack_frames() const { return ack_frames_; } const std::vector<QuicConnectionCloseFrame>& connection_close_frames() const { @@ -161,6 +171,7 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface { QuicPacketHeader header_; std::unique_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_; std::unique_ptr<QuicPublicResetPacket> public_reset_packet_; + std::unique_ptr<QuicIetfStatelessResetPacket> stateless_reset_packet_; std::vector<QuicAckFrame> ack_frames_; std::vector<QuicStopWaitingFrame> stop_waiting_frames_; std::vector<QuicPaddingFrame> padding_frames_; diff --git a/chromium/net/quic/test_tools/simple_session_notifier.cc b/chromium/net/quic/test_tools/simple_session_notifier.cc index 61ba9238349..689a6599c12 100644 --- a/chromium/net/quic/test_tools/simple_session_notifier.cc +++ b/chromium/net/quic/test_tools/simple_session_notifier.cc @@ -24,18 +24,6 @@ SimpleSessionNotifier::~SimpleSessionNotifier() { } } -std::ostream& operator<<(std::ostream& os, - const SimpleSessionNotifier::StreamState& s) { - os << "bytes_total: " << s.bytes_total << " bytes_sent: " << s.bytes_sent - << " bytes_acked " << s.bytes_acked - << " pending_retransmissions: " << s.pending_retransmissions - << " fin_buffered: " << s.fin_buffered << " fin_sent: " << s.fin_sent - << " fin_outstanding: " << s.fin_outstanding - << " fin_lost: " << s.fin_lost; - - return os; -} - SimpleSessionNotifier::StreamState::StreamState() : bytes_total(0), bytes_sent(0), @@ -477,7 +465,7 @@ bool SimpleSessionNotifier::RetransmitLostStreamData() { } if (length > consumed.bytes_consumed || (can_bundle_fin && !consumed.fin_consumed)) { - DLOG(INFO) << "Connection is write blocked"; + DVLOG(1) << "Connection is write blocked"; break; } } diff --git a/chromium/net/quic/test_tools/simple_session_notifier.h b/chromium/net/quic/test_tools/simple_session_notifier.h index b5700286540..845e2eca3b2 100644 --- a/chromium/net/quic/test_tools/simple_session_notifier.h +++ b/chromium/net/quic/test_tools/simple_session_notifier.h @@ -31,9 +31,6 @@ class SimpleSessionNotifier : public SessionNotifierInterface { QuicRstStreamErrorCode error, QuicStreamOffset bytes_written); - // Called when |frame| is sent. - void OnControlFrameSent(const QuicFrame& frame); - // Neuters unencrypted data of crypto stream. void NeuterUnencryptedData(); diff --git a/chromium/net/quic/test_tools/simple_session_notifier_test.cc b/chromium/net/quic/test_tools/simple_session_notifier_test.cc index 0b0f6630cf6..545ae483f8b 100644 --- a/chromium/net/quic/test_tools/simple_session_notifier_test.cc +++ b/chromium/net/quic/test_tools/simple_session_notifier_test.cc @@ -29,13 +29,6 @@ class MockQuicConnectionWithSendStreamData : public MockQuicConnection { size_t write_length, QuicStreamOffset offset, StreamSendingState state)); - - static QuicConsumedData ConsumeAllData(QuicStreamId /*id*/, - size_t write_length, - QuicStreamOffset /*offset*/, - StreamSendingState state) { - return QuicConsumedData(write_length, state != NO_FIN); - } }; class SimpleSessionNotifierTest : public QuicTest { diff --git a/chromium/net/quic/test_tools/simulator/quic_endpoint.cc b/chromium/net/quic/test_tools/simulator/quic_endpoint.cc index 2b46e83858a..a02af996c48 100644 --- a/chromium/net/quic/test_tools/simulator/quic_endpoint.cc +++ b/chromium/net/quic/test_tools/simulator/quic_endpoint.cc @@ -84,9 +84,9 @@ QuicEndpoint::QuicEndpoint(Simulator* simulator, connection_.SetSelfAddress(GetAddressFromName(name)); connection_.set_visitor(this); connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, - new NullEncrypter(perspective)); + QuicMakeUnique<NullEncrypter>(perspective)); connection_.SetDecrypter(ENCRYPTION_FORWARD_SECURE, - new NullDecrypter(perspective)); + QuicMakeUnique<NullDecrypter>(perspective)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); connection_.SetDataProducer(&producer_); connection_.SetSessionNotifier(this); diff --git a/chromium/net/quic/test_tools/simulator/quic_endpoint.h b/chromium/net/quic/test_tools/simulator/quic_endpoint.h index bd983e4d593..c064560fee6 100644 --- a/chromium/net/quic/test_tools/simulator/quic_endpoint.h +++ b/chromium/net/quic/test_tools/simulator/quic_endpoint.h @@ -98,6 +98,7 @@ class QuicEndpoint : public Endpoint, void OnAckNeedsRetransmittableFrame() override {} void SendPing() override {} bool AllowSelfAddressChange() const override; + void OnForwardProgressConfirmed() override {} // End QuicConnectionVisitorInterface implementation. // Begin SessionNotifierInterface methods: diff --git a/chromium/net/quic/test_tools/simulator/quic_endpoint_test.cc b/chromium/net/quic/test_tools/simulator/quic_endpoint_test.cc index 2d8c87ee6b0..edff605c9b5 100644 --- a/chromium/net/quic/test_tools/simulator/quic_endpoint_test.cc +++ b/chromium/net/quic/test_tools/simulator/quic_endpoint_test.cc @@ -177,7 +177,7 @@ TEST_F(QuicEndpointTest, Competition) { endpoint_b->AddBytesToTransfer(2 * 1024 * 1024); endpoint_c->AddBytesToTransfer(2 * 1024 * 1024); QuicTime end_time = - simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(8); + simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(10); simulator_.RunUntil( [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; }); |