Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / net / quic / quic_client_session.cc
blob5f825db395a1ec27598379faa8926063bb91aaa7
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/stl_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/values.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
16 #include "net/base/network_activity_monitor.h"
17 #include "net/http/transport_security_state.h"
18 #include "net/quic/crypto/proof_verifier_chromium.h"
19 #include "net/quic/crypto/quic_server_info.h"
20 #include "net/quic/quic_connection_helper.h"
21 #include "net/quic/quic_crypto_client_stream_factory.h"
22 #include "net/quic/quic_server_id.h"
23 #include "net/quic/quic_stream_factory.h"
24 #include "net/spdy/spdy_session.h"
25 #include "net/ssl/channel_id_service.h"
26 #include "net/ssl/ssl_connection_status_flags.h"
27 #include "net/ssl/ssl_info.h"
28 #include "net/udp/datagram_client_socket.h"
30 namespace net {
32 namespace {
34 // The length of time to wait for a 0-RTT handshake to complete
35 // before allowing the requests to possibly proceed over TCP.
36 const int k0RttHandshakeTimeoutMs = 300;
38 // IPv6 packets have an additional 20 bytes of overhead than IPv4 packets.
39 const size_t kAdditionalOverheadForIPv6 = 20;
41 // Histograms for tracking down the crashes from http://crbug.com/354669
42 // Note: these values must be kept in sync with the corresponding values in:
43 // tools/metrics/histograms/histograms.xml
44 enum Location {
45 DESTRUCTOR = 0,
46 ADD_OBSERVER = 1,
47 TRY_CREATE_STREAM = 2,
48 CREATE_OUTGOING_RELIABLE_STREAM = 3,
49 NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER = 4,
50 NOTIFY_FACTORY_OF_SESSION_CLOSED = 5,
51 NUM_LOCATIONS = 6,
54 void RecordUnexpectedOpenStreams(Location location) {
55 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
56 NUM_LOCATIONS);
59 void RecordUnexpectedObservers(Location location) {
60 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
61 NUM_LOCATIONS);
64 void RecordUnexpectedNotGoingAway(Location location) {
65 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
66 NUM_LOCATIONS);
69 // Histogram for recording the different reasons that a QUIC session is unable
70 // to complete the handshake.
71 enum HandshakeFailureReason {
72 HANDSHAKE_FAILURE_UNKNOWN = 0,
73 HANDSHAKE_FAILURE_BLACK_HOLE = 1,
74 HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
75 NUM_HANDSHAKE_FAILURE_REASONS = 3,
78 void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
79 UMA_HISTOGRAM_ENUMERATION(
80 "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason",
81 reason, NUM_HANDSHAKE_FAILURE_REASONS);
84 // Note: these values must be kept in sync with the corresponding values in:
85 // tools/metrics/histograms/histograms.xml
86 enum HandshakeState {
87 STATE_STARTED = 0,
88 STATE_ENCRYPTION_ESTABLISHED = 1,
89 STATE_HANDSHAKE_CONFIRMED = 2,
90 STATE_FAILED = 3,
91 NUM_HANDSHAKE_STATES = 4
94 void RecordHandshakeState(HandshakeState state) {
95 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
96 NUM_HANDSHAKE_STATES);
99 scoped_ptr<base::Value> NetLogQuicClientSessionCallback(
100 const QuicServerId* server_id,
101 bool require_confirmation,
102 NetLogCaptureMode /* capture_mode */) {
103 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
104 dict->SetString("host", server_id->host());
105 dict->SetInteger("port", server_id->port());
106 dict->SetBoolean("is_https", server_id->is_https());
107 dict->SetBoolean("privacy_mode",
108 server_id->privacy_mode() == PRIVACY_MODE_ENABLED);
109 dict->SetBoolean("require_confirmation", require_confirmation);
110 return dict.Pass();
113 } // namespace
115 QuicClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
117 QuicClientSession::StreamRequest::~StreamRequest() {
118 CancelRequest();
121 int QuicClientSession::StreamRequest::StartRequest(
122 const base::WeakPtr<QuicClientSession>& session,
123 QuicReliableClientStream** stream,
124 const CompletionCallback& callback) {
125 session_ = session;
126 stream_ = stream;
127 int rv = session_->TryCreateStream(this, stream_);
128 if (rv == ERR_IO_PENDING) {
129 callback_ = callback;
132 return rv;
135 void QuicClientSession::StreamRequest::CancelRequest() {
136 if (session_)
137 session_->CancelRequest(this);
138 session_.reset();
139 callback_.Reset();
142 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
143 QuicReliableClientStream* stream) {
144 session_.reset();
145 *stream_ = stream;
146 ResetAndReturn(&callback_).Run(OK);
149 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
150 session_.reset();
151 ResetAndReturn(&callback_).Run(rv);
154 QuicClientSession::QuicClientSession(
155 QuicConnection* connection,
156 scoped_ptr<DatagramClientSocket> socket,
157 QuicStreamFactory* stream_factory,
158 TransportSecurityState* transport_security_state,
159 scoped_ptr<QuicServerInfo> server_info,
160 const QuicConfig& config,
161 const char* const connection_description,
162 base::TimeTicks dns_resolution_end_time,
163 base::TaskRunner* task_runner,
164 NetLog* net_log)
165 : QuicClientSessionBase(connection, config),
166 require_confirmation_(false),
167 stream_factory_(stream_factory),
168 socket_(socket.Pass()),
169 transport_security_state_(transport_security_state),
170 server_info_(server_info.Pass()),
171 num_total_streams_(0),
172 task_runner_(task_runner),
173 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
174 packet_reader_(socket_.get(), this, net_log_),
175 dns_resolution_end_time_(dns_resolution_end_time),
176 logger_(new QuicConnectionLogger(this, connection_description, net_log_)),
177 going_away_(false),
178 weak_factory_(this) {
179 connection->set_debug_visitor(logger_.get());
180 IPEndPoint address;
181 if (socket && socket->GetLocalAddress(&address) == OK &&
182 address.GetFamily() == ADDRESS_FAMILY_IPV6) {
183 connection->set_max_packet_length(
184 connection->max_packet_length() - kAdditionalOverheadForIPv6);
188 void QuicClientSession::InitializeSession(
189 const QuicServerId& server_id,
190 QuicCryptoClientConfig* crypto_config,
191 QuicCryptoClientStreamFactory* crypto_client_stream_factory) {
192 server_id_ = server_id;
193 crypto_stream_.reset(
194 crypto_client_stream_factory ?
195 crypto_client_stream_factory->CreateQuicCryptoClientStream(
196 server_id, this, crypto_config) :
197 new QuicCryptoClientStream(server_id, this,
198 new ProofVerifyContextChromium(net_log_),
199 crypto_config));
200 QuicClientSessionBase::InitializeSession();
201 // TODO(rch): pass in full host port proxy pair
202 net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION,
203 base::Bind(NetLogQuicClientSessionCallback,
204 &server_id,
205 require_confirmation_));
208 QuicClientSession::~QuicClientSession() {
209 if (!streams()->empty())
210 RecordUnexpectedOpenStreams(DESTRUCTOR);
211 if (!observers_.empty())
212 RecordUnexpectedObservers(DESTRUCTOR);
213 if (!going_away_)
214 RecordUnexpectedNotGoingAway(DESTRUCTOR);
216 while (!streams()->empty() ||
217 !observers_.empty() ||
218 !stream_requests_.empty()) {
219 // The session must be closed before it is destroyed.
220 DCHECK(streams()->empty());
221 CloseAllStreams(ERR_UNEXPECTED);
222 DCHECK(observers_.empty());
223 CloseAllObservers(ERR_UNEXPECTED);
225 connection()->set_debug_visitor(nullptr);
226 net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
228 while (!stream_requests_.empty()) {
229 StreamRequest* request = stream_requests_.front();
230 stream_requests_.pop_front();
231 request->OnRequestCompleteFailure(ERR_ABORTED);
235 if (connection()->connected()) {
236 // Ensure that the connection is closed by the time the session is
237 // destroyed.
238 connection()->CloseConnection(QUIC_INTERNAL_ERROR, false);
241 if (IsEncryptionEstablished())
242 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
243 if (IsCryptoHandshakeConfirmed())
244 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
245 else
246 RecordHandshakeState(STATE_FAILED);
248 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
249 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
250 crypto_stream_->num_sent_client_hellos());
251 if (!IsCryptoHandshakeConfirmed())
252 return;
254 // Sending one client_hello means we had zero handshake-round-trips.
255 int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
257 // Don't bother with these histogram during tests, which mock out
258 // num_sent_client_hellos().
259 if (round_trip_handshakes < 0 || !stream_factory_)
260 return;
262 bool port_selected = stream_factory_->enable_port_selection();
263 SSLInfo ssl_info;
264 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
265 if (port_selected) {
266 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
267 round_trip_handshakes, 0, 3, 4);
268 } else {
269 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
270 round_trip_handshakes, 0, 3, 4);
271 if (require_confirmation_) {
272 UMA_HISTOGRAM_CUSTOM_COUNTS(
273 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
274 round_trip_handshakes, 0, 3, 4);
277 } else {
278 if (port_selected) {
279 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
280 round_trip_handshakes, 0, 3, 4);
281 } else {
282 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
283 round_trip_handshakes, 0, 3, 4);
284 if (require_confirmation_) {
285 UMA_HISTOGRAM_CUSTOM_COUNTS(
286 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
287 round_trip_handshakes, 0, 3, 4);
291 const QuicConnectionStats stats = connection()->GetStats();
292 if (server_info_ && stats.min_rtt_us > 0) {
293 base::TimeTicks wait_for_data_start_time =
294 server_info_->wait_for_data_start_time();
295 base::TimeTicks wait_for_data_end_time =
296 server_info_->wait_for_data_end_time();
297 if (!wait_for_data_start_time.is_null() &&
298 !wait_for_data_end_time.is_null()) {
299 base::TimeDelta wait_time =
300 wait_for_data_end_time - wait_for_data_start_time;
301 const base::HistogramBase::Sample kMaxWaitToRtt = 1000;
302 base::HistogramBase::Sample wait_to_rtt =
303 static_cast<base::HistogramBase::Sample>(
304 100 * wait_time.InMicroseconds() / stats.min_rtt_us);
305 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicServerInfo.WaitForDataReadyToRtt",
306 wait_to_rtt, 0, kMaxWaitToRtt, 50);
310 if (stats.max_sequence_reordering == 0)
311 return;
312 const base::HistogramBase::Sample kMaxReordering = 100;
313 base::HistogramBase::Sample reordering = kMaxReordering;
314 if (stats.min_rtt_us > 0) {
315 reordering = static_cast<base::HistogramBase::Sample>(
316 100 * stats.max_time_reordering_us / stats.min_rtt_us);
318 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime",
319 reordering, 0, kMaxReordering, 50);
320 if (stats.min_rtt_us > 100 * 1000) {
321 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
322 reordering, 0, kMaxReordering, 50);
324 UMA_HISTOGRAM_COUNTS(
325 "Net.QuicSession.MaxReordering",
326 static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
329 void QuicClientSession::OnStreamFrames(
330 const std::vector<QuicStreamFrame>& frames) {
331 // Record total number of stream frames.
332 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames.size());
334 // Record number of frames per stream in packet.
335 typedef std::map<QuicStreamId, size_t> FrameCounter;
336 FrameCounter frames_per_stream;
337 for (size_t i = 0; i < frames.size(); ++i) {
338 frames_per_stream[frames[i].stream_id]++;
340 for (FrameCounter::const_iterator it = frames_per_stream.begin();
341 it != frames_per_stream.end(); ++it) {
342 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
343 it->second);
346 return QuicSession::OnStreamFrames(frames);
349 void QuicClientSession::AddObserver(Observer* observer) {
350 if (going_away_) {
351 RecordUnexpectedObservers(ADD_OBSERVER);
352 observer->OnSessionClosed(ERR_UNEXPECTED);
353 return;
356 DCHECK(!ContainsKey(observers_, observer));
357 observers_.insert(observer);
360 void QuicClientSession::RemoveObserver(Observer* observer) {
361 DCHECK(ContainsKey(observers_, observer));
362 observers_.erase(observer);
365 int QuicClientSession::TryCreateStream(StreamRequest* request,
366 QuicReliableClientStream** stream) {
367 if (!crypto_stream_->encryption_established()) {
368 DLOG(DFATAL) << "Encryption not established.";
369 return ERR_CONNECTION_CLOSED;
372 if (goaway_received()) {
373 DVLOG(1) << "Going away.";
374 return ERR_CONNECTION_CLOSED;
377 if (!connection()->connected()) {
378 DVLOG(1) << "Already closed.";
379 return ERR_CONNECTION_CLOSED;
382 if (going_away_) {
383 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
384 return ERR_CONNECTION_CLOSED;
387 if (GetNumOpenStreams() < get_max_open_streams()) {
388 *stream = CreateOutgoingReliableStreamImpl();
389 return OK;
392 stream_requests_.push_back(request);
393 return ERR_IO_PENDING;
396 void QuicClientSession::CancelRequest(StreamRequest* request) {
397 // Remove |request| from the queue while preserving the order of the
398 // other elements.
399 StreamRequestQueue::iterator it =
400 std::find(stream_requests_.begin(), stream_requests_.end(), request);
401 if (it != stream_requests_.end()) {
402 it = stream_requests_.erase(it);
406 QuicReliableClientStream* QuicClientSession::CreateOutgoingDataStream() {
407 if (!crypto_stream_->encryption_established()) {
408 DVLOG(1) << "Encryption not active so no outgoing stream created.";
409 return nullptr;
411 if (GetNumOpenStreams() >= get_max_open_streams()) {
412 DVLOG(1) << "Failed to create a new outgoing stream. "
413 << "Already " << GetNumOpenStreams() << " open.";
414 return nullptr;
416 if (goaway_received()) {
417 DVLOG(1) << "Failed to create a new outgoing stream. "
418 << "Already received goaway.";
419 return nullptr;
421 if (going_away_) {
422 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
423 return nullptr;
425 return CreateOutgoingReliableStreamImpl();
428 QuicReliableClientStream*
429 QuicClientSession::CreateOutgoingReliableStreamImpl() {
430 DCHECK(connection()->connected());
431 QuicReliableClientStream* stream =
432 new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
433 ActivateStream(stream);
434 ++num_total_streams_;
435 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
436 // The previous histogram puts 100 in a bucket betweeen 86-113 which does
437 // not shed light on if chrome ever things it has more than 100 streams open.
438 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.TooManyOpenStreams",
439 GetNumOpenStreams() > 100);
440 return stream;
443 QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
444 return crypto_stream_.get();
447 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
448 // we learn about SSL info (sync vs async vs cached).
449 bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
450 ssl_info->Reset();
451 if (!cert_verify_result_) {
452 return false;
455 ssl_info->cert_status = cert_verify_result_->cert_status;
456 ssl_info->cert = cert_verify_result_->verified_cert;
458 // TODO(wtc): Define QUIC "cipher suites".
459 // Report the TLS cipher suite that most closely resembles the crypto
460 // parameters of the QUIC connection.
461 QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
462 uint16 cipher_suite;
463 int security_bits;
464 switch (aead) {
465 case kAESG:
466 cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
467 security_bits = 128;
468 break;
469 case kCC12:
470 cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
471 security_bits = 256;
472 break;
473 default:
474 NOTREACHED();
475 return false;
477 int ssl_connection_status = 0;
478 ssl_connection_status |= cipher_suite;
479 ssl_connection_status |=
480 (SSL_CONNECTION_VERSION_QUIC & SSL_CONNECTION_VERSION_MASK) <<
481 SSL_CONNECTION_VERSION_SHIFT;
483 ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
484 ssl_info->is_issued_by_known_root =
485 cert_verify_result_->is_issued_by_known_root;
487 ssl_info->connection_status = ssl_connection_status;
488 ssl_info->client_cert_sent = false;
489 ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent();
490 ssl_info->security_bits = security_bits;
491 ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
492 ssl_info->pinning_failure_log = pinning_failure_log_;
493 return true;
496 int QuicClientSession::CryptoConnect(bool require_confirmation,
497 const CompletionCallback& callback) {
498 require_confirmation_ = require_confirmation;
499 handshake_start_ = base::TimeTicks::Now();
500 RecordHandshakeState(STATE_STARTED);
501 DCHECK(flow_controller());
502 crypto_stream_->CryptoConnect();
504 if (IsCryptoHandshakeConfirmed())
505 return OK;
507 // Unless we require handshake confirmation, activate the session if
508 // we have established initial encryption.
509 if (!require_confirmation_ && IsEncryptionEstablished()) {
510 // To mitigate the effects of hanging 0-RTT connections, set up a timer to
511 // cancel any requests, if the handshake takes too long.
512 task_runner_->PostDelayedTask(
513 FROM_HERE,
514 base::Bind(&QuicClientSession::OnConnectTimeout,
515 weak_factory_.GetWeakPtr()),
516 base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs));
517 return OK;
521 callback_ = callback;
522 return ERR_IO_PENDING;
525 int QuicClientSession::ResumeCryptoConnect(const CompletionCallback& callback) {
527 if (IsCryptoHandshakeConfirmed())
528 return OK;
530 if (!connection()->connected())
531 return ERR_QUIC_HANDSHAKE_FAILED;
533 callback_ = callback;
534 return ERR_IO_PENDING;
537 int QuicClientSession::GetNumSentClientHellos() const {
538 return crypto_stream_->num_sent_client_hellos();
541 bool QuicClientSession::CanPool(const std::string& hostname,
542 PrivacyMode privacy_mode) const {
543 DCHECK(connection()->connected());
544 if (privacy_mode != server_id_.privacy_mode()) {
545 // Privacy mode must always match.
546 return false;
548 SSLInfo ssl_info;
549 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
550 // We can always pool with insecure QUIC sessions.
551 return true;
554 return SpdySession::CanPool(transport_security_state_, ssl_info,
555 server_id_.host(), hostname);
558 QuicDataStream* QuicClientSession::CreateIncomingDataStream(
559 QuicStreamId id) {
560 DLOG(ERROR) << "Server push not supported";
561 return nullptr;
564 void QuicClientSession::CloseStream(QuicStreamId stream_id) {
565 ReliableQuicStream* stream = GetStream(stream_id);
566 if (stream) {
567 logger_->UpdateReceivedFrameCounts(
568 stream_id, stream->num_frames_received(),
569 stream->num_duplicate_frames_received());
571 QuicSession::CloseStream(stream_id);
572 OnClosedStream();
575 void QuicClientSession::SendRstStream(QuicStreamId id,
576 QuicRstStreamErrorCode error,
577 QuicStreamOffset bytes_written) {
578 QuicSession::SendRstStream(id, error, bytes_written);
579 OnClosedStream();
582 void QuicClientSession::OnClosedStream() {
583 if (GetNumOpenStreams() < get_max_open_streams() &&
584 !stream_requests_.empty() &&
585 crypto_stream_->encryption_established() &&
586 !goaway_received() &&
587 !going_away_ &&
588 connection()->connected()) {
589 StreamRequest* request = stream_requests_.front();
590 stream_requests_.pop_front();
591 request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
594 if (GetNumOpenStreams() == 0) {
595 stream_factory_->OnIdleSession(this);
599 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
600 if (stream_factory_ && event == HANDSHAKE_CONFIRMED &&
601 (stream_factory_->OnHandshakeConfirmed(
602 this, logger_->ReceivedPacketLossRate()))) {
603 return;
606 if (!callback_.is_null() &&
607 (!require_confirmation_ ||
608 event == HANDSHAKE_CONFIRMED || event == ENCRYPTION_REESTABLISHED)) {
609 // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
610 // could be called because there are no error events in CryptoHandshakeEvent
611 // enum. If error events are added to CryptoHandshakeEvent, then the
612 // following code needs to changed.
613 base::ResetAndReturn(&callback_).Run(OK);
615 if (event == HANDSHAKE_CONFIRMED) {
616 UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime",
617 base::TimeTicks::Now() - handshake_start_);
618 if (server_info_) {
619 // TODO(rtenneti): Should we delete this histogram?
620 // Track how long it has taken to finish handshake once we start waiting
621 // for reading of QUIC server information from disk cache. We could use
622 // this data to compare total time taken if we were to cancel the disk
623 // cache read vs waiting for the read to complete.
624 base::TimeTicks wait_for_data_start_time =
625 server_info_->wait_for_data_start_time();
626 if (!wait_for_data_start_time.is_null()) {
627 UMA_HISTOGRAM_TIMES(
628 "Net.QuicServerInfo.WaitForDataReady.HandshakeConfirmedTime",
629 base::TimeTicks::Now() - wait_for_data_start_time);
632 // Track how long it has taken to finish handshake after we have finished
633 // DNS host resolution.
634 if (!dns_resolution_end_time_.is_null()) {
635 UMA_HISTOGRAM_TIMES(
636 "Net.QuicSession.HostResolution.HandshakeConfirmedTime",
637 base::TimeTicks::Now() - dns_resolution_end_time_);
640 ObserverSet::iterator it = observers_.begin();
641 while (it != observers_.end()) {
642 Observer* observer = *it;
643 ++it;
644 observer->OnCryptoHandshakeConfirmed();
646 if (server_info_)
647 server_info_->OnExternalCacheHit();
649 QuicSession::OnCryptoHandshakeEvent(event);
652 void QuicClientSession::OnCryptoHandshakeMessageSent(
653 const CryptoHandshakeMessage& message) {
654 logger_->OnCryptoHandshakeMessageSent(message);
657 void QuicClientSession::OnCryptoHandshakeMessageReceived(
658 const CryptoHandshakeMessage& message) {
659 logger_->OnCryptoHandshakeMessageReceived(message);
662 void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
663 bool from_peer) {
664 DCHECK(!connection()->connected());
665 logger_->OnConnectionClosed(error, from_peer);
666 if (from_peer) {
667 UMA_HISTOGRAM_SPARSE_SLOWLY(
668 "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
669 } else {
670 UMA_HISTOGRAM_SPARSE_SLOWLY(
671 "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
674 if (error == QUIC_CONNECTION_TIMED_OUT) {
675 UMA_HISTOGRAM_COUNTS(
676 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
677 GetNumOpenStreams());
678 if (IsCryptoHandshakeConfirmed()) {
679 if (GetNumOpenStreams() > 0) {
680 UMA_HISTOGRAM_BOOLEAN(
681 "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
682 connection()->sent_packet_manager().HasUnackedPackets());
683 UMA_HISTOGRAM_COUNTS(
684 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
685 connection()->sent_packet_manager().consecutive_rto_count());
686 UMA_HISTOGRAM_COUNTS(
687 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
688 connection()->sent_packet_manager().consecutive_tlp_count());
690 if (connection()->sent_packet_manager().HasUnackedPackets()) {
691 UMA_HISTOGRAM_TIMES(
692 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
693 "TimeSinceLastReceived.UnackedPackets",
694 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
695 } else {
696 UMA_HISTOGRAM_TIMES(
697 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
698 "TimeSinceLastReceived.NoUnackedPackets",
699 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
702 } else {
703 UMA_HISTOGRAM_COUNTS(
704 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
705 GetNumOpenStreams());
706 UMA_HISTOGRAM_COUNTS(
707 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
708 num_total_streams_);
712 if (!IsCryptoHandshakeConfirmed()) {
713 if (error == QUIC_PUBLIC_RESET) {
714 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
715 } else if (connection()->GetStats().packets_received == 0) {
716 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
717 UMA_HISTOGRAM_SPARSE_SLOWLY(
718 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
719 error);
720 } else {
721 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
722 UMA_HISTOGRAM_SPARSE_SLOWLY(
723 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
724 error);
728 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
729 connection()->version());
730 NotifyFactoryOfSessionGoingAway();
731 if (!callback_.is_null()) {
732 base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
734 socket_->Close();
735 QuicSession::OnConnectionClosed(error, from_peer);
736 DCHECK(streams()->empty());
737 CloseAllStreams(ERR_UNEXPECTED);
738 CloseAllObservers(ERR_UNEXPECTED);
739 NotifyFactoryOfSessionClosedLater();
742 void QuicClientSession::OnSuccessfulVersionNegotiation(
743 const QuicVersion& version) {
744 logger_->OnSuccessfulVersionNegotiation(version);
745 QuicSession::OnSuccessfulVersionNegotiation(version);
748 void QuicClientSession::OnProofValid(
749 const QuicCryptoClientConfig::CachedState& cached) {
750 DCHECK(cached.proof_valid());
752 if (!server_info_) {
753 return;
756 QuicServerInfo::State* state = server_info_->mutable_state();
758 state->server_config = cached.server_config();
759 state->source_address_token = cached.source_address_token();
760 state->server_config_sig = cached.signature();
761 state->certs = cached.certs();
763 server_info_->Persist();
766 void QuicClientSession::OnProofVerifyDetailsAvailable(
767 const ProofVerifyDetails& verify_details) {
768 const ProofVerifyDetailsChromium* verify_details_chromium =
769 reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
770 CertVerifyResult* result_copy = new CertVerifyResult;
771 result_copy->CopyFrom(verify_details_chromium->cert_verify_result);
772 cert_verify_result_.reset(result_copy);
773 pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
774 logger_->OnCertificateVerified(*cert_verify_result_);
777 void QuicClientSession::StartReading() {
778 packet_reader_.StartReading();
781 void QuicClientSession::CloseSessionOnError(int error,
782 QuicErrorCode quic_error) {
783 RecordAndCloseSessionOnError(error, quic_error);
784 NotifyFactoryOfSessionClosed();
787 void QuicClientSession::CloseSessionOnErrorAndNotifyFactoryLater(
788 int error,
789 QuicErrorCode quic_error) {
790 RecordAndCloseSessionOnError(error, quic_error);
791 NotifyFactoryOfSessionClosedLater();
794 void QuicClientSession::RecordAndCloseSessionOnError(int error,
795 QuicErrorCode quic_error) {
796 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
797 CloseSessionOnErrorInner(error, quic_error);
800 void QuicClientSession::CloseSessionOnErrorInner(int net_error,
801 QuicErrorCode quic_error) {
802 if (!callback_.is_null()) {
803 base::ResetAndReturn(&callback_).Run(net_error);
805 CloseAllStreams(net_error);
806 CloseAllObservers(net_error);
807 net_log_.AddEvent(
808 NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
809 NetLog::IntegerCallback("net_error", net_error));
811 if (connection()->connected())
812 connection()->CloseConnection(quic_error, false);
813 DCHECK(!connection()->connected());
816 void QuicClientSession::CloseAllStreams(int net_error) {
817 while (!streams()->empty()) {
818 ReliableQuicStream* stream = streams()->begin()->second;
819 QuicStreamId id = stream->id();
820 static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
821 CloseStream(id);
825 void QuicClientSession::CloseAllObservers(int net_error) {
826 while (!observers_.empty()) {
827 Observer* observer = *observers_.begin();
828 observers_.erase(observer);
829 observer->OnSessionClosed(net_error);
833 scoped_ptr<base::Value> QuicClientSession::GetInfoAsValue(
834 const std::set<HostPortPair>& aliases) {
835 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
836 dict->SetString("version", QuicVersionToString(connection()->version()));
837 dict->SetInteger("open_streams", GetNumOpenStreams());
838 scoped_ptr<base::ListValue> stream_list(new base::ListValue());
839 for (base::hash_map<QuicStreamId, QuicDataStream*>::const_iterator it
840 = streams()->begin();
841 it != streams()->end();
842 ++it) {
843 stream_list->Append(new base::StringValue(
844 base::Uint64ToString(it->second->id())));
846 dict->Set("active_streams", stream_list.Pass());
848 dict->SetInteger("total_streams", num_total_streams_);
849 dict->SetString("peer_address", peer_address().ToString());
850 dict->SetString("connection_id", base::Uint64ToString(connection_id()));
851 dict->SetBoolean("connected", connection()->connected());
852 const QuicConnectionStats& stats = connection()->GetStats();
853 dict->SetInteger("packets_sent", stats.packets_sent);
854 dict->SetInteger("packets_received", stats.packets_received);
855 dict->SetInteger("packets_lost", stats.packets_lost);
856 SSLInfo ssl_info;
857 dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
859 scoped_ptr<base::ListValue> alias_list(new base::ListValue());
860 for (std::set<HostPortPair>::const_iterator it = aliases.begin();
861 it != aliases.end(); it++) {
862 alias_list->Append(new base::StringValue(it->ToString()));
864 dict->Set("aliases", alias_list.Pass());
866 return dict.Pass();
869 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
870 return weak_factory_.GetWeakPtr();
873 void QuicClientSession::OnReadError(int result) {
874 DVLOG(1) << "Closing session on read error: " << result;
875 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
876 NotifyFactoryOfSessionGoingAway();
877 CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
878 NotifyFactoryOfSessionClosedLater();
881 bool QuicClientSession::OnPacket(const QuicEncryptedPacket& packet,
882 IPEndPoint local_address,
883 IPEndPoint peer_address) {
884 connection()->ProcessUdpPacket(local_address, peer_address, packet);
885 if (!connection()->connected()) {
886 NotifyFactoryOfSessionClosedLater();
887 return false;
889 return true;
892 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
893 going_away_ = true;
894 if (stream_factory_)
895 stream_factory_->OnSessionGoingAway(this);
898 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
899 if (!streams()->empty())
900 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
902 if (!going_away_)
903 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
905 going_away_ = true;
906 DCHECK_EQ(0u, GetNumOpenStreams());
907 DCHECK(!connection()->connected());
908 base::MessageLoop::current()->PostTask(
909 FROM_HERE,
910 base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
911 weak_factory_.GetWeakPtr()));
914 void QuicClientSession::NotifyFactoryOfSessionClosed() {
915 if (!streams()->empty())
916 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
918 if (!going_away_)
919 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
921 going_away_ = true;
922 DCHECK_EQ(0u, GetNumOpenStreams());
923 // Will delete |this|.
924 if (stream_factory_)
925 stream_factory_->OnSessionClosed(this);
928 void QuicClientSession::OnConnectTimeout() {
929 DCHECK(callback_.is_null());
930 DCHECK(IsEncryptionEstablished());
932 if (IsCryptoHandshakeConfirmed())
933 return;
935 // TODO(rch): re-enable this code once beta is cut.
936 // if (stream_factory_)
937 // stream_factory_->OnSessionConnectTimeout(this);
938 // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
939 // DCHECK_EQ(0u, GetNumOpenStreams());
942 } // namespace net