Revert of Add support for escaped target names in isolate driver. (patchset #6 id...
[chromium-blink-merge.git] / net / quic / quic_client_session.cc
blobdf26856f520ad50a5bd7dd07a0f08c783bacaaf6
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/quic/quic_client_session.h"
7 #include "base/callback_helpers.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/metrics/histogram.h"
10 #include "base/metrics/sparse_histogram.h"
11 #include "base/profiler/scoped_tracker.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/values.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/network_activity_monitor.h"
18 #include "net/http/transport_security_state.h"
19 #include "net/quic/crypto/proof_verifier_chromium.h"
20 #include "net/quic/crypto/quic_server_info.h"
21 #include "net/quic/quic_connection_helper.h"
22 #include "net/quic/quic_crypto_client_stream_factory.h"
23 #include "net/quic/quic_server_id.h"
24 #include "net/quic/quic_stream_factory.h"
25 #include "net/spdy/spdy_session.h"
26 #include "net/ssl/channel_id_service.h"
27 #include "net/ssl/ssl_connection_status_flags.h"
28 #include "net/ssl/ssl_info.h"
29 #include "net/udp/datagram_client_socket.h"
31 namespace net {
33 namespace {
35 // The length of time to wait for a 0-RTT handshake to complete
36 // before allowing the requests to possibly proceed over TCP.
37 const int k0RttHandshakeTimeoutMs = 300;
39 // IPv6 packets have an additional 20 bytes of overhead than IPv4 packets.
40 const size_t kAdditionalOverheadForIPv6 = 20;
42 // Histograms for tracking down the crashes from http://crbug.com/354669
43 // Note: these values must be kept in sync with the corresponding values in:
44 // tools/metrics/histograms/histograms.xml
45 enum Location {
46 DESTRUCTOR = 0,
47 ADD_OBSERVER = 1,
48 TRY_CREATE_STREAM = 2,
49 CREATE_OUTGOING_RELIABLE_STREAM = 3,
50 NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER = 4,
51 NOTIFY_FACTORY_OF_SESSION_CLOSED = 5,
52 NUM_LOCATIONS = 6,
55 void RecordUnexpectedOpenStreams(Location location) {
56 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
57 NUM_LOCATIONS);
60 void RecordUnexpectedObservers(Location location) {
61 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
62 NUM_LOCATIONS);
65 void RecordUnexpectedNotGoingAway(Location location) {
66 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
67 NUM_LOCATIONS);
70 // Histogram for recording the different reasons that a QUIC session is unable
71 // to complete the handshake.
72 enum HandshakeFailureReason {
73 HANDSHAKE_FAILURE_UNKNOWN = 0,
74 HANDSHAKE_FAILURE_BLACK_HOLE = 1,
75 HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
76 NUM_HANDSHAKE_FAILURE_REASONS = 3,
79 void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
80 UMA_HISTOGRAM_ENUMERATION(
81 "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason",
82 reason, NUM_HANDSHAKE_FAILURE_REASONS);
85 // Note: these values must be kept in sync with the corresponding values in:
86 // tools/metrics/histograms/histograms.xml
87 enum HandshakeState {
88 STATE_STARTED = 0,
89 STATE_ENCRYPTION_ESTABLISHED = 1,
90 STATE_HANDSHAKE_CONFIRMED = 2,
91 STATE_FAILED = 3,
92 NUM_HANDSHAKE_STATES = 4
95 void RecordHandshakeState(HandshakeState state) {
96 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
97 NUM_HANDSHAKE_STATES);
100 base::Value* NetLogQuicClientSessionCallback(
101 const QuicServerId* server_id,
102 bool require_confirmation,
103 NetLog::LogLevel /* log_level */) {
104 base::DictionaryValue* dict = new base::DictionaryValue();
105 dict->SetString("host", server_id->host());
106 dict->SetInteger("port", server_id->port());
107 dict->SetBoolean("is_https", server_id->is_https());
108 dict->SetBoolean("privacy_mode",
109 server_id->privacy_mode() == PRIVACY_MODE_ENABLED);
110 dict->SetBoolean("require_confirmation", require_confirmation);
111 return dict;
114 } // namespace
116 QuicClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
118 QuicClientSession::StreamRequest::~StreamRequest() {
119 CancelRequest();
122 int QuicClientSession::StreamRequest::StartRequest(
123 const base::WeakPtr<QuicClientSession>& session,
124 QuicReliableClientStream** stream,
125 const CompletionCallback& callback) {
126 session_ = session;
127 stream_ = stream;
128 int rv = session_->TryCreateStream(this, stream_);
129 if (rv == ERR_IO_PENDING) {
130 callback_ = callback;
133 return rv;
136 void QuicClientSession::StreamRequest::CancelRequest() {
137 if (session_)
138 session_->CancelRequest(this);
139 session_.reset();
140 callback_.Reset();
143 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
144 QuicReliableClientStream* stream) {
145 session_.reset();
146 *stream_ = stream;
147 ResetAndReturn(&callback_).Run(OK);
150 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
151 session_.reset();
152 ResetAndReturn(&callback_).Run(rv);
155 QuicClientSession::QuicClientSession(
156 QuicConnection* connection,
157 scoped_ptr<DatagramClientSocket> socket,
158 QuicStreamFactory* stream_factory,
159 TransportSecurityState* transport_security_state,
160 scoped_ptr<QuicServerInfo> server_info,
161 const QuicConfig& config,
162 const char* const connection_description,
163 base::TimeTicks dns_resolution_end_time,
164 base::TaskRunner* task_runner,
165 NetLog* net_log)
166 : QuicClientSessionBase(connection, config),
167 require_confirmation_(false),
168 stream_factory_(stream_factory),
169 socket_(socket.Pass()),
170 read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
171 transport_security_state_(transport_security_state),
172 server_info_(server_info.Pass()),
173 read_pending_(false),
174 num_total_streams_(0),
175 task_runner_(task_runner),
176 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
177 dns_resolution_end_time_(dns_resolution_end_time),
178 logger_(new QuicConnectionLogger(this, connection_description, net_log_)),
179 num_packets_read_(0),
180 going_away_(false),
181 weak_factory_(this) {
182 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
183 tracked_objects::ScopedTracker tracking_profile1(
184 FROM_HERE_WITH_EXPLICIT_FUNCTION(
185 "422516 QuicClientSession::QuicClientSession1"));
187 connection->set_debug_visitor(logger_.get());
188 IPEndPoint address;
189 // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed.
190 tracked_objects::ScopedTracker tracking_profile2(
191 FROM_HERE_WITH_EXPLICIT_FUNCTION(
192 "422516 QuicClientSession::QuicClientSession2"));
193 if (socket && socket->GetLocalAddress(&address) == OK &&
194 address.GetFamily() == ADDRESS_FAMILY_IPV6) {
195 connection->set_max_packet_length(
196 connection->max_packet_length() - kAdditionalOverheadForIPv6);
200 void QuicClientSession::InitializeSession(
201 const QuicServerId& server_id,
202 QuicCryptoClientConfig* crypto_config,
203 QuicCryptoClientStreamFactory* crypto_client_stream_factory) {
204 server_id_ = server_id;
205 crypto_stream_.reset(
206 crypto_client_stream_factory ?
207 crypto_client_stream_factory->CreateQuicCryptoClientStream(
208 server_id, this, crypto_config) :
209 new QuicCryptoClientStream(server_id, this,
210 new ProofVerifyContextChromium(net_log_),
211 crypto_config));
212 QuicClientSessionBase::InitializeSession();
213 // TODO(rch): pass in full host port proxy pair
214 net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION,
215 base::Bind(NetLogQuicClientSessionCallback,
216 &server_id,
217 require_confirmation_));
220 QuicClientSession::~QuicClientSession() {
221 if (!streams()->empty())
222 RecordUnexpectedOpenStreams(DESTRUCTOR);
223 if (!observers_.empty())
224 RecordUnexpectedObservers(DESTRUCTOR);
225 if (!going_away_)
226 RecordUnexpectedNotGoingAway(DESTRUCTOR);
228 while (!streams()->empty() ||
229 !observers_.empty() ||
230 !stream_requests_.empty()) {
231 // The session must be closed before it is destroyed.
232 DCHECK(streams()->empty());
233 CloseAllStreams(ERR_UNEXPECTED);
234 DCHECK(observers_.empty());
235 CloseAllObservers(ERR_UNEXPECTED);
237 connection()->set_debug_visitor(nullptr);
238 net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
240 while (!stream_requests_.empty()) {
241 StreamRequest* request = stream_requests_.front();
242 stream_requests_.pop_front();
243 request->OnRequestCompleteFailure(ERR_ABORTED);
247 if (connection()->connected()) {
248 // Ensure that the connection is closed by the time the session is
249 // destroyed.
250 connection()->CloseConnection(QUIC_INTERNAL_ERROR, false);
253 if (IsEncryptionEstablished())
254 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
255 if (IsCryptoHandshakeConfirmed())
256 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
257 else
258 RecordHandshakeState(STATE_FAILED);
260 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
261 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
262 crypto_stream_->num_sent_client_hellos());
263 if (!IsCryptoHandshakeConfirmed())
264 return;
266 // Sending one client_hello means we had zero handshake-round-trips.
267 int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
269 // Don't bother with these histogram during tests, which mock out
270 // num_sent_client_hellos().
271 if (round_trip_handshakes < 0 || !stream_factory_)
272 return;
274 bool port_selected = stream_factory_->enable_port_selection();
275 SSLInfo ssl_info;
276 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
277 if (port_selected) {
278 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
279 round_trip_handshakes, 0, 3, 4);
280 } else {
281 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
282 round_trip_handshakes, 0, 3, 4);
283 if (require_confirmation_) {
284 UMA_HISTOGRAM_CUSTOM_COUNTS(
285 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
286 round_trip_handshakes, 0, 3, 4);
289 } else {
290 if (port_selected) {
291 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
292 round_trip_handshakes, 0, 3, 4);
293 } else {
294 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
295 round_trip_handshakes, 0, 3, 4);
296 if (require_confirmation_) {
297 UMA_HISTOGRAM_CUSTOM_COUNTS(
298 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
299 round_trip_handshakes, 0, 3, 4);
303 const QuicConnectionStats stats = connection()->GetStats();
304 if (server_info_ && stats.min_rtt_us > 0) {
305 base::TimeTicks wait_for_data_start_time =
306 server_info_->wait_for_data_start_time();
307 base::TimeTicks wait_for_data_end_time =
308 server_info_->wait_for_data_end_time();
309 if (!wait_for_data_start_time.is_null() &&
310 !wait_for_data_end_time.is_null()) {
311 base::TimeDelta wait_time =
312 wait_for_data_end_time - wait_for_data_start_time;
313 const base::HistogramBase::Sample kMaxWaitToRtt = 1000;
314 base::HistogramBase::Sample wait_to_rtt =
315 static_cast<base::HistogramBase::Sample>(
316 100 * wait_time.InMicroseconds() / stats.min_rtt_us);
317 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicServerInfo.WaitForDataReadyToRtt",
318 wait_to_rtt, 0, kMaxWaitToRtt, 50);
322 if (stats.max_sequence_reordering == 0)
323 return;
324 const base::HistogramBase::Sample kMaxReordering = 100;
325 base::HistogramBase::Sample reordering = kMaxReordering;
326 if (stats.min_rtt_us > 0) {
327 reordering = static_cast<base::HistogramBase::Sample>(
328 100 * stats.max_time_reordering_us / stats.min_rtt_us);
330 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime",
331 reordering, 0, kMaxReordering, 50);
332 if (stats.min_rtt_us > 100 * 1000) {
333 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
334 reordering, 0, kMaxReordering, 50);
336 UMA_HISTOGRAM_COUNTS(
337 "Net.QuicSession.MaxReordering",
338 static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
341 void QuicClientSession::OnStreamFrames(
342 const std::vector<QuicStreamFrame>& frames) {
343 // Record total number of stream frames.
344 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames.size());
346 // Record number of frames per stream in packet.
347 typedef std::map<QuicStreamId, size_t> FrameCounter;
348 FrameCounter frames_per_stream;
349 for (size_t i = 0; i < frames.size(); ++i) {
350 frames_per_stream[frames[i].stream_id]++;
352 for (FrameCounter::const_iterator it = frames_per_stream.begin();
353 it != frames_per_stream.end(); ++it) {
354 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
355 it->second);
358 return QuicSession::OnStreamFrames(frames);
361 void QuicClientSession::AddObserver(Observer* observer) {
362 if (going_away_) {
363 RecordUnexpectedObservers(ADD_OBSERVER);
364 observer->OnSessionClosed(ERR_UNEXPECTED);
365 return;
368 DCHECK(!ContainsKey(observers_, observer));
369 observers_.insert(observer);
372 void QuicClientSession::RemoveObserver(Observer* observer) {
373 DCHECK(ContainsKey(observers_, observer));
374 observers_.erase(observer);
377 int QuicClientSession::TryCreateStream(StreamRequest* request,
378 QuicReliableClientStream** stream) {
379 if (!crypto_stream_->encryption_established()) {
380 DLOG(DFATAL) << "Encryption not established.";
381 return ERR_CONNECTION_CLOSED;
384 if (goaway_received()) {
385 DVLOG(1) << "Going away.";
386 return ERR_CONNECTION_CLOSED;
389 if (!connection()->connected()) {
390 DVLOG(1) << "Already closed.";
391 return ERR_CONNECTION_CLOSED;
394 if (going_away_) {
395 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
396 return ERR_CONNECTION_CLOSED;
399 if (GetNumOpenStreams() < get_max_open_streams()) {
400 *stream = CreateOutgoingReliableStreamImpl();
401 return OK;
404 stream_requests_.push_back(request);
405 return ERR_IO_PENDING;
408 void QuicClientSession::CancelRequest(StreamRequest* request) {
409 // Remove |request| from the queue while preserving the order of the
410 // other elements.
411 StreamRequestQueue::iterator it =
412 std::find(stream_requests_.begin(), stream_requests_.end(), request);
413 if (it != stream_requests_.end()) {
414 it = stream_requests_.erase(it);
418 QuicReliableClientStream* QuicClientSession::CreateOutgoingDataStream() {
419 if (!crypto_stream_->encryption_established()) {
420 DVLOG(1) << "Encryption not active so no outgoing stream created.";
421 return nullptr;
423 if (GetNumOpenStreams() >= get_max_open_streams()) {
424 DVLOG(1) << "Failed to create a new outgoing stream. "
425 << "Already " << GetNumOpenStreams() << " open.";
426 return nullptr;
428 if (goaway_received()) {
429 DVLOG(1) << "Failed to create a new outgoing stream. "
430 << "Already received goaway.";
431 return nullptr;
433 if (going_away_) {
434 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
435 return nullptr;
437 return CreateOutgoingReliableStreamImpl();
440 QuicReliableClientStream*
441 QuicClientSession::CreateOutgoingReliableStreamImpl() {
442 DCHECK(connection()->connected());
443 QuicReliableClientStream* stream =
444 new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
445 ActivateStream(stream);
446 ++num_total_streams_;
447 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
448 return stream;
451 QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
452 return crypto_stream_.get();
455 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
456 // we learn about SSL info (sync vs async vs cached).
457 bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
458 ssl_info->Reset();
459 if (!cert_verify_result_) {
460 return false;
463 ssl_info->cert_status = cert_verify_result_->cert_status;
464 ssl_info->cert = cert_verify_result_->verified_cert;
466 // TODO(wtc): Define QUIC "cipher suites".
467 // Report the TLS cipher suite that most closely resembles the crypto
468 // parameters of the QUIC connection.
469 QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
470 uint16 cipher_suite;
471 int security_bits;
472 switch (aead) {
473 case kAESG:
474 cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
475 security_bits = 128;
476 break;
477 case kCC12:
478 cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
479 security_bits = 256;
480 break;
481 default:
482 NOTREACHED();
483 return false;
485 int ssl_connection_status = 0;
486 ssl_connection_status |= cipher_suite;
487 ssl_connection_status |=
488 (SSL_CONNECTION_VERSION_QUIC & SSL_CONNECTION_VERSION_MASK) <<
489 SSL_CONNECTION_VERSION_SHIFT;
491 ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
492 ssl_info->is_issued_by_known_root =
493 cert_verify_result_->is_issued_by_known_root;
495 ssl_info->connection_status = ssl_connection_status;
496 ssl_info->client_cert_sent = false;
497 ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent();
498 ssl_info->security_bits = security_bits;
499 ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
500 ssl_info->pinning_failure_log = pinning_failure_log_;
501 return true;
504 int QuicClientSession::CryptoConnect(bool require_confirmation,
505 const CompletionCallback& callback) {
506 require_confirmation_ = require_confirmation;
507 handshake_start_ = base::TimeTicks::Now();
508 RecordHandshakeState(STATE_STARTED);
509 DCHECK(flow_controller());
510 crypto_stream_->CryptoConnect();
512 if (IsCryptoHandshakeConfirmed())
513 return OK;
515 // Unless we require handshake confirmation, activate the session if
516 // we have established initial encryption.
517 if (!require_confirmation_ && IsEncryptionEstablished()) {
518 // To mitigate the effects of hanging 0-RTT connections, set up a timer to
519 // cancel any requests, if the handshake takes too long.
520 task_runner_->PostDelayedTask(
521 FROM_HERE,
522 base::Bind(&QuicClientSession::OnConnectTimeout,
523 weak_factory_.GetWeakPtr()),
524 base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs));
525 return OK;
529 callback_ = callback;
530 return ERR_IO_PENDING;
533 int QuicClientSession::ResumeCryptoConnect(const CompletionCallback& callback) {
535 if (IsCryptoHandshakeConfirmed())
536 return OK;
538 if (!connection()->connected())
539 return ERR_QUIC_HANDSHAKE_FAILED;
541 callback_ = callback;
542 return ERR_IO_PENDING;
545 int QuicClientSession::GetNumSentClientHellos() const {
546 return crypto_stream_->num_sent_client_hellos();
549 bool QuicClientSession::CanPool(const std::string& hostname,
550 PrivacyMode privacy_mode) const {
551 DCHECK(connection()->connected());
552 if (privacy_mode != server_id_.privacy_mode()) {
553 // Privacy mode must always match.
554 return false;
556 SSLInfo ssl_info;
557 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
558 // We can always pool with insecure QUIC sessions.
559 return true;
562 return SpdySession::CanPool(transport_security_state_, ssl_info,
563 server_id_.host(), hostname);
566 QuicDataStream* QuicClientSession::CreateIncomingDataStream(
567 QuicStreamId id) {
568 DLOG(ERROR) << "Server push not supported";
569 return nullptr;
572 void QuicClientSession::CloseStream(QuicStreamId stream_id) {
573 ReliableQuicStream* stream = GetStream(stream_id);
574 if (stream) {
575 logger_->UpdateReceivedFrameCounts(
576 stream_id, stream->num_frames_received(),
577 stream->num_duplicate_frames_received());
579 QuicSession::CloseStream(stream_id);
580 OnClosedStream();
583 void QuicClientSession::SendRstStream(QuicStreamId id,
584 QuicRstStreamErrorCode error,
585 QuicStreamOffset bytes_written) {
586 QuicSession::SendRstStream(id, error, bytes_written);
587 OnClosedStream();
590 void QuicClientSession::OnClosedStream() {
591 if (GetNumOpenStreams() < get_max_open_streams() &&
592 !stream_requests_.empty() &&
593 crypto_stream_->encryption_established() &&
594 !goaway_received() &&
595 !going_away_ &&
596 connection()->connected()) {
597 StreamRequest* request = stream_requests_.front();
598 stream_requests_.pop_front();
599 request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
602 if (GetNumOpenStreams() == 0) {
603 stream_factory_->OnIdleSession(this);
607 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
608 if (!callback_.is_null() &&
609 (!require_confirmation_ ||
610 event == HANDSHAKE_CONFIRMED || event == ENCRYPTION_REESTABLISHED)) {
611 // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
612 // could be called because there are no error events in CryptoHandshakeEvent
613 // enum. If error events are added to CryptoHandshakeEvent, then the
614 // following code needs to changed.
615 base::ResetAndReturn(&callback_).Run(OK);
617 if (event == HANDSHAKE_CONFIRMED) {
618 UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime",
619 base::TimeTicks::Now() - handshake_start_);
620 if (server_info_) {
621 // TODO(rtenneti): Should we delete this histogram?
622 // Track how long it has taken to finish handshake once we start waiting
623 // for reading of QUIC server information from disk cache. We could use
624 // this data to compare total time taken if we were to cancel the disk
625 // cache read vs waiting for the read to complete.
626 base::TimeTicks wait_for_data_start_time =
627 server_info_->wait_for_data_start_time();
628 if (!wait_for_data_start_time.is_null()) {
629 UMA_HISTOGRAM_TIMES(
630 "Net.QuicServerInfo.WaitForDataReady.HandshakeConfirmedTime",
631 base::TimeTicks::Now() - wait_for_data_start_time);
634 // Track how long it has taken to finish handshake after we have finished
635 // DNS host resolution.
636 if (!dns_resolution_end_time_.is_null()) {
637 UMA_HISTOGRAM_TIMES(
638 "Net.QuicSession.HostResolution.HandshakeConfirmedTime",
639 base::TimeTicks::Now() - dns_resolution_end_time_);
642 ObserverSet::iterator it = observers_.begin();
643 while (it != observers_.end()) {
644 Observer* observer = *it;
645 ++it;
646 observer->OnCryptoHandshakeConfirmed();
648 if (server_info_)
649 server_info_->OnExternalCacheHit();
651 QuicSession::OnCryptoHandshakeEvent(event);
654 void QuicClientSession::OnCryptoHandshakeMessageSent(
655 const CryptoHandshakeMessage& message) {
656 logger_->OnCryptoHandshakeMessageSent(message);
659 void QuicClientSession::OnCryptoHandshakeMessageReceived(
660 const CryptoHandshakeMessage& message) {
661 logger_->OnCryptoHandshakeMessageReceived(message);
664 void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
665 bool from_peer) {
666 DCHECK(!connection()->connected());
667 logger_->OnConnectionClosed(error, from_peer);
668 if (from_peer) {
669 UMA_HISTOGRAM_SPARSE_SLOWLY(
670 "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
671 } else {
672 UMA_HISTOGRAM_SPARSE_SLOWLY(
673 "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
676 if (error == QUIC_CONNECTION_TIMED_OUT) {
677 UMA_HISTOGRAM_COUNTS(
678 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
679 GetNumOpenStreams());
680 if (IsCryptoHandshakeConfirmed()) {
681 if (GetNumOpenStreams() > 0) {
682 UMA_HISTOGRAM_BOOLEAN(
683 "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
684 connection()->sent_packet_manager().HasUnackedPackets());
685 UMA_HISTOGRAM_COUNTS(
686 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
687 connection()->sent_packet_manager().consecutive_rto_count());
688 UMA_HISTOGRAM_COUNTS(
689 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
690 connection()->sent_packet_manager().consecutive_tlp_count());
692 if (connection()->sent_packet_manager().HasUnackedPackets()) {
693 UMA_HISTOGRAM_TIMES(
694 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
695 "TimeSinceLastReceived.UnackedPackets",
696 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
697 } else {
698 UMA_HISTOGRAM_TIMES(
699 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
700 "TimeSinceLastReceived.NoUnackedPackets",
701 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
704 } else {
705 UMA_HISTOGRAM_COUNTS(
706 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
707 GetNumOpenStreams());
708 UMA_HISTOGRAM_COUNTS(
709 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
710 num_total_streams_);
714 if (!IsCryptoHandshakeConfirmed()) {
715 if (error == QUIC_PUBLIC_RESET) {
716 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
717 } else if (connection()->GetStats().packets_received == 0) {
718 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
719 UMA_HISTOGRAM_SPARSE_SLOWLY(
720 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
721 error);
722 } else {
723 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
724 UMA_HISTOGRAM_SPARSE_SLOWLY(
725 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
726 error);
730 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
731 connection()->version());
732 NotifyFactoryOfSessionGoingAway();
733 if (!callback_.is_null()) {
734 base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
736 socket_->Close();
737 QuicSession::OnConnectionClosed(error, from_peer);
738 DCHECK(streams()->empty());
739 CloseAllStreams(ERR_UNEXPECTED);
740 CloseAllObservers(ERR_UNEXPECTED);
741 NotifyFactoryOfSessionClosedLater();
744 void QuicClientSession::OnSuccessfulVersionNegotiation(
745 const QuicVersion& version) {
746 logger_->OnSuccessfulVersionNegotiation(version);
747 QuicSession::OnSuccessfulVersionNegotiation(version);
750 void QuicClientSession::OnProofValid(
751 const QuicCryptoClientConfig::CachedState& cached) {
752 DCHECK(cached.proof_valid());
754 if (!server_info_) {
755 return;
758 QuicServerInfo::State* state = server_info_->mutable_state();
760 state->server_config = cached.server_config();
761 state->source_address_token = cached.source_address_token();
762 state->server_config_sig = cached.signature();
763 state->certs = cached.certs();
765 server_info_->Persist();
768 void QuicClientSession::OnProofVerifyDetailsAvailable(
769 const ProofVerifyDetails& verify_details) {
770 const ProofVerifyDetailsChromium* verify_details_chromium =
771 reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
772 CertVerifyResult* result_copy = new CertVerifyResult;
773 result_copy->CopyFrom(verify_details_chromium->cert_verify_result);
774 cert_verify_result_.reset(result_copy);
775 pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
776 logger_->OnCertificateVerified(*cert_verify_result_);
779 void QuicClientSession::StartReading() {
780 if (read_pending_) {
781 return;
783 read_pending_ = true;
784 int rv = socket_->Read(read_buffer_.get(),
785 read_buffer_->size(),
786 base::Bind(&QuicClientSession::OnReadComplete,
787 weak_factory_.GetWeakPtr()));
788 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING);
789 if (rv == ERR_IO_PENDING) {
790 num_packets_read_ = 0;
791 return;
794 if (++num_packets_read_ > 32) {
795 num_packets_read_ = 0;
796 // Data was read, process it.
797 // Schedule the work through the message loop to 1) prevent infinite
798 // recursion and 2) avoid blocking the thread for too long.
799 base::MessageLoop::current()->PostTask(
800 FROM_HERE,
801 base::Bind(&QuicClientSession::OnReadComplete,
802 weak_factory_.GetWeakPtr(), rv));
803 } else {
804 OnReadComplete(rv);
808 void QuicClientSession::CloseSessionOnError(int error) {
809 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
810 CloseSessionOnErrorInner(error, QUIC_INTERNAL_ERROR);
811 NotifyFactoryOfSessionClosed();
814 void QuicClientSession::CloseSessionOnErrorInner(int net_error,
815 QuicErrorCode quic_error) {
816 if (!callback_.is_null()) {
817 base::ResetAndReturn(&callback_).Run(net_error);
819 CloseAllStreams(net_error);
820 CloseAllObservers(net_error);
821 net_log_.AddEvent(
822 NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
823 NetLog::IntegerCallback("net_error", net_error));
825 if (connection()->connected())
826 connection()->CloseConnection(quic_error, false);
827 DCHECK(!connection()->connected());
830 void QuicClientSession::CloseAllStreams(int net_error) {
831 while (!streams()->empty()) {
832 ReliableQuicStream* stream = streams()->begin()->second;
833 QuicStreamId id = stream->id();
834 static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
835 CloseStream(id);
839 void QuicClientSession::CloseAllObservers(int net_error) {
840 while (!observers_.empty()) {
841 Observer* observer = *observers_.begin();
842 observers_.erase(observer);
843 observer->OnSessionClosed(net_error);
847 base::Value* QuicClientSession::GetInfoAsValue(
848 const std::set<HostPortPair>& aliases) {
849 base::DictionaryValue* dict = new base::DictionaryValue();
850 dict->SetString("version", QuicVersionToString(connection()->version()));
851 dict->SetInteger("open_streams", GetNumOpenStreams());
852 base::ListValue* stream_list = new base::ListValue();
853 for (base::hash_map<QuicStreamId, QuicDataStream*>::const_iterator it
854 = streams()->begin();
855 it != streams()->end();
856 ++it) {
857 stream_list->Append(new base::StringValue(
858 base::Uint64ToString(it->second->id())));
860 dict->Set("active_streams", stream_list);
862 dict->SetInteger("total_streams", num_total_streams_);
863 dict->SetString("peer_address", peer_address().ToString());
864 dict->SetString("connection_id", base::Uint64ToString(connection_id()));
865 dict->SetBoolean("connected", connection()->connected());
866 const QuicConnectionStats& stats = connection()->GetStats();
867 dict->SetInteger("packets_sent", stats.packets_sent);
868 dict->SetInteger("packets_received", stats.packets_received);
869 dict->SetInteger("packets_lost", stats.packets_lost);
870 SSLInfo ssl_info;
871 dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
873 base::ListValue* alias_list = new base::ListValue();
874 for (std::set<HostPortPair>::const_iterator it = aliases.begin();
875 it != aliases.end(); it++) {
876 alias_list->Append(new base::StringValue(it->ToString()));
878 dict->Set("aliases", alias_list);
880 return dict;
883 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
884 return weak_factory_.GetWeakPtr();
887 void QuicClientSession::OnReadComplete(int result) {
888 read_pending_ = false;
889 if (result == 0)
890 result = ERR_CONNECTION_CLOSED;
892 if (result < 0) {
893 DVLOG(1) << "Closing session on read error: " << result;
894 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
895 NotifyFactoryOfSessionGoingAway();
896 CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
897 NotifyFactoryOfSessionClosedLater();
898 return;
901 QuicEncryptedPacket packet(read_buffer_->data(), result);
902 IPEndPoint local_address;
903 IPEndPoint peer_address;
904 socket_->GetLocalAddress(&local_address);
905 socket_->GetPeerAddress(&peer_address);
906 // ProcessUdpPacket might result in |this| being deleted, so we
907 // use a weak pointer to be safe.
908 connection()->ProcessUdpPacket(local_address, peer_address, packet);
909 if (!connection()->connected()) {
910 NotifyFactoryOfSessionClosedLater();
911 return;
913 StartReading();
916 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
917 going_away_ = true;
918 if (stream_factory_)
919 stream_factory_->OnSessionGoingAway(this);
922 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
923 if (!streams()->empty())
924 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
926 if (!going_away_)
927 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
929 going_away_ = true;
930 DCHECK_EQ(0u, GetNumOpenStreams());
931 DCHECK(!connection()->connected());
932 base::MessageLoop::current()->PostTask(
933 FROM_HERE,
934 base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
935 weak_factory_.GetWeakPtr()));
938 void QuicClientSession::NotifyFactoryOfSessionClosed() {
939 if (!streams()->empty())
940 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
942 if (!going_away_)
943 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
945 going_away_ = true;
946 DCHECK_EQ(0u, GetNumOpenStreams());
947 // Will delete |this|.
948 if (stream_factory_)
949 stream_factory_->OnSessionClosed(this);
952 void QuicClientSession::OnConnectTimeout() {
953 DCHECK(callback_.is_null());
954 DCHECK(IsEncryptionEstablished());
956 if (IsCryptoHandshakeConfirmed())
957 return;
959 // TODO(rch): re-enable this code once beta is cut.
960 // if (stream_factory_)
961 // stream_factory_->OnSessionConnectTimeout(this);
962 // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
963 // DCHECK_EQ(0u, GetNumOpenStreams());
966 } // namespace net