| Index: net/quic/quic_client_session.cc
|
| diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
|
| deleted file mode 100644
|
| index a2f9179f19b223243e363c2ac18e61d3ec767b38..0000000000000000000000000000000000000000
|
| --- a/net/quic/quic_client_session.cc
|
| +++ /dev/null
|
| @@ -1,955 +0,0 @@
|
| -// 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/quic_client_session.h"
|
| -
|
| -#include "base/callback_helpers.h"
|
| -#include "base/message_loop/message_loop.h"
|
| -#include "base/metrics/histogram.h"
|
| -#include "base/metrics/sparse_histogram.h"
|
| -#include "base/profiler/scoped_tracker.h"
|
| -#include "base/stl_util.h"
|
| -#include "base/strings/string_number_conversions.h"
|
| -#include "base/values.h"
|
| -#include "net/base/io_buffer.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/base/network_activity_monitor.h"
|
| -#include "net/http/transport_security_state.h"
|
| -#include "net/quic/crypto/proof_verifier_chromium.h"
|
| -#include "net/quic/crypto/quic_server_info.h"
|
| -#include "net/quic/quic_connection_helper.h"
|
| -#include "net/quic/quic_crypto_client_stream_factory.h"
|
| -#include "net/quic/quic_server_id.h"
|
| -#include "net/quic/quic_stream_factory.h"
|
| -#include "net/spdy/spdy_session.h"
|
| -#include "net/ssl/channel_id_service.h"
|
| -#include "net/ssl/ssl_connection_status_flags.h"
|
| -#include "net/ssl/ssl_info.h"
|
| -#include "net/udp/datagram_client_socket.h"
|
| -
|
| -namespace net {
|
| -
|
| -namespace {
|
| -
|
| -// The length of time to wait for a 0-RTT handshake to complete
|
| -// before allowing the requests to possibly proceed over TCP.
|
| -const int k0RttHandshakeTimeoutMs = 300;
|
| -
|
| -// IPv6 packets have an additional 20 bytes of overhead than IPv4 packets.
|
| -const size_t kAdditionalOverheadForIPv6 = 20;
|
| -
|
| -// 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
|
| -enum Location {
|
| - DESTRUCTOR = 0,
|
| - ADD_OBSERVER = 1,
|
| - TRY_CREATE_STREAM = 2,
|
| - CREATE_OUTGOING_RELIABLE_STREAM = 3,
|
| - NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER = 4,
|
| - NOTIFY_FACTORY_OF_SESSION_CLOSED = 5,
|
| - NUM_LOCATIONS = 6,
|
| -};
|
| -
|
| -void RecordUnexpectedOpenStreams(Location location) {
|
| - UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
|
| - NUM_LOCATIONS);
|
| -}
|
| -
|
| -void RecordUnexpectedObservers(Location location) {
|
| - UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
|
| - NUM_LOCATIONS);
|
| -}
|
| -
|
| -void RecordUnexpectedNotGoingAway(Location location) {
|
| - UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
|
| - NUM_LOCATIONS);
|
| -}
|
| -
|
| -// Histogram for recording the different reasons that a QUIC session is unable
|
| -// to complete the handshake.
|
| -enum HandshakeFailureReason {
|
| - HANDSHAKE_FAILURE_UNKNOWN = 0,
|
| - HANDSHAKE_FAILURE_BLACK_HOLE = 1,
|
| - HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
|
| - NUM_HANDSHAKE_FAILURE_REASONS = 3,
|
| -};
|
| -
|
| -void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
|
| - UMA_HISTOGRAM_ENUMERATION(
|
| - "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason",
|
| - reason, NUM_HANDSHAKE_FAILURE_REASONS);
|
| -}
|
| -
|
| -// Note: these values must be kept in sync with the corresponding values in:
|
| -// tools/metrics/histograms/histograms.xml
|
| -enum HandshakeState {
|
| - STATE_STARTED = 0,
|
| - STATE_ENCRYPTION_ESTABLISHED = 1,
|
| - STATE_HANDSHAKE_CONFIRMED = 2,
|
| - STATE_FAILED = 3,
|
| - NUM_HANDSHAKE_STATES = 4
|
| -};
|
| -
|
| -void RecordHandshakeState(HandshakeState state) {
|
| - UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
|
| - NUM_HANDSHAKE_STATES);
|
| -}
|
| -
|
| -base::Value* NetLogQuicClientSessionCallback(
|
| - const QuicServerId* server_id,
|
| - bool require_confirmation,
|
| - NetLog::LogLevel /* log_level */) {
|
| - base::DictionaryValue* dict = new base::DictionaryValue();
|
| - dict->SetString("host", server_id->host());
|
| - dict->SetInteger("port", server_id->port());
|
| - dict->SetBoolean("is_https", server_id->is_https());
|
| - dict->SetBoolean("privacy_mode",
|
| - server_id->privacy_mode() == PRIVACY_MODE_ENABLED);
|
| - dict->SetBoolean("require_confirmation", require_confirmation);
|
| - return dict;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -QuicClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
|
| -
|
| -QuicClientSession::StreamRequest::~StreamRequest() {
|
| - CancelRequest();
|
| -}
|
| -
|
| -int QuicClientSession::StreamRequest::StartRequest(
|
| - const base::WeakPtr<QuicClientSession>& session,
|
| - QuicReliableClientStream** stream,
|
| - const CompletionCallback& callback) {
|
| - session_ = session;
|
| - stream_ = stream;
|
| - int rv = session_->TryCreateStream(this, stream_);
|
| - if (rv == ERR_IO_PENDING) {
|
| - callback_ = callback;
|
| - }
|
| -
|
| - return rv;
|
| -}
|
| -
|
| -void QuicClientSession::StreamRequest::CancelRequest() {
|
| - if (session_)
|
| - session_->CancelRequest(this);
|
| - session_.reset();
|
| - callback_.Reset();
|
| -}
|
| -
|
| -void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
|
| - QuicReliableClientStream* stream) {
|
| - session_.reset();
|
| - *stream_ = stream;
|
| - ResetAndReturn(&callback_).Run(OK);
|
| -}
|
| -
|
| -void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
|
| - session_.reset();
|
| - ResetAndReturn(&callback_).Run(rv);
|
| -}
|
| -
|
| -QuicClientSession::QuicClientSession(
|
| - QuicConnection* connection,
|
| - scoped_ptr<DatagramClientSocket> socket,
|
| - QuicStreamFactory* stream_factory,
|
| - TransportSecurityState* transport_security_state,
|
| - scoped_ptr<QuicServerInfo> server_info,
|
| - const QuicConfig& config,
|
| - base::TaskRunner* task_runner,
|
| - NetLog* net_log)
|
| - : QuicClientSessionBase(connection, config),
|
| - require_confirmation_(false),
|
| - stream_factory_(stream_factory),
|
| - socket_(socket.Pass()),
|
| - read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
|
| - transport_security_state_(transport_security_state),
|
| - server_info_(server_info.Pass()),
|
| - read_pending_(false),
|
| - num_total_streams_(0),
|
| - task_runner_(task_runner),
|
| - net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
|
| - logger_(new QuicConnectionLogger(this, net_log_)),
|
| - num_packets_read_(0),
|
| - going_away_(false),
|
| - weak_factory_(this) {
|
| - // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
|
| - tracked_objects::ScopedTracker tracking_profile1(
|
| - FROM_HERE_WITH_EXPLICIT_FUNCTION(
|
| - "422516 QuicClientSession::QuicClientSession1"));
|
| -
|
| - connection->set_debug_visitor(logger_);
|
| - IPEndPoint address;
|
| - // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed.
|
| - tracked_objects::ScopedTracker tracking_profile2(
|
| - FROM_HERE_WITH_EXPLICIT_FUNCTION(
|
| - "422516 QuicClientSession::QuicClientSession2"));
|
| - if (socket && socket->GetLocalAddress(&address) == OK &&
|
| - address.GetFamily() == ADDRESS_FAMILY_IPV6) {
|
| - connection->set_max_packet_length(
|
| - connection->max_packet_length() - kAdditionalOverheadForIPv6);
|
| - }
|
| -}
|
| -
|
| -void QuicClientSession::InitializeSession(
|
| - const QuicServerId& server_id,
|
| - QuicCryptoClientConfig* crypto_config,
|
| - QuicCryptoClientStreamFactory* crypto_client_stream_factory) {
|
| - server_id_ = server_id;
|
| - crypto_stream_.reset(
|
| - crypto_client_stream_factory ?
|
| - crypto_client_stream_factory->CreateQuicCryptoClientStream(
|
| - server_id, this, crypto_config) :
|
| - new QuicCryptoClientStream(server_id, this,
|
| - new ProofVerifyContextChromium(net_log_),
|
| - crypto_config));
|
| - QuicClientSessionBase::InitializeSession();
|
| - // TODO(rch): pass in full host port proxy pair
|
| - net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION,
|
| - base::Bind(NetLogQuicClientSessionCallback,
|
| - &server_id,
|
| - require_confirmation_));
|
| -}
|
| -
|
| -QuicClientSession::~QuicClientSession() {
|
| - if (!streams()->empty())
|
| - RecordUnexpectedOpenStreams(DESTRUCTOR);
|
| - if (!observers_.empty())
|
| - RecordUnexpectedObservers(DESTRUCTOR);
|
| - if (!going_away_)
|
| - RecordUnexpectedNotGoingAway(DESTRUCTOR);
|
| -
|
| - while (!streams()->empty() ||
|
| - !observers_.empty() ||
|
| - !stream_requests_.empty()) {
|
| - // The session must be closed before it is destroyed.
|
| - DCHECK(streams()->empty());
|
| - CloseAllStreams(ERR_UNEXPECTED);
|
| - DCHECK(observers_.empty());
|
| - CloseAllObservers(ERR_UNEXPECTED);
|
| -
|
| - connection()->set_debug_visitor(nullptr);
|
| - net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
|
| -
|
| - while (!stream_requests_.empty()) {
|
| - StreamRequest* request = stream_requests_.front();
|
| - stream_requests_.pop_front();
|
| - request->OnRequestCompleteFailure(ERR_ABORTED);
|
| - }
|
| - }
|
| -
|
| - if (connection()->connected()) {
|
| - // Ensure that the connection is closed by the time the session is
|
| - // destroyed.
|
| - connection()->CloseConnection(QUIC_INTERNAL_ERROR, false);
|
| - }
|
| -
|
| - if (IsEncryptionEstablished())
|
| - RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
|
| - if (IsCryptoHandshakeConfirmed())
|
| - RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
|
| - else
|
| - RecordHandshakeState(STATE_FAILED);
|
| -
|
| - UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
|
| - UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
|
| - crypto_stream_->num_sent_client_hellos());
|
| - if (!IsCryptoHandshakeConfirmed())
|
| - return;
|
| -
|
| - // Sending one client_hello means we had zero handshake-round-trips.
|
| - int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
|
| -
|
| - // Don't bother with these histogram during tests, which mock out
|
| - // num_sent_client_hellos().
|
| - if (round_trip_handshakes < 0 || !stream_factory_)
|
| - return;
|
| -
|
| - bool port_selected = stream_factory_->enable_port_selection();
|
| - SSLInfo ssl_info;
|
| - if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
|
| - if (port_selected) {
|
| - UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
|
| - round_trip_handshakes, 0, 3, 4);
|
| - } else {
|
| - UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
|
| - round_trip_handshakes, 0, 3, 4);
|
| - if (require_confirmation_) {
|
| - UMA_HISTOGRAM_CUSTOM_COUNTS(
|
| - "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
|
| - round_trip_handshakes, 0, 3, 4);
|
| - }
|
| - }
|
| - } else {
|
| - if (port_selected) {
|
| - UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
|
| - round_trip_handshakes, 0, 3, 4);
|
| - } else {
|
| - UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
|
| - round_trip_handshakes, 0, 3, 4);
|
| - if (require_confirmation_) {
|
| - UMA_HISTOGRAM_CUSTOM_COUNTS(
|
| - "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
|
| - round_trip_handshakes, 0, 3, 4);
|
| - }
|
| - }
|
| - }
|
| - const QuicConnectionStats stats = connection()->GetStats();
|
| - if (server_info_ && stats.min_rtt_us > 0) {
|
| - base::TimeTicks wait_for_data_start_time =
|
| - server_info_->wait_for_data_start_time();
|
| - base::TimeTicks wait_for_data_end_time =
|
| - server_info_->wait_for_data_end_time();
|
| - if (!wait_for_data_start_time.is_null() &&
|
| - !wait_for_data_end_time.is_null()) {
|
| - base::TimeDelta wait_time =
|
| - wait_for_data_end_time - wait_for_data_start_time;
|
| - const base::HistogramBase::Sample kMaxWaitToRtt = 1000;
|
| - base::HistogramBase::Sample wait_to_rtt =
|
| - static_cast<base::HistogramBase::Sample>(
|
| - 100 * wait_time.InMicroseconds() / stats.min_rtt_us);
|
| - UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicServerInfo.WaitForDataReadyToRtt",
|
| - wait_to_rtt, 0, kMaxWaitToRtt, 50);
|
| - }
|
| - }
|
| -
|
| - if (stats.max_sequence_reordering == 0)
|
| - return;
|
| - const base::HistogramBase::Sample kMaxReordering = 100;
|
| - base::HistogramBase::Sample reordering = kMaxReordering;
|
| - if (stats.min_rtt_us > 0) {
|
| - reordering = static_cast<base::HistogramBase::Sample>(
|
| - 100 * stats.max_time_reordering_us / stats.min_rtt_us);
|
| - }
|
| - UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime",
|
| - reordering, 0, kMaxReordering, 50);
|
| - if (stats.min_rtt_us > 100 * 1000) {
|
| - UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
|
| - reordering, 0, kMaxReordering, 50);
|
| - }
|
| - UMA_HISTOGRAM_COUNTS(
|
| - "Net.QuicSession.MaxReordering",
|
| - static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
|
| -}
|
| -
|
| -void QuicClientSession::OnStreamFrames(
|
| - const std::vector<QuicStreamFrame>& frames) {
|
| - // Record total number of stream frames.
|
| - UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames.size());
|
| -
|
| - // Record number of frames per stream in packet.
|
| - typedef std::map<QuicStreamId, size_t> FrameCounter;
|
| - FrameCounter frames_per_stream;
|
| - for (size_t i = 0; i < frames.size(); ++i) {
|
| - frames_per_stream[frames[i].stream_id]++;
|
| - }
|
| - for (FrameCounter::const_iterator it = frames_per_stream.begin();
|
| - it != frames_per_stream.end(); ++it) {
|
| - UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
|
| - it->second);
|
| - }
|
| -
|
| - return QuicSession::OnStreamFrames(frames);
|
| -}
|
| -
|
| -void QuicClientSession::AddObserver(Observer* observer) {
|
| - if (going_away_) {
|
| - RecordUnexpectedObservers(ADD_OBSERVER);
|
| - observer->OnSessionClosed(ERR_UNEXPECTED);
|
| - return;
|
| - }
|
| -
|
| - DCHECK(!ContainsKey(observers_, observer));
|
| - observers_.insert(observer);
|
| -}
|
| -
|
| -void QuicClientSession::RemoveObserver(Observer* observer) {
|
| - DCHECK(ContainsKey(observers_, observer));
|
| - observers_.erase(observer);
|
| -}
|
| -
|
| -int QuicClientSession::TryCreateStream(StreamRequest* request,
|
| - QuicReliableClientStream** stream) {
|
| - if (!crypto_stream_->encryption_established()) {
|
| - DLOG(DFATAL) << "Encryption not established.";
|
| - return ERR_CONNECTION_CLOSED;
|
| - }
|
| -
|
| - if (goaway_received()) {
|
| - DVLOG(1) << "Going away.";
|
| - return ERR_CONNECTION_CLOSED;
|
| - }
|
| -
|
| - if (!connection()->connected()) {
|
| - DVLOG(1) << "Already closed.";
|
| - return ERR_CONNECTION_CLOSED;
|
| - }
|
| -
|
| - if (going_away_) {
|
| - RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
|
| - return ERR_CONNECTION_CLOSED;
|
| - }
|
| -
|
| - if (GetNumOpenStreams() < get_max_open_streams()) {
|
| - *stream = CreateOutgoingReliableStreamImpl();
|
| - return OK;
|
| - }
|
| -
|
| - stream_requests_.push_back(request);
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -void QuicClientSession::CancelRequest(StreamRequest* request) {
|
| - // Remove |request| from the queue while preserving the order of the
|
| - // other elements.
|
| - StreamRequestQueue::iterator it =
|
| - std::find(stream_requests_.begin(), stream_requests_.end(), request);
|
| - if (it != stream_requests_.end()) {
|
| - it = stream_requests_.erase(it);
|
| - }
|
| -}
|
| -
|
| -QuicReliableClientStream* QuicClientSession::CreateOutgoingDataStream() {
|
| - if (!crypto_stream_->encryption_established()) {
|
| - DVLOG(1) << "Encryption not active so no outgoing stream created.";
|
| - return nullptr;
|
| - }
|
| - if (GetNumOpenStreams() >= get_max_open_streams()) {
|
| - DVLOG(1) << "Failed to create a new outgoing stream. "
|
| - << "Already " << GetNumOpenStreams() << " open.";
|
| - return nullptr;
|
| - }
|
| - if (goaway_received()) {
|
| - DVLOG(1) << "Failed to create a new outgoing stream. "
|
| - << "Already received goaway.";
|
| - return nullptr;
|
| - }
|
| - if (going_away_) {
|
| - RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
|
| - return nullptr;
|
| - }
|
| - return CreateOutgoingReliableStreamImpl();
|
| -}
|
| -
|
| -QuicReliableClientStream*
|
| -QuicClientSession::CreateOutgoingReliableStreamImpl() {
|
| - DCHECK(connection()->connected());
|
| - QuicReliableClientStream* stream =
|
| - new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
|
| - ActivateStream(stream);
|
| - ++num_total_streams_;
|
| - UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
|
| - return stream;
|
| -}
|
| -
|
| -QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
|
| - return crypto_stream_.get();
|
| -};
|
| -
|
| -// TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
|
| -// we learn about SSL info (sync vs async vs cached).
|
| -bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
|
| - ssl_info->Reset();
|
| - if (!cert_verify_result_) {
|
| - return false;
|
| - }
|
| -
|
| - ssl_info->cert_status = cert_verify_result_->cert_status;
|
| - ssl_info->cert = cert_verify_result_->verified_cert;
|
| -
|
| - // TODO(wtc): Define QUIC "cipher suites".
|
| - // Report the TLS cipher suite that most closely resembles the crypto
|
| - // parameters of the QUIC connection.
|
| - QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
|
| - uint16 cipher_suite;
|
| - int security_bits;
|
| - switch (aead) {
|
| - case kAESG:
|
| - cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
| - security_bits = 128;
|
| - break;
|
| - case kCC12:
|
| - cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
|
| - security_bits = 256;
|
| - break;
|
| - default:
|
| - NOTREACHED();
|
| - return false;
|
| - }
|
| - int ssl_connection_status = 0;
|
| - ssl_connection_status |= cipher_suite;
|
| - ssl_connection_status |=
|
| - (SSL_CONNECTION_VERSION_QUIC & SSL_CONNECTION_VERSION_MASK) <<
|
| - SSL_CONNECTION_VERSION_SHIFT;
|
| -
|
| - ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
|
| - ssl_info->is_issued_by_known_root =
|
| - cert_verify_result_->is_issued_by_known_root;
|
| -
|
| - ssl_info->connection_status = ssl_connection_status;
|
| - ssl_info->client_cert_sent = false;
|
| - ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent();
|
| - ssl_info->security_bits = security_bits;
|
| - ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
|
| - ssl_info->pinning_failure_log = pinning_failure_log_;
|
| - return true;
|
| -}
|
| -
|
| -int QuicClientSession::CryptoConnect(bool require_confirmation,
|
| - const CompletionCallback& callback) {
|
| - require_confirmation_ = require_confirmation;
|
| - handshake_start_ = base::TimeTicks::Now();
|
| - RecordHandshakeState(STATE_STARTED);
|
| - DCHECK(flow_controller());
|
| - crypto_stream_->CryptoConnect();
|
| -
|
| - if (IsCryptoHandshakeConfirmed())
|
| - return OK;
|
| -
|
| - // Unless we require handshake confirmation, activate the session if
|
| - // we have established initial encryption.
|
| - if (!require_confirmation_ && IsEncryptionEstablished()) {
|
| - // To mitigate the effects of hanging 0-RTT connections, set up a timer to
|
| - // cancel any requests, if the handshake takes too long.
|
| - task_runner_->PostDelayedTask(
|
| - FROM_HERE,
|
| - base::Bind(&QuicClientSession::OnConnectTimeout,
|
| - weak_factory_.GetWeakPtr()),
|
| - base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs));
|
| - return OK;
|
| -
|
| - }
|
| -
|
| - callback_ = callback;
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -int QuicClientSession::ResumeCryptoConnect(const CompletionCallback& callback) {
|
| -
|
| - if (IsCryptoHandshakeConfirmed())
|
| - return OK;
|
| -
|
| - if (!connection()->connected())
|
| - return ERR_QUIC_HANDSHAKE_FAILED;
|
| -
|
| - callback_ = callback;
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -int QuicClientSession::GetNumSentClientHellos() const {
|
| - return crypto_stream_->num_sent_client_hellos();
|
| -}
|
| -
|
| -bool QuicClientSession::CanPool(const std::string& hostname,
|
| - PrivacyMode privacy_mode) const {
|
| - DCHECK(connection()->connected());
|
| - if (privacy_mode != server_id_.privacy_mode()) {
|
| - // Privacy mode must always match.
|
| - return false;
|
| - }
|
| - SSLInfo ssl_info;
|
| - if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
|
| - // We can always pool with insecure QUIC sessions.
|
| - return true;
|
| - }
|
| -
|
| - return SpdySession::CanPool(transport_security_state_, ssl_info,
|
| - server_id_.host(), hostname);
|
| -}
|
| -
|
| -QuicDataStream* QuicClientSession::CreateIncomingDataStream(
|
| - QuicStreamId id) {
|
| - DLOG(ERROR) << "Server push not supported";
|
| - return nullptr;
|
| -}
|
| -
|
| -void QuicClientSession::CloseStream(QuicStreamId stream_id) {
|
| - ReliableQuicStream* stream = GetStream(stream_id);
|
| - if (stream) {
|
| - logger_->UpdateReceivedFrameCounts(
|
| - stream_id, stream->num_frames_received(),
|
| - stream->num_duplicate_frames_received());
|
| - }
|
| - QuicSession::CloseStream(stream_id);
|
| - OnClosedStream();
|
| -}
|
| -
|
| -void QuicClientSession::SendRstStream(QuicStreamId id,
|
| - QuicRstStreamErrorCode error,
|
| - QuicStreamOffset bytes_written) {
|
| - QuicSession::SendRstStream(id, error, bytes_written);
|
| - OnClosedStream();
|
| -}
|
| -
|
| -void QuicClientSession::OnClosedStream() {
|
| - if (GetNumOpenStreams() < get_max_open_streams() &&
|
| - !stream_requests_.empty() &&
|
| - crypto_stream_->encryption_established() &&
|
| - !goaway_received() &&
|
| - !going_away_ &&
|
| - connection()->connected()) {
|
| - StreamRequest* request = stream_requests_.front();
|
| - stream_requests_.pop_front();
|
| - request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
|
| - }
|
| -
|
| - if (GetNumOpenStreams() == 0) {
|
| - stream_factory_->OnIdleSession(this);
|
| - }
|
| -}
|
| -
|
| -void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
|
| - if (!callback_.is_null() &&
|
| - (!require_confirmation_ ||
|
| - event == HANDSHAKE_CONFIRMED || event == ENCRYPTION_REESTABLISHED)) {
|
| - // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
|
| - // could be called because there are no error events in CryptoHandshakeEvent
|
| - // enum. If error events are added to CryptoHandshakeEvent, then the
|
| - // following code needs to changed.
|
| - base::ResetAndReturn(&callback_).Run(OK);
|
| - }
|
| - if (event == HANDSHAKE_CONFIRMED) {
|
| - UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime",
|
| - base::TimeTicks::Now() - handshake_start_);
|
| - if (server_info_) {
|
| - // Track how long it has taken to finish handshake once we start waiting
|
| - // for reading of QUIC server information from disk cache. We could use
|
| - // this data to compare total time taken if we were to cancel the disk
|
| - // cache read vs waiting for the read to complete.
|
| - base::TimeTicks wait_for_data_start_time =
|
| - server_info_->wait_for_data_start_time();
|
| - if (!wait_for_data_start_time.is_null()) {
|
| - UMA_HISTOGRAM_TIMES(
|
| - "Net.QuicServerInfo.WaitForDataReady.HandshakeConfirmedTime",
|
| - base::TimeTicks::Now() - wait_for_data_start_time);
|
| - }
|
| - }
|
| -
|
| - ObserverSet::iterator it = observers_.begin();
|
| - while (it != observers_.end()) {
|
| - Observer* observer = *it;
|
| - ++it;
|
| - observer->OnCryptoHandshakeConfirmed();
|
| - }
|
| - if (server_info_)
|
| - server_info_->OnExternalCacheHit();
|
| - }
|
| - QuicSession::OnCryptoHandshakeEvent(event);
|
| -}
|
| -
|
| -void QuicClientSession::OnCryptoHandshakeMessageSent(
|
| - const CryptoHandshakeMessage& message) {
|
| - logger_->OnCryptoHandshakeMessageSent(message);
|
| -}
|
| -
|
| -void QuicClientSession::OnCryptoHandshakeMessageReceived(
|
| - const CryptoHandshakeMessage& message) {
|
| - logger_->OnCryptoHandshakeMessageReceived(message);
|
| -}
|
| -
|
| -void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
|
| - bool from_peer) {
|
| - DCHECK(!connection()->connected());
|
| - logger_->OnConnectionClosed(error, from_peer);
|
| - if (from_peer) {
|
| - UMA_HISTOGRAM_SPARSE_SLOWLY(
|
| - "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
|
| - } else {
|
| - UMA_HISTOGRAM_SPARSE_SLOWLY(
|
| - "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
|
| - }
|
| -
|
| - if (error == QUIC_CONNECTION_TIMED_OUT) {
|
| - UMA_HISTOGRAM_COUNTS(
|
| - "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
|
| - GetNumOpenStreams());
|
| - if (IsCryptoHandshakeConfirmed()) {
|
| - if (GetNumOpenStreams() > 0) {
|
| - UMA_HISTOGRAM_BOOLEAN(
|
| - "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
|
| - connection()->sent_packet_manager().HasUnackedPackets());
|
| - UMA_HISTOGRAM_COUNTS(
|
| - "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
|
| - connection()->sent_packet_manager().consecutive_rto_count());
|
| - UMA_HISTOGRAM_COUNTS(
|
| - "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
|
| - connection()->sent_packet_manager().consecutive_tlp_count());
|
| - }
|
| - if (connection()->sent_packet_manager().HasUnackedPackets()) {
|
| - UMA_HISTOGRAM_TIMES(
|
| - "Net.QuicSession.LocallyTimedOutWithOpenStreams."
|
| - "TimeSinceLastReceived.UnackedPackets",
|
| - NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
|
| - } else {
|
| - UMA_HISTOGRAM_TIMES(
|
| - "Net.QuicSession.LocallyTimedOutWithOpenStreams."
|
| - "TimeSinceLastReceived.NoUnackedPackets",
|
| - NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
|
| - }
|
| -
|
| - } else {
|
| - UMA_HISTOGRAM_COUNTS(
|
| - "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
|
| - GetNumOpenStreams());
|
| - UMA_HISTOGRAM_COUNTS(
|
| - "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
|
| - num_total_streams_);
|
| - }
|
| - }
|
| -
|
| - if (!IsCryptoHandshakeConfirmed()) {
|
| - if (error == QUIC_PUBLIC_RESET) {
|
| - RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
|
| - } else if (connection()->GetStats().packets_received == 0) {
|
| - RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
|
| - UMA_HISTOGRAM_SPARSE_SLOWLY(
|
| - "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
|
| - error);
|
| - } else {
|
| - RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
|
| - UMA_HISTOGRAM_SPARSE_SLOWLY(
|
| - "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
|
| - error);
|
| - }
|
| - }
|
| -
|
| - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
|
| - connection()->version());
|
| - NotifyFactoryOfSessionGoingAway();
|
| - if (!callback_.is_null()) {
|
| - base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
|
| - }
|
| - socket_->Close();
|
| - QuicSession::OnConnectionClosed(error, from_peer);
|
| - DCHECK(streams()->empty());
|
| - CloseAllStreams(ERR_UNEXPECTED);
|
| - CloseAllObservers(ERR_UNEXPECTED);
|
| - NotifyFactoryOfSessionClosedLater();
|
| -}
|
| -
|
| -void QuicClientSession::OnSuccessfulVersionNegotiation(
|
| - const QuicVersion& version) {
|
| - logger_->OnSuccessfulVersionNegotiation(version);
|
| - QuicSession::OnSuccessfulVersionNegotiation(version);
|
| -}
|
| -
|
| -void QuicClientSession::OnProofValid(
|
| - const QuicCryptoClientConfig::CachedState& cached) {
|
| - DCHECK(cached.proof_valid());
|
| -
|
| - if (!server_info_) {
|
| - return;
|
| - }
|
| -
|
| - QuicServerInfo::State* state = server_info_->mutable_state();
|
| -
|
| - state->server_config = cached.server_config();
|
| - state->source_address_token = cached.source_address_token();
|
| - state->server_config_sig = cached.signature();
|
| - state->certs = cached.certs();
|
| -
|
| - server_info_->Persist();
|
| -}
|
| -
|
| -void QuicClientSession::OnProofVerifyDetailsAvailable(
|
| - const ProofVerifyDetails& verify_details) {
|
| - const ProofVerifyDetailsChromium* verify_details_chromium =
|
| - reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
|
| - CertVerifyResult* result_copy = new CertVerifyResult;
|
| - result_copy->CopyFrom(verify_details_chromium->cert_verify_result);
|
| - cert_verify_result_.reset(result_copy);
|
| - pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
|
| - logger_->OnCertificateVerified(*cert_verify_result_);
|
| -}
|
| -
|
| -void QuicClientSession::StartReading() {
|
| - if (read_pending_) {
|
| - return;
|
| - }
|
| - read_pending_ = true;
|
| - int rv = socket_->Read(read_buffer_.get(),
|
| - read_buffer_->size(),
|
| - base::Bind(&QuicClientSession::OnReadComplete,
|
| - weak_factory_.GetWeakPtr()));
|
| - UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING);
|
| - if (rv == ERR_IO_PENDING) {
|
| - num_packets_read_ = 0;
|
| - return;
|
| - }
|
| -
|
| - if (++num_packets_read_ > 32) {
|
| - num_packets_read_ = 0;
|
| - // Data was read, process it.
|
| - // Schedule the work through the message loop to 1) prevent infinite
|
| - // recursion and 2) avoid blocking the thread for too long.
|
| - base::MessageLoop::current()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&QuicClientSession::OnReadComplete,
|
| - weak_factory_.GetWeakPtr(), rv));
|
| - } else {
|
| - OnReadComplete(rv);
|
| - }
|
| -}
|
| -
|
| -void QuicClientSession::CloseSessionOnError(int error) {
|
| - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
|
| - CloseSessionOnErrorInner(error, QUIC_INTERNAL_ERROR);
|
| - NotifyFactoryOfSessionClosed();
|
| -}
|
| -
|
| -void QuicClientSession::CloseSessionOnErrorInner(int net_error,
|
| - QuicErrorCode quic_error) {
|
| - if (!callback_.is_null()) {
|
| - base::ResetAndReturn(&callback_).Run(net_error);
|
| - }
|
| - CloseAllStreams(net_error);
|
| - CloseAllObservers(net_error);
|
| - net_log_.AddEvent(
|
| - NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
|
| - NetLog::IntegerCallback("net_error", net_error));
|
| -
|
| - if (connection()->connected())
|
| - connection()->CloseConnection(quic_error, false);
|
| - DCHECK(!connection()->connected());
|
| -}
|
| -
|
| -void QuicClientSession::CloseAllStreams(int net_error) {
|
| - while (!streams()->empty()) {
|
| - ReliableQuicStream* stream = streams()->begin()->second;
|
| - QuicStreamId id = stream->id();
|
| - static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
|
| - CloseStream(id);
|
| - }
|
| -}
|
| -
|
| -void QuicClientSession::CloseAllObservers(int net_error) {
|
| - while (!observers_.empty()) {
|
| - Observer* observer = *observers_.begin();
|
| - observers_.erase(observer);
|
| - observer->OnSessionClosed(net_error);
|
| - }
|
| -}
|
| -
|
| -base::Value* QuicClientSession::GetInfoAsValue(
|
| - const std::set<HostPortPair>& aliases) {
|
| - base::DictionaryValue* dict = new base::DictionaryValue();
|
| - dict->SetString("version", QuicVersionToString(connection()->version()));
|
| - dict->SetInteger("open_streams", GetNumOpenStreams());
|
| - base::ListValue* stream_list = new base::ListValue();
|
| - for (base::hash_map<QuicStreamId, QuicDataStream*>::const_iterator it
|
| - = streams()->begin();
|
| - it != streams()->end();
|
| - ++it) {
|
| - stream_list->Append(new base::StringValue(
|
| - base::Uint64ToString(it->second->id())));
|
| - }
|
| - dict->Set("active_streams", stream_list);
|
| -
|
| - dict->SetInteger("total_streams", num_total_streams_);
|
| - dict->SetString("peer_address", peer_address().ToString());
|
| - dict->SetString("connection_id", base::Uint64ToString(connection_id()));
|
| - dict->SetBoolean("connected", connection()->connected());
|
| - const QuicConnectionStats& stats = connection()->GetStats();
|
| - dict->SetInteger("packets_sent", stats.packets_sent);
|
| - dict->SetInteger("packets_received", stats.packets_received);
|
| - dict->SetInteger("packets_lost", stats.packets_lost);
|
| - SSLInfo ssl_info;
|
| - dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
|
| -
|
| - base::ListValue* alias_list = new base::ListValue();
|
| - for (std::set<HostPortPair>::const_iterator it = aliases.begin();
|
| - it != aliases.end(); it++) {
|
| - alias_list->Append(new base::StringValue(it->ToString()));
|
| - }
|
| - dict->Set("aliases", alias_list);
|
| -
|
| - return dict;
|
| -}
|
| -
|
| -base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
|
| - return weak_factory_.GetWeakPtr();
|
| -}
|
| -
|
| -void QuicClientSession::OnReadComplete(int result) {
|
| - read_pending_ = false;
|
| - if (result == 0)
|
| - result = ERR_CONNECTION_CLOSED;
|
| -
|
| - if (result < 0) {
|
| - DVLOG(1) << "Closing session on read error: " << result;
|
| - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
|
| - NotifyFactoryOfSessionGoingAway();
|
| - CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
|
| - NotifyFactoryOfSessionClosedLater();
|
| - return;
|
| - }
|
| -
|
| - QuicEncryptedPacket packet(read_buffer_->data(), result);
|
| - IPEndPoint local_address;
|
| - IPEndPoint peer_address;
|
| - socket_->GetLocalAddress(&local_address);
|
| - socket_->GetPeerAddress(&peer_address);
|
| - // ProcessUdpPacket might result in |this| being deleted, so we
|
| - // use a weak pointer to be safe.
|
| - connection()->ProcessUdpPacket(local_address, peer_address, packet);
|
| - if (!connection()->connected()) {
|
| - NotifyFactoryOfSessionClosedLater();
|
| - return;
|
| - }
|
| - StartReading();
|
| -}
|
| -
|
| -void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
|
| - going_away_ = true;
|
| - if (stream_factory_)
|
| - stream_factory_->OnSessionGoingAway(this);
|
| -}
|
| -
|
| -void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
|
| - if (!streams()->empty())
|
| - RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
|
| -
|
| - if (!going_away_)
|
| - RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
|
| -
|
| - going_away_ = true;
|
| - DCHECK_EQ(0u, GetNumOpenStreams());
|
| - DCHECK(!connection()->connected());
|
| - base::MessageLoop::current()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
|
| - weak_factory_.GetWeakPtr()));
|
| -}
|
| -
|
| -void QuicClientSession::NotifyFactoryOfSessionClosed() {
|
| - if (!streams()->empty())
|
| - RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
|
| -
|
| - if (!going_away_)
|
| - RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
|
| -
|
| - going_away_ = true;
|
| - DCHECK_EQ(0u, GetNumOpenStreams());
|
| - // Will delete |this|.
|
| - if (stream_factory_)
|
| - stream_factory_->OnSessionClosed(this);
|
| -}
|
| -
|
| -void QuicClientSession::OnConnectTimeout() {
|
| - DCHECK(callback_.is_null());
|
| - DCHECK(IsEncryptionEstablished());
|
| -
|
| - if (IsCryptoHandshakeConfirmed())
|
| - return;
|
| -
|
| - // TODO(rch): re-enable this code once beta is cut.
|
| - // if (stream_factory_)
|
| - // stream_factory_->OnSessionConnectTimeout(this);
|
| - // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
|
| - // DCHECK_EQ(0u, GetNumOpenStreams());
|
| -}
|
| -
|
| -} // namespace net
|
|
|