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 |