Snap pinch zoom gestures near the screen edge.
[chromium-blink-merge.git] / net / quic / quic_client_session.cc
blob57a5393d734e359f50ef96f0b2fe6ccf6965f1f1
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/location.h"
9 #include "base/metrics/histogram_macros.h"
10 #include "base/metrics/sparse_histogram.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/values.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/network_activity_monitor.h"
19 #include "net/http/transport_security_state.h"
20 #include "net/quic/crypto/proof_verifier_chromium.h"
21 #include "net/quic/crypto/quic_server_info.h"
22 #include "net/quic/quic_connection_helper.h"
23 #include "net/quic/quic_crypto_client_stream_factory.h"
24 #include "net/quic/quic_server_id.h"
25 #include "net/quic/quic_stream_factory.h"
26 #include "net/spdy/spdy_session.h"
27 #include "net/ssl/channel_id_service.h"
28 #include "net/ssl/ssl_connection_status_flags.h"
29 #include "net/ssl/ssl_info.h"
30 #include "net/udp/datagram_client_socket.h"
32 namespace net {
34 namespace {
36 // The length of time to wait for a 0-RTT handshake to complete
37 // before allowing the requests to possibly proceed over TCP.
38 const int k0RttHandshakeTimeoutMs = 300;
40 // IPv6 packets have an additional 20 bytes of overhead than IPv4 packets.
41 const size_t kAdditionalOverheadForIPv6 = 20;
43 // Histograms for tracking down the crashes from http://crbug.com/354669
44 // Note: these values must be kept in sync with the corresponding values in:
45 // tools/metrics/histograms/histograms.xml
46 enum Location {
47 DESTRUCTOR = 0,
48 ADD_OBSERVER = 1,
49 TRY_CREATE_STREAM = 2,
50 CREATE_OUTGOING_RELIABLE_STREAM = 3,
51 NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER = 4,
52 NOTIFY_FACTORY_OF_SESSION_CLOSED = 5,
53 NUM_LOCATIONS = 6,
56 void RecordUnexpectedOpenStreams(Location location) {
57 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
58 NUM_LOCATIONS);
61 void RecordUnexpectedObservers(Location location) {
62 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
63 NUM_LOCATIONS);
66 void RecordUnexpectedNotGoingAway(Location location) {
67 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
68 NUM_LOCATIONS);
71 // Histogram for recording the different reasons that a QUIC session is unable
72 // to complete the handshake.
73 enum HandshakeFailureReason {
74 HANDSHAKE_FAILURE_UNKNOWN = 0,
75 HANDSHAKE_FAILURE_BLACK_HOLE = 1,
76 HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
77 NUM_HANDSHAKE_FAILURE_REASONS = 3,
80 void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
81 UMA_HISTOGRAM_ENUMERATION(
82 "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason",
83 reason, NUM_HANDSHAKE_FAILURE_REASONS);
86 // Note: these values must be kept in sync with the corresponding values in:
87 // tools/metrics/histograms/histograms.xml
88 enum HandshakeState {
89 STATE_STARTED = 0,
90 STATE_ENCRYPTION_ESTABLISHED = 1,
91 STATE_HANDSHAKE_CONFIRMED = 2,
92 STATE_FAILED = 3,
93 NUM_HANDSHAKE_STATES = 4
96 void RecordHandshakeState(HandshakeState state) {
97 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
98 NUM_HANDSHAKE_STATES);
101 scoped_ptr<base::Value> NetLogQuicClientSessionCallback(
102 const QuicServerId* server_id,
103 int cert_verify_flags,
104 bool require_confirmation,
105 NetLogCaptureMode /* capture_mode */) {
106 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
107 dict->SetString("host", server_id->host());
108 dict->SetInteger("port", server_id->port());
109 dict->SetBoolean("is_https", server_id->is_https());
110 dict->SetBoolean("privacy_mode",
111 server_id->privacy_mode() == PRIVACY_MODE_ENABLED);
112 dict->SetBoolean("require_confirmation", require_confirmation);
113 dict->SetInteger("cert_verify_flags", cert_verify_flags);
114 return dict.Pass();
117 } // namespace
119 QuicClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
121 QuicClientSession::StreamRequest::~StreamRequest() {
122 CancelRequest();
125 int QuicClientSession::StreamRequest::StartRequest(
126 const base::WeakPtr<QuicClientSession>& session,
127 QuicReliableClientStream** stream,
128 const CompletionCallback& callback) {
129 session_ = session;
130 stream_ = stream;
131 int rv = session_->TryCreateStream(this, stream_);
132 if (rv == ERR_IO_PENDING) {
133 callback_ = callback;
136 return rv;
139 void QuicClientSession::StreamRequest::CancelRequest() {
140 if (session_)
141 session_->CancelRequest(this);
142 session_.reset();
143 callback_.Reset();
146 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
147 QuicReliableClientStream* stream) {
148 session_.reset();
149 *stream_ = stream;
150 ResetAndReturn(&callback_).Run(OK);
153 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
154 session_.reset();
155 ResetAndReturn(&callback_).Run(rv);
158 QuicClientSession::QuicClientSession(
159 QuicConnection* connection,
160 scoped_ptr<DatagramClientSocket> socket,
161 QuicStreamFactory* stream_factory,
162 QuicCryptoClientStreamFactory* crypto_client_stream_factory,
163 TransportSecurityState* transport_security_state,
164 scoped_ptr<QuicServerInfo> server_info,
165 const QuicServerId& server_id,
166 int cert_verify_flags,
167 const QuicConfig& config,
168 QuicCryptoClientConfig* crypto_config,
169 const char* const connection_description,
170 base::TimeTicks dns_resolution_end_time,
171 base::TaskRunner* task_runner,
172 NetLog* net_log)
173 : QuicClientSessionBase(connection, config),
174 server_id_(server_id),
175 require_confirmation_(false),
176 stream_factory_(stream_factory),
177 socket_(socket.Pass()),
178 transport_security_state_(transport_security_state),
179 server_info_(server_info.Pass()),
180 num_total_streams_(0),
181 task_runner_(task_runner),
182 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
183 packet_reader_(socket_.get(), this, net_log_),
184 dns_resolution_end_time_(dns_resolution_end_time),
185 logger_(new QuicConnectionLogger(this, connection_description, net_log_)),
186 going_away_(false),
187 weak_factory_(this) {
188 crypto_stream_.reset(
189 crypto_client_stream_factory
190 ? crypto_client_stream_factory->CreateQuicCryptoClientStream(
191 server_id, this, crypto_config)
192 : new QuicCryptoClientStream(
193 server_id, this,
194 new ProofVerifyContextChromium(cert_verify_flags, net_log_),
195 crypto_config));
196 connection->set_debug_visitor(logger_.get());
197 net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION,
198 base::Bind(NetLogQuicClientSessionCallback, &server_id,
199 cert_verify_flags, require_confirmation_));
200 IPEndPoint address;
201 if (socket && socket->GetLocalAddress(&address) == OK &&
202 address.GetFamily() == ADDRESS_FAMILY_IPV6) {
203 connection->set_max_packet_length(connection->max_packet_length() -
204 kAdditionalOverheadForIPv6);
208 QuicClientSession::~QuicClientSession() {
209 if (!dynamic_streams().empty())
210 RecordUnexpectedOpenStreams(DESTRUCTOR);
211 if (!observers_.empty())
212 RecordUnexpectedObservers(DESTRUCTOR);
213 if (!going_away_)
214 RecordUnexpectedNotGoingAway(DESTRUCTOR);
216 while (!dynamic_streams().empty() || !observers_.empty() ||
217 !stream_requests_.empty()) {
218 // The session must be closed before it is destroyed.
219 DCHECK(dynamic_streams().empty());
220 CloseAllStreams(ERR_UNEXPECTED);
221 DCHECK(observers_.empty());
222 CloseAllObservers(ERR_UNEXPECTED);
224 connection()->set_debug_visitor(nullptr);
225 net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
227 while (!stream_requests_.empty()) {
228 StreamRequest* request = stream_requests_.front();
229 stream_requests_.pop_front();
230 request->OnRequestCompleteFailure(ERR_ABORTED);
234 if (connection()->connected()) {
235 // Ensure that the connection is closed by the time the session is
236 // destroyed.
237 connection()->CloseConnection(QUIC_INTERNAL_ERROR, false);
240 if (IsEncryptionEstablished())
241 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
242 if (IsCryptoHandshakeConfirmed())
243 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
244 else
245 RecordHandshakeState(STATE_FAILED);
247 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
248 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
249 crypto_stream_->num_sent_client_hellos());
250 if (!IsCryptoHandshakeConfirmed())
251 return;
253 // Sending one client_hello means we had zero handshake-round-trips.
254 int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
256 // Don't bother with these histogram during tests, which mock out
257 // num_sent_client_hellos().
258 if (round_trip_handshakes < 0 || !stream_factory_)
259 return;
261 bool port_selected = stream_factory_->enable_port_selection();
262 SSLInfo ssl_info;
263 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
264 if (port_selected) {
265 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
266 round_trip_handshakes, 0, 3, 4);
267 } else {
268 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
269 round_trip_handshakes, 0, 3, 4);
270 if (require_confirmation_) {
271 UMA_HISTOGRAM_CUSTOM_COUNTS(
272 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
273 round_trip_handshakes, 0, 3, 4);
276 } else {
277 if (port_selected) {
278 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
279 round_trip_handshakes, 0, 3, 4);
280 } else {
281 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
282 round_trip_handshakes, 0, 3, 4);
283 if (require_confirmation_) {
284 UMA_HISTOGRAM_CUSTOM_COUNTS(
285 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
286 round_trip_handshakes, 0, 3, 4);
290 const QuicConnectionStats stats = connection()->GetStats();
291 if (server_info_ && stats.min_rtt_us > 0) {
292 base::TimeTicks wait_for_data_start_time =
293 server_info_->wait_for_data_start_time();
294 base::TimeTicks wait_for_data_end_time =
295 server_info_->wait_for_data_end_time();
296 if (!wait_for_data_start_time.is_null() &&
297 !wait_for_data_end_time.is_null()) {
298 base::TimeDelta wait_time =
299 wait_for_data_end_time - wait_for_data_start_time;
300 const base::HistogramBase::Sample kMaxWaitToRtt = 1000;
301 base::HistogramBase::Sample wait_to_rtt =
302 static_cast<base::HistogramBase::Sample>(
303 100 * wait_time.InMicroseconds() / stats.min_rtt_us);
304 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicServerInfo.WaitForDataReadyToRtt",
305 wait_to_rtt, 0, kMaxWaitToRtt, 50);
309 if (stats.max_sequence_reordering == 0)
310 return;
311 const base::HistogramBase::Sample kMaxReordering = 100;
312 base::HistogramBase::Sample reordering = kMaxReordering;
313 if (stats.min_rtt_us > 0) {
314 reordering = static_cast<base::HistogramBase::Sample>(
315 100 * stats.max_time_reordering_us / stats.min_rtt_us);
317 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime",
318 reordering, 0, kMaxReordering, 50);
319 if (stats.min_rtt_us > 100 * 1000) {
320 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
321 reordering, 0, kMaxReordering, 50);
323 UMA_HISTOGRAM_COUNTS(
324 "Net.QuicSession.MaxReordering",
325 static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
328 void QuicClientSession::OnStreamFrames(
329 const std::vector<QuicStreamFrame>& frames) {
330 // Record total number of stream frames.
331 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames.size());
333 // Record number of frames per stream in packet.
334 typedef std::map<QuicStreamId, size_t> FrameCounter;
335 FrameCounter frames_per_stream;
336 for (size_t i = 0; i < frames.size(); ++i) {
337 frames_per_stream[frames[i].stream_id]++;
339 for (FrameCounter::const_iterator it = frames_per_stream.begin();
340 it != frames_per_stream.end(); ++it) {
341 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
342 it->second);
345 return QuicSpdySession::OnStreamFrames(frames);
348 void QuicClientSession::AddObserver(Observer* observer) {
349 if (going_away_) {
350 RecordUnexpectedObservers(ADD_OBSERVER);
351 observer->OnSessionClosed(ERR_UNEXPECTED);
352 return;
355 DCHECK(!ContainsKey(observers_, observer));
356 observers_.insert(observer);
359 void QuicClientSession::RemoveObserver(Observer* observer) {
360 DCHECK(ContainsKey(observers_, observer));
361 observers_.erase(observer);
364 int QuicClientSession::TryCreateStream(StreamRequest* request,
365 QuicReliableClientStream** stream) {
366 if (!crypto_stream_->encryption_established()) {
367 DLOG(DFATAL) << "Encryption not established.";
368 return ERR_CONNECTION_CLOSED;
371 if (goaway_received()) {
372 DVLOG(1) << "Going away.";
373 return ERR_CONNECTION_CLOSED;
376 if (!connection()->connected()) {
377 DVLOG(1) << "Already closed.";
378 return ERR_CONNECTION_CLOSED;
381 if (going_away_) {
382 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
383 return ERR_CONNECTION_CLOSED;
386 if (GetNumOpenStreams() < get_max_open_streams()) {
387 *stream = CreateOutgoingReliableStreamImpl();
388 return OK;
391 stream_requests_.push_back(request);
392 return ERR_IO_PENDING;
395 void QuicClientSession::CancelRequest(StreamRequest* request) {
396 // Remove |request| from the queue while preserving the order of the
397 // other elements.
398 StreamRequestQueue::iterator it =
399 std::find(stream_requests_.begin(), stream_requests_.end(), request);
400 if (it != stream_requests_.end()) {
401 it = stream_requests_.erase(it);
405 QuicReliableClientStream* QuicClientSession::CreateOutgoingDynamicStream() {
406 if (!crypto_stream_->encryption_established()) {
407 DVLOG(1) << "Encryption not active so no outgoing stream created.";
408 return nullptr;
410 if (GetNumOpenStreams() >= get_max_open_streams()) {
411 DVLOG(1) << "Failed to create a new outgoing stream. "
412 << "Already " << GetNumOpenStreams() << " open.";
413 return nullptr;
415 if (goaway_received()) {
416 DVLOG(1) << "Failed to create a new outgoing stream. "
417 << "Already received goaway.";
418 return nullptr;
420 if (going_away_) {
421 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
422 return nullptr;
424 return CreateOutgoingReliableStreamImpl();
427 QuicReliableClientStream*
428 QuicClientSession::CreateOutgoingReliableStreamImpl() {
429 DCHECK(connection()->connected());
430 QuicReliableClientStream* stream =
431 new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
432 ActivateStream(stream);
433 ++num_total_streams_;
434 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
435 // The previous histogram puts 100 in a bucket betweeen 86-113 which does
436 // not shed light on if chrome ever things it has more than 100 streams open.
437 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.TooManyOpenStreams",
438 GetNumOpenStreams() > 100);
439 return stream;
442 QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
443 return crypto_stream_.get();
446 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
447 // we learn about SSL info (sync vs async vs cached).
448 bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
449 ssl_info->Reset();
450 if (!cert_verify_result_) {
451 return false;
454 ssl_info->cert_status = cert_verify_result_->cert_status;
455 ssl_info->cert = cert_verify_result_->verified_cert;
457 // TODO(wtc): Define QUIC "cipher suites".
458 // Report the TLS cipher suite that most closely resembles the crypto
459 // parameters of the QUIC connection.
460 QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
461 uint16 cipher_suite;
462 int security_bits;
463 switch (aead) {
464 case kAESG:
465 cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
466 security_bits = 128;
467 break;
468 case kCC12:
469 cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
470 security_bits = 256;
471 break;
472 default:
473 NOTREACHED();
474 return false;
476 int ssl_connection_status = 0;
477 ssl_connection_status |= cipher_suite;
478 ssl_connection_status |=
479 (SSL_CONNECTION_VERSION_QUIC & SSL_CONNECTION_VERSION_MASK) <<
480 SSL_CONNECTION_VERSION_SHIFT;
482 ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
483 ssl_info->is_issued_by_known_root =
484 cert_verify_result_->is_issued_by_known_root;
486 ssl_info->connection_status = ssl_connection_status;
487 ssl_info->client_cert_sent = false;
488 ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent();
489 ssl_info->security_bits = security_bits;
490 ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
491 ssl_info->pinning_failure_log = pinning_failure_log_;
492 return true;
495 int QuicClientSession::CryptoConnect(bool require_confirmation,
496 const CompletionCallback& callback) {
497 require_confirmation_ = require_confirmation;
498 handshake_start_ = base::TimeTicks::Now();
499 RecordHandshakeState(STATE_STARTED);
500 DCHECK(flow_controller());
501 crypto_stream_->CryptoConnect();
503 if (IsCryptoHandshakeConfirmed())
504 return OK;
506 // Unless we require handshake confirmation, activate the session if
507 // we have established initial encryption.
508 if (!require_confirmation_ && IsEncryptionEstablished()) {
509 // To mitigate the effects of hanging 0-RTT connections, set up a timer to
510 // cancel any requests, if the handshake takes too long.
511 task_runner_->PostDelayedTask(
512 FROM_HERE,
513 base::Bind(&QuicClientSession::OnConnectTimeout,
514 weak_factory_.GetWeakPtr()),
515 base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs));
516 return OK;
520 callback_ = callback;
521 return ERR_IO_PENDING;
524 int QuicClientSession::ResumeCryptoConnect(const CompletionCallback& callback) {
526 if (IsCryptoHandshakeConfirmed())
527 return OK;
529 if (!connection()->connected())
530 return ERR_QUIC_HANDSHAKE_FAILED;
532 callback_ = callback;
533 return ERR_IO_PENDING;
536 int QuicClientSession::GetNumSentClientHellos() const {
537 return crypto_stream_->num_sent_client_hellos();
540 bool QuicClientSession::CanPool(const std::string& hostname,
541 PrivacyMode privacy_mode) const {
542 DCHECK(connection()->connected());
543 if (privacy_mode != server_id_.privacy_mode()) {
544 // Privacy mode must always match.
545 return false;
547 SSLInfo ssl_info;
548 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
549 // We can always pool with insecure QUIC sessions.
550 return true;
553 return SpdySession::CanPool(transport_security_state_, ssl_info,
554 server_id_.host(), hostname);
557 QuicDataStream* QuicClientSession::CreateIncomingDynamicStream(
558 QuicStreamId id) {
559 DLOG(ERROR) << "Server push not supported";
560 return nullptr;
563 void QuicClientSession::CloseStream(QuicStreamId stream_id) {
564 ReliableQuicStream* stream = GetStream(stream_id);
565 if (stream) {
566 logger_->UpdateReceivedFrameCounts(
567 stream_id, stream->num_frames_received(),
568 stream->num_duplicate_frames_received());
570 QuicSpdySession::CloseStream(stream_id);
571 OnClosedStream();
574 void QuicClientSession::SendRstStream(QuicStreamId id,
575 QuicRstStreamErrorCode error,
576 QuicStreamOffset bytes_written) {
577 QuicSpdySession::SendRstStream(id, error, bytes_written);
578 OnClosedStream();
581 void QuicClientSession::OnClosedStream() {
582 if (GetNumOpenStreams() < get_max_open_streams() &&
583 !stream_requests_.empty() &&
584 crypto_stream_->encryption_established() &&
585 !goaway_received() &&
586 !going_away_ &&
587 connection()->connected()) {
588 StreamRequest* request = stream_requests_.front();
589 stream_requests_.pop_front();
590 request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
593 if (GetNumOpenStreams() == 0) {
594 stream_factory_->OnIdleSession(this);
598 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
599 if (stream_factory_ && event == HANDSHAKE_CONFIRMED &&
600 (stream_factory_->OnHandshakeConfirmed(
601 this, logger_->ReceivedPacketLossRate()))) {
602 return;
605 if (!callback_.is_null() &&
606 (!require_confirmation_ ||
607 event == HANDSHAKE_CONFIRMED || event == ENCRYPTION_REESTABLISHED)) {
608 // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
609 // could be called because there are no error events in CryptoHandshakeEvent
610 // enum. If error events are added to CryptoHandshakeEvent, then the
611 // following code needs to changed.
612 base::ResetAndReturn(&callback_).Run(OK);
614 if (event == HANDSHAKE_CONFIRMED) {
615 UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime",
616 base::TimeTicks::Now() - handshake_start_);
617 if (server_info_) {
618 // TODO(rtenneti): Should we delete this histogram?
619 // Track how long it has taken to finish handshake once we start waiting
620 // for reading of QUIC server information from disk cache. We could use
621 // this data to compare total time taken if we were to cancel the disk
622 // cache read vs waiting for the read to complete.
623 base::TimeTicks wait_for_data_start_time =
624 server_info_->wait_for_data_start_time();
625 if (!wait_for_data_start_time.is_null()) {
626 UMA_HISTOGRAM_TIMES(
627 "Net.QuicServerInfo.WaitForDataReady.HandshakeConfirmedTime",
628 base::TimeTicks::Now() - wait_for_data_start_time);
631 // Track how long it has taken to finish handshake after we have finished
632 // DNS host resolution.
633 if (!dns_resolution_end_time_.is_null()) {
634 UMA_HISTOGRAM_TIMES(
635 "Net.QuicSession.HostResolution.HandshakeConfirmedTime",
636 base::TimeTicks::Now() - dns_resolution_end_time_);
639 ObserverSet::iterator it = observers_.begin();
640 while (it != observers_.end()) {
641 Observer* observer = *it;
642 ++it;
643 observer->OnCryptoHandshakeConfirmed();
645 if (server_info_)
646 server_info_->OnExternalCacheHit();
648 QuicSpdySession::OnCryptoHandshakeEvent(event);
651 void QuicClientSession::OnCryptoHandshakeMessageSent(
652 const CryptoHandshakeMessage& message) {
653 logger_->OnCryptoHandshakeMessageSent(message);
656 void QuicClientSession::OnCryptoHandshakeMessageReceived(
657 const CryptoHandshakeMessage& message) {
658 logger_->OnCryptoHandshakeMessageReceived(message);
661 void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
662 bool from_peer) {
663 DCHECK(!connection()->connected());
664 logger_->OnConnectionClosed(error, from_peer);
665 if (from_peer) {
666 UMA_HISTOGRAM_SPARSE_SLOWLY(
667 "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
668 } else {
669 UMA_HISTOGRAM_SPARSE_SLOWLY(
670 "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
673 if (error == QUIC_CONNECTION_TIMED_OUT) {
674 UMA_HISTOGRAM_COUNTS(
675 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
676 GetNumOpenStreams());
677 if (IsCryptoHandshakeConfirmed()) {
678 if (GetNumOpenStreams() > 0) {
679 UMA_HISTOGRAM_BOOLEAN(
680 "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
681 connection()->sent_packet_manager().HasUnackedPackets());
682 UMA_HISTOGRAM_COUNTS(
683 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
684 connection()->sent_packet_manager().consecutive_rto_count());
685 UMA_HISTOGRAM_COUNTS(
686 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
687 connection()->sent_packet_manager().consecutive_tlp_count());
689 if (connection()->sent_packet_manager().HasUnackedPackets()) {
690 UMA_HISTOGRAM_TIMES(
691 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
692 "TimeSinceLastReceived.UnackedPackets",
693 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
694 } else {
695 UMA_HISTOGRAM_TIMES(
696 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
697 "TimeSinceLastReceived.NoUnackedPackets",
698 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
701 } else {
702 UMA_HISTOGRAM_COUNTS(
703 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
704 GetNumOpenStreams());
705 UMA_HISTOGRAM_COUNTS(
706 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
707 num_total_streams_);
711 if (!IsCryptoHandshakeConfirmed()) {
712 if (error == QUIC_PUBLIC_RESET) {
713 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
714 } else if (connection()->GetStats().packets_received == 0) {
715 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
716 UMA_HISTOGRAM_SPARSE_SLOWLY(
717 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
718 error);
719 } else {
720 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
721 UMA_HISTOGRAM_SPARSE_SLOWLY(
722 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
723 error);
727 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
728 connection()->version());
729 NotifyFactoryOfSessionGoingAway();
730 if (!callback_.is_null()) {
731 base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
733 socket_->Close();
734 QuicSession::OnConnectionClosed(error, from_peer);
735 DCHECK(dynamic_streams().empty());
736 CloseAllStreams(ERR_UNEXPECTED);
737 CloseAllObservers(ERR_UNEXPECTED);
738 NotifyFactoryOfSessionClosedLater();
741 void QuicClientSession::OnSuccessfulVersionNegotiation(
742 const QuicVersion& version) {
743 logger_->OnSuccessfulVersionNegotiation(version);
744 QuicSpdySession::OnSuccessfulVersionNegotiation(version);
747 void QuicClientSession::OnProofValid(
748 const QuicCryptoClientConfig::CachedState& cached) {
749 DCHECK(cached.proof_valid());
751 if (!server_info_) {
752 return;
755 QuicServerInfo::State* state = server_info_->mutable_state();
757 state->server_config = cached.server_config();
758 state->source_address_token = cached.source_address_token();
759 state->server_config_sig = cached.signature();
760 state->certs = cached.certs();
762 server_info_->Persist();
765 void QuicClientSession::OnProofVerifyDetailsAvailable(
766 const ProofVerifyDetails& verify_details) {
767 const ProofVerifyDetailsChromium* verify_details_chromium =
768 reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
769 CertVerifyResult* result_copy = new CertVerifyResult;
770 result_copy->CopyFrom(verify_details_chromium->cert_verify_result);
771 cert_verify_result_.reset(result_copy);
772 pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
773 logger_->OnCertificateVerified(*cert_verify_result_);
776 void QuicClientSession::StartReading() {
777 packet_reader_.StartReading();
780 void QuicClientSession::CloseSessionOnError(int error,
781 QuicErrorCode quic_error) {
782 RecordAndCloseSessionOnError(error, quic_error);
783 NotifyFactoryOfSessionClosed();
786 void QuicClientSession::CloseSessionOnErrorAndNotifyFactoryLater(
787 int error,
788 QuicErrorCode quic_error) {
789 RecordAndCloseSessionOnError(error, quic_error);
790 NotifyFactoryOfSessionClosedLater();
793 void QuicClientSession::RecordAndCloseSessionOnError(int error,
794 QuicErrorCode quic_error) {
795 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
796 CloseSessionOnErrorInner(error, quic_error);
799 void QuicClientSession::CloseSessionOnErrorInner(int net_error,
800 QuicErrorCode quic_error) {
801 if (!callback_.is_null()) {
802 base::ResetAndReturn(&callback_).Run(net_error);
804 CloseAllStreams(net_error);
805 CloseAllObservers(net_error);
806 net_log_.AddEvent(
807 NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
808 NetLog::IntegerCallback("net_error", net_error));
810 if (connection()->connected())
811 connection()->CloseConnection(quic_error, false);
812 DCHECK(!connection()->connected());
815 void QuicClientSession::CloseAllStreams(int net_error) {
816 while (!dynamic_streams().empty()) {
817 ReliableQuicStream* stream = dynamic_streams().begin()->second;
818 QuicStreamId id = stream->id();
819 static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
820 CloseStream(id);
824 void QuicClientSession::CloseAllObservers(int net_error) {
825 while (!observers_.empty()) {
826 Observer* observer = *observers_.begin();
827 observers_.erase(observer);
828 observer->OnSessionClosed(net_error);
832 scoped_ptr<base::Value> QuicClientSession::GetInfoAsValue(
833 const std::set<HostPortPair>& aliases) {
834 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
835 dict->SetString("version", QuicVersionToString(connection()->version()));
836 dict->SetInteger("open_streams", GetNumOpenStreams());
837 scoped_ptr<base::ListValue> stream_list(new base::ListValue());
838 for (base::hash_map<QuicStreamId, ReliableQuicStream*>::const_iterator it =
839 dynamic_streams().begin();
840 it != dynamic_streams().end(); ++it) {
841 stream_list->Append(new base::StringValue(
842 base::Uint64ToString(it->second->id())));
844 dict->Set("active_streams", stream_list.Pass());
846 dict->SetInteger("total_streams", num_total_streams_);
847 dict->SetString("peer_address", peer_address().ToString());
848 dict->SetString("connection_id", base::Uint64ToString(connection_id()));
849 dict->SetBoolean("connected", connection()->connected());
850 const QuicConnectionStats& stats = connection()->GetStats();
851 dict->SetInteger("packets_sent", stats.packets_sent);
852 dict->SetInteger("packets_received", stats.packets_received);
853 dict->SetInteger("packets_lost", stats.packets_lost);
854 SSLInfo ssl_info;
855 dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
857 scoped_ptr<base::ListValue> alias_list(new base::ListValue());
858 for (std::set<HostPortPair>::const_iterator it = aliases.begin();
859 it != aliases.end(); it++) {
860 alias_list->Append(new base::StringValue(it->ToString()));
862 dict->Set("aliases", alias_list.Pass());
864 return dict.Pass();
867 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
868 return weak_factory_.GetWeakPtr();
871 void QuicClientSession::OnReadError(int result) {
872 DVLOG(1) << "Closing session on read error: " << result;
873 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
874 NotifyFactoryOfSessionGoingAway();
875 CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
876 NotifyFactoryOfSessionClosedLater();
879 bool QuicClientSession::OnPacket(const QuicEncryptedPacket& packet,
880 IPEndPoint local_address,
881 IPEndPoint peer_address) {
882 connection()->ProcessUdpPacket(local_address, peer_address, packet);
883 if (!connection()->connected()) {
884 NotifyFactoryOfSessionClosedLater();
885 return false;
887 return true;
890 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
891 going_away_ = true;
892 if (stream_factory_)
893 stream_factory_->OnSessionGoingAway(this);
896 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
897 if (!dynamic_streams().empty())
898 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
900 if (!going_away_)
901 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
903 going_away_ = true;
904 DCHECK_EQ(0u, GetNumOpenStreams());
905 DCHECK(!connection()->connected());
906 base::ThreadTaskRunnerHandle::Get()->PostTask(
907 FROM_HERE, base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
908 weak_factory_.GetWeakPtr()));
911 void QuicClientSession::NotifyFactoryOfSessionClosed() {
912 if (!dynamic_streams().empty())
913 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
915 if (!going_away_)
916 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
918 going_away_ = true;
919 DCHECK_EQ(0u, GetNumOpenStreams());
920 // Will delete |this|.
921 if (stream_factory_)
922 stream_factory_->OnSessionClosed(this);
925 void QuicClientSession::OnConnectTimeout() {
926 DCHECK(callback_.is_null());
927 DCHECK(IsEncryptionEstablished());
929 if (IsCryptoHandshakeConfirmed())
930 return;
932 // TODO(rch): re-enable this code once beta is cut.
933 // if (stream_factory_)
934 // stream_factory_->OnSessionConnectTimeout(this);
935 // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
936 // DCHECK_EQ(0u, GetNumOpenStreams());
939 } // namespace net