Landing Recent QUIC changes until 06/07/2015.
[chromium-blink-merge.git] / net / quic / quic_client_session.cc
blobf62f61eb952f84d77858137417fd9e97e66ac293
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.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 bool require_confirmation,
104 NetLogCaptureMode /* capture_mode */) {
105 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
106 dict->SetString("host", server_id->host());
107 dict->SetInteger("port", server_id->port());
108 dict->SetBoolean("is_https", server_id->is_https());
109 dict->SetBoolean("privacy_mode",
110 server_id->privacy_mode() == PRIVACY_MODE_ENABLED);
111 dict->SetBoolean("require_confirmation", require_confirmation);
112 return dict.Pass();
115 } // namespace
117 QuicClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
119 QuicClientSession::StreamRequest::~StreamRequest() {
120 CancelRequest();
123 int QuicClientSession::StreamRequest::StartRequest(
124 const base::WeakPtr<QuicClientSession>& session,
125 QuicReliableClientStream** stream,
126 const CompletionCallback& callback) {
127 session_ = session;
128 stream_ = stream;
129 int rv = session_->TryCreateStream(this, stream_);
130 if (rv == ERR_IO_PENDING) {
131 callback_ = callback;
134 return rv;
137 void QuicClientSession::StreamRequest::CancelRequest() {
138 if (session_)
139 session_->CancelRequest(this);
140 session_.reset();
141 callback_.Reset();
144 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
145 QuicReliableClientStream* stream) {
146 session_.reset();
147 *stream_ = stream;
148 ResetAndReturn(&callback_).Run(OK);
151 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
152 session_.reset();
153 ResetAndReturn(&callback_).Run(rv);
156 QuicClientSession::QuicClientSession(
157 QuicConnection* connection,
158 scoped_ptr<DatagramClientSocket> socket,
159 QuicStreamFactory* stream_factory,
160 QuicCryptoClientStreamFactory* crypto_client_stream_factory,
161 TransportSecurityState* transport_security_state,
162 scoped_ptr<QuicServerInfo> server_info,
163 const QuicServerId& server_id,
164 const QuicConfig& config,
165 QuicCryptoClientConfig* crypto_config,
166 const char* const connection_description,
167 base::TimeTicks dns_resolution_end_time,
168 base::TaskRunner* task_runner,
169 NetLog* net_log)
170 : QuicClientSessionBase(connection, config),
171 server_id_(server_id),
172 require_confirmation_(false),
173 stream_factory_(stream_factory),
174 socket_(socket.Pass()),
175 transport_security_state_(transport_security_state),
176 server_info_(server_info.Pass()),
177 num_total_streams_(0),
178 task_runner_(task_runner),
179 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
180 packet_reader_(socket_.get(), this, net_log_),
181 dns_resolution_end_time_(dns_resolution_end_time),
182 logger_(new QuicConnectionLogger(this, connection_description, net_log_)),
183 going_away_(false),
184 weak_factory_(this) {
185 crypto_stream_.reset(
186 crypto_client_stream_factory ?
187 crypto_client_stream_factory->CreateQuicCryptoClientStream(
188 server_id, this, crypto_config) :
189 new QuicCryptoClientStream(server_id, this,
190 new ProofVerifyContextChromium(net_log_),
191 crypto_config));
192 connection->set_debug_visitor(logger_.get());
193 net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION,
194 base::Bind(NetLogQuicClientSessionCallback,
195 &server_id,
196 require_confirmation_));
197 IPEndPoint address;
198 if (socket && socket->GetLocalAddress(&address) == OK &&
199 address.GetFamily() == ADDRESS_FAMILY_IPV6) {
200 connection->set_max_packet_length(connection->max_packet_length() -
201 kAdditionalOverheadForIPv6);
205 QuicClientSession::~QuicClientSession() {
206 if (!streams()->empty())
207 RecordUnexpectedOpenStreams(DESTRUCTOR);
208 if (!observers_.empty())
209 RecordUnexpectedObservers(DESTRUCTOR);
210 if (!going_away_)
211 RecordUnexpectedNotGoingAway(DESTRUCTOR);
213 while (!streams()->empty() ||
214 !observers_.empty() ||
215 !stream_requests_.empty()) {
216 // The session must be closed before it is destroyed.
217 DCHECK(streams()->empty());
218 CloseAllStreams(ERR_UNEXPECTED);
219 DCHECK(observers_.empty());
220 CloseAllObservers(ERR_UNEXPECTED);
222 connection()->set_debug_visitor(nullptr);
223 net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
225 while (!stream_requests_.empty()) {
226 StreamRequest* request = stream_requests_.front();
227 stream_requests_.pop_front();
228 request->OnRequestCompleteFailure(ERR_ABORTED);
232 if (connection()->connected()) {
233 // Ensure that the connection is closed by the time the session is
234 // destroyed.
235 connection()->CloseConnection(QUIC_INTERNAL_ERROR, false);
238 if (IsEncryptionEstablished())
239 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
240 if (IsCryptoHandshakeConfirmed())
241 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
242 else
243 RecordHandshakeState(STATE_FAILED);
245 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
246 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
247 crypto_stream_->num_sent_client_hellos());
248 if (!IsCryptoHandshakeConfirmed())
249 return;
251 // Sending one client_hello means we had zero handshake-round-trips.
252 int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
254 // Don't bother with these histogram during tests, which mock out
255 // num_sent_client_hellos().
256 if (round_trip_handshakes < 0 || !stream_factory_)
257 return;
259 bool port_selected = stream_factory_->enable_port_selection();
260 SSLInfo ssl_info;
261 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
262 if (port_selected) {
263 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
264 round_trip_handshakes, 0, 3, 4);
265 } else {
266 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
267 round_trip_handshakes, 0, 3, 4);
268 if (require_confirmation_) {
269 UMA_HISTOGRAM_CUSTOM_COUNTS(
270 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
271 round_trip_handshakes, 0, 3, 4);
274 } else {
275 if (port_selected) {
276 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
277 round_trip_handshakes, 0, 3, 4);
278 } else {
279 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
280 round_trip_handshakes, 0, 3, 4);
281 if (require_confirmation_) {
282 UMA_HISTOGRAM_CUSTOM_COUNTS(
283 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
284 round_trip_handshakes, 0, 3, 4);
288 const QuicConnectionStats stats = connection()->GetStats();
289 if (server_info_ && stats.min_rtt_us > 0) {
290 base::TimeTicks wait_for_data_start_time =
291 server_info_->wait_for_data_start_time();
292 base::TimeTicks wait_for_data_end_time =
293 server_info_->wait_for_data_end_time();
294 if (!wait_for_data_start_time.is_null() &&
295 !wait_for_data_end_time.is_null()) {
296 base::TimeDelta wait_time =
297 wait_for_data_end_time - wait_for_data_start_time;
298 const base::HistogramBase::Sample kMaxWaitToRtt = 1000;
299 base::HistogramBase::Sample wait_to_rtt =
300 static_cast<base::HistogramBase::Sample>(
301 100 * wait_time.InMicroseconds() / stats.min_rtt_us);
302 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicServerInfo.WaitForDataReadyToRtt",
303 wait_to_rtt, 0, kMaxWaitToRtt, 50);
307 if (stats.max_sequence_reordering == 0)
308 return;
309 const base::HistogramBase::Sample kMaxReordering = 100;
310 base::HistogramBase::Sample reordering = kMaxReordering;
311 if (stats.min_rtt_us > 0) {
312 reordering = static_cast<base::HistogramBase::Sample>(
313 100 * stats.max_time_reordering_us / stats.min_rtt_us);
315 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime",
316 reordering, 0, kMaxReordering, 50);
317 if (stats.min_rtt_us > 100 * 1000) {
318 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
319 reordering, 0, kMaxReordering, 50);
321 UMA_HISTOGRAM_COUNTS(
322 "Net.QuicSession.MaxReordering",
323 static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
326 void QuicClientSession::OnStreamFrames(
327 const std::vector<QuicStreamFrame>& frames) {
328 // Record total number of stream frames.
329 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames.size());
331 // Record number of frames per stream in packet.
332 typedef std::map<QuicStreamId, size_t> FrameCounter;
333 FrameCounter frames_per_stream;
334 for (size_t i = 0; i < frames.size(); ++i) {
335 frames_per_stream[frames[i].stream_id]++;
337 for (FrameCounter::const_iterator it = frames_per_stream.begin();
338 it != frames_per_stream.end(); ++it) {
339 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
340 it->second);
343 return QuicSession::OnStreamFrames(frames);
346 void QuicClientSession::AddObserver(Observer* observer) {
347 if (going_away_) {
348 RecordUnexpectedObservers(ADD_OBSERVER);
349 observer->OnSessionClosed(ERR_UNEXPECTED);
350 return;
353 DCHECK(!ContainsKey(observers_, observer));
354 observers_.insert(observer);
357 void QuicClientSession::RemoveObserver(Observer* observer) {
358 DCHECK(ContainsKey(observers_, observer));
359 observers_.erase(observer);
362 int QuicClientSession::TryCreateStream(StreamRequest* request,
363 QuicReliableClientStream** stream) {
364 if (!crypto_stream_->encryption_established()) {
365 DLOG(DFATAL) << "Encryption not established.";
366 return ERR_CONNECTION_CLOSED;
369 if (goaway_received()) {
370 DVLOG(1) << "Going away.";
371 return ERR_CONNECTION_CLOSED;
374 if (!connection()->connected()) {
375 DVLOG(1) << "Already closed.";
376 return ERR_CONNECTION_CLOSED;
379 if (going_away_) {
380 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
381 return ERR_CONNECTION_CLOSED;
384 if (GetNumOpenStreams() < get_max_open_streams()) {
385 *stream = CreateOutgoingReliableStreamImpl();
386 return OK;
389 stream_requests_.push_back(request);
390 return ERR_IO_PENDING;
393 void QuicClientSession::CancelRequest(StreamRequest* request) {
394 // Remove |request| from the queue while preserving the order of the
395 // other elements.
396 StreamRequestQueue::iterator it =
397 std::find(stream_requests_.begin(), stream_requests_.end(), request);
398 if (it != stream_requests_.end()) {
399 it = stream_requests_.erase(it);
403 QuicReliableClientStream* QuicClientSession::CreateOutgoingDataStream() {
404 if (!crypto_stream_->encryption_established()) {
405 DVLOG(1) << "Encryption not active so no outgoing stream created.";
406 return nullptr;
408 if (GetNumOpenStreams() >= get_max_open_streams()) {
409 DVLOG(1) << "Failed to create a new outgoing stream. "
410 << "Already " << GetNumOpenStreams() << " open.";
411 return nullptr;
413 if (goaway_received()) {
414 DVLOG(1) << "Failed to create a new outgoing stream. "
415 << "Already received goaway.";
416 return nullptr;
418 if (going_away_) {
419 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
420 return nullptr;
422 return CreateOutgoingReliableStreamImpl();
425 QuicReliableClientStream*
426 QuicClientSession::CreateOutgoingReliableStreamImpl() {
427 DCHECK(connection()->connected());
428 QuicReliableClientStream* stream =
429 new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
430 ActivateStream(stream);
431 ++num_total_streams_;
432 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
433 // The previous histogram puts 100 in a bucket betweeen 86-113 which does
434 // not shed light on if chrome ever things it has more than 100 streams open.
435 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.TooManyOpenStreams",
436 GetNumOpenStreams() > 100);
437 return stream;
440 QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
441 return crypto_stream_.get();
444 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
445 // we learn about SSL info (sync vs async vs cached).
446 bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
447 ssl_info->Reset();
448 if (!cert_verify_result_) {
449 return false;
452 ssl_info->cert_status = cert_verify_result_->cert_status;
453 ssl_info->cert = cert_verify_result_->verified_cert;
455 // TODO(wtc): Define QUIC "cipher suites".
456 // Report the TLS cipher suite that most closely resembles the crypto
457 // parameters of the QUIC connection.
458 QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
459 uint16 cipher_suite;
460 int security_bits;
461 switch (aead) {
462 case kAESG:
463 cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
464 security_bits = 128;
465 break;
466 case kCC12:
467 cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
468 security_bits = 256;
469 break;
470 default:
471 NOTREACHED();
472 return false;
474 int ssl_connection_status = 0;
475 ssl_connection_status |= cipher_suite;
476 ssl_connection_status |=
477 (SSL_CONNECTION_VERSION_QUIC & SSL_CONNECTION_VERSION_MASK) <<
478 SSL_CONNECTION_VERSION_SHIFT;
480 ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
481 ssl_info->is_issued_by_known_root =
482 cert_verify_result_->is_issued_by_known_root;
484 ssl_info->connection_status = ssl_connection_status;
485 ssl_info->client_cert_sent = false;
486 ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent();
487 ssl_info->security_bits = security_bits;
488 ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
489 ssl_info->pinning_failure_log = pinning_failure_log_;
490 return true;
493 int QuicClientSession::CryptoConnect(bool require_confirmation,
494 const CompletionCallback& callback) {
495 require_confirmation_ = require_confirmation;
496 handshake_start_ = base::TimeTicks::Now();
497 RecordHandshakeState(STATE_STARTED);
498 DCHECK(flow_controller());
499 crypto_stream_->CryptoConnect();
501 if (IsCryptoHandshakeConfirmed())
502 return OK;
504 // Unless we require handshake confirmation, activate the session if
505 // we have established initial encryption.
506 if (!require_confirmation_ && IsEncryptionEstablished()) {
507 // To mitigate the effects of hanging 0-RTT connections, set up a timer to
508 // cancel any requests, if the handshake takes too long.
509 task_runner_->PostDelayedTask(
510 FROM_HERE,
511 base::Bind(&QuicClientSession::OnConnectTimeout,
512 weak_factory_.GetWeakPtr()),
513 base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs));
514 return OK;
518 callback_ = callback;
519 return ERR_IO_PENDING;
522 int QuicClientSession::ResumeCryptoConnect(const CompletionCallback& callback) {
524 if (IsCryptoHandshakeConfirmed())
525 return OK;
527 if (!connection()->connected())
528 return ERR_QUIC_HANDSHAKE_FAILED;
530 callback_ = callback;
531 return ERR_IO_PENDING;
534 int QuicClientSession::GetNumSentClientHellos() const {
535 return crypto_stream_->num_sent_client_hellos();
538 bool QuicClientSession::CanPool(const std::string& hostname,
539 PrivacyMode privacy_mode) const {
540 DCHECK(connection()->connected());
541 if (privacy_mode != server_id_.privacy_mode()) {
542 // Privacy mode must always match.
543 return false;
545 SSLInfo ssl_info;
546 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
547 // We can always pool with insecure QUIC sessions.
548 return true;
551 return SpdySession::CanPool(transport_security_state_, ssl_info,
552 server_id_.host(), hostname);
555 QuicDataStream* QuicClientSession::CreateIncomingDataStream(
556 QuicStreamId id) {
557 DLOG(ERROR) << "Server push not supported";
558 return nullptr;
561 void QuicClientSession::CloseStream(QuicStreamId stream_id) {
562 ReliableQuicStream* stream = GetStream(stream_id);
563 if (stream) {
564 logger_->UpdateReceivedFrameCounts(
565 stream_id, stream->num_frames_received(),
566 stream->num_duplicate_frames_received());
568 QuicSession::CloseStream(stream_id);
569 OnClosedStream();
572 void QuicClientSession::SendRstStream(QuicStreamId id,
573 QuicRstStreamErrorCode error,
574 QuicStreamOffset bytes_written) {
575 QuicSession::SendRstStream(id, error, bytes_written);
576 OnClosedStream();
579 void QuicClientSession::OnClosedStream() {
580 if (GetNumOpenStreams() < get_max_open_streams() &&
581 !stream_requests_.empty() &&
582 crypto_stream_->encryption_established() &&
583 !goaway_received() &&
584 !going_away_ &&
585 connection()->connected()) {
586 StreamRequest* request = stream_requests_.front();
587 stream_requests_.pop_front();
588 request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
591 if (GetNumOpenStreams() == 0) {
592 stream_factory_->OnIdleSession(this);
596 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
597 if (stream_factory_ && event == HANDSHAKE_CONFIRMED &&
598 (stream_factory_->OnHandshakeConfirmed(
599 this, logger_->ReceivedPacketLossRate()))) {
600 return;
603 if (!callback_.is_null() &&
604 (!require_confirmation_ ||
605 event == HANDSHAKE_CONFIRMED || event == ENCRYPTION_REESTABLISHED)) {
606 // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
607 // could be called because there are no error events in CryptoHandshakeEvent
608 // enum. If error events are added to CryptoHandshakeEvent, then the
609 // following code needs to changed.
610 base::ResetAndReturn(&callback_).Run(OK);
612 if (event == HANDSHAKE_CONFIRMED) {
613 UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime",
614 base::TimeTicks::Now() - handshake_start_);
615 if (server_info_) {
616 // TODO(rtenneti): Should we delete this histogram?
617 // Track how long it has taken to finish handshake once we start waiting
618 // for reading of QUIC server information from disk cache. We could use
619 // this data to compare total time taken if we were to cancel the disk
620 // cache read vs waiting for the read to complete.
621 base::TimeTicks wait_for_data_start_time =
622 server_info_->wait_for_data_start_time();
623 if (!wait_for_data_start_time.is_null()) {
624 UMA_HISTOGRAM_TIMES(
625 "Net.QuicServerInfo.WaitForDataReady.HandshakeConfirmedTime",
626 base::TimeTicks::Now() - wait_for_data_start_time);
629 // Track how long it has taken to finish handshake after we have finished
630 // DNS host resolution.
631 if (!dns_resolution_end_time_.is_null()) {
632 UMA_HISTOGRAM_TIMES(
633 "Net.QuicSession.HostResolution.HandshakeConfirmedTime",
634 base::TimeTicks::Now() - dns_resolution_end_time_);
637 ObserverSet::iterator it = observers_.begin();
638 while (it != observers_.end()) {
639 Observer* observer = *it;
640 ++it;
641 observer->OnCryptoHandshakeConfirmed();
643 if (server_info_)
644 server_info_->OnExternalCacheHit();
646 QuicSession::OnCryptoHandshakeEvent(event);
649 void QuicClientSession::OnCryptoHandshakeMessageSent(
650 const CryptoHandshakeMessage& message) {
651 logger_->OnCryptoHandshakeMessageSent(message);
654 void QuicClientSession::OnCryptoHandshakeMessageReceived(
655 const CryptoHandshakeMessage& message) {
656 logger_->OnCryptoHandshakeMessageReceived(message);
659 void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
660 bool from_peer) {
661 DCHECK(!connection()->connected());
662 logger_->OnConnectionClosed(error, from_peer);
663 if (from_peer) {
664 UMA_HISTOGRAM_SPARSE_SLOWLY(
665 "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
666 } else {
667 UMA_HISTOGRAM_SPARSE_SLOWLY(
668 "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
671 if (error == QUIC_CONNECTION_TIMED_OUT) {
672 UMA_HISTOGRAM_COUNTS(
673 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
674 GetNumOpenStreams());
675 if (IsCryptoHandshakeConfirmed()) {
676 if (GetNumOpenStreams() > 0) {
677 UMA_HISTOGRAM_BOOLEAN(
678 "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
679 connection()->sent_packet_manager().HasUnackedPackets());
680 UMA_HISTOGRAM_COUNTS(
681 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
682 connection()->sent_packet_manager().consecutive_rto_count());
683 UMA_HISTOGRAM_COUNTS(
684 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
685 connection()->sent_packet_manager().consecutive_tlp_count());
687 if (connection()->sent_packet_manager().HasUnackedPackets()) {
688 UMA_HISTOGRAM_TIMES(
689 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
690 "TimeSinceLastReceived.UnackedPackets",
691 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
692 } else {
693 UMA_HISTOGRAM_TIMES(
694 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
695 "TimeSinceLastReceived.NoUnackedPackets",
696 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
699 } else {
700 UMA_HISTOGRAM_COUNTS(
701 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
702 GetNumOpenStreams());
703 UMA_HISTOGRAM_COUNTS(
704 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
705 num_total_streams_);
709 if (!IsCryptoHandshakeConfirmed()) {
710 if (error == QUIC_PUBLIC_RESET) {
711 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
712 } else if (connection()->GetStats().packets_received == 0) {
713 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
714 UMA_HISTOGRAM_SPARSE_SLOWLY(
715 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
716 error);
717 } else {
718 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
719 UMA_HISTOGRAM_SPARSE_SLOWLY(
720 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
721 error);
725 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
726 connection()->version());
727 NotifyFactoryOfSessionGoingAway();
728 if (!callback_.is_null()) {
729 base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
731 socket_->Close();
732 QuicSession::OnConnectionClosed(error, from_peer);
733 DCHECK(streams()->empty());
734 CloseAllStreams(ERR_UNEXPECTED);
735 CloseAllObservers(ERR_UNEXPECTED);
736 NotifyFactoryOfSessionClosedLater();
739 void QuicClientSession::OnSuccessfulVersionNegotiation(
740 const QuicVersion& version) {
741 logger_->OnSuccessfulVersionNegotiation(version);
742 QuicSession::OnSuccessfulVersionNegotiation(version);
745 void QuicClientSession::OnProofValid(
746 const QuicCryptoClientConfig::CachedState& cached) {
747 DCHECK(cached.proof_valid());
749 if (!server_info_) {
750 return;
753 QuicServerInfo::State* state = server_info_->mutable_state();
755 state->server_config = cached.server_config();
756 state->source_address_token = cached.source_address_token();
757 state->server_config_sig = cached.signature();
758 state->certs = cached.certs();
760 server_info_->Persist();
763 void QuicClientSession::OnProofVerifyDetailsAvailable(
764 const ProofVerifyDetails& verify_details) {
765 const ProofVerifyDetailsChromium* verify_details_chromium =
766 reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
767 CertVerifyResult* result_copy = new CertVerifyResult;
768 result_copy->CopyFrom(verify_details_chromium->cert_verify_result);
769 cert_verify_result_.reset(result_copy);
770 pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
771 logger_->OnCertificateVerified(*cert_verify_result_);
774 void QuicClientSession::StartReading() {
775 packet_reader_.StartReading();
778 void QuicClientSession::CloseSessionOnError(int error,
779 QuicErrorCode quic_error) {
780 RecordAndCloseSessionOnError(error, quic_error);
781 NotifyFactoryOfSessionClosed();
784 void QuicClientSession::CloseSessionOnErrorAndNotifyFactoryLater(
785 int error,
786 QuicErrorCode quic_error) {
787 RecordAndCloseSessionOnError(error, quic_error);
788 NotifyFactoryOfSessionClosedLater();
791 void QuicClientSession::RecordAndCloseSessionOnError(int error,
792 QuicErrorCode quic_error) {
793 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
794 CloseSessionOnErrorInner(error, quic_error);
797 void QuicClientSession::CloseSessionOnErrorInner(int net_error,
798 QuicErrorCode quic_error) {
799 if (!callback_.is_null()) {
800 base::ResetAndReturn(&callback_).Run(net_error);
802 CloseAllStreams(net_error);
803 CloseAllObservers(net_error);
804 net_log_.AddEvent(
805 NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
806 NetLog::IntegerCallback("net_error", net_error));
808 if (connection()->connected())
809 connection()->CloseConnection(quic_error, false);
810 DCHECK(!connection()->connected());
813 void QuicClientSession::CloseAllStreams(int net_error) {
814 while (!streams()->empty()) {
815 ReliableQuicStream* stream = streams()->begin()->second;
816 QuicStreamId id = stream->id();
817 static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
818 CloseStream(id);
822 void QuicClientSession::CloseAllObservers(int net_error) {
823 while (!observers_.empty()) {
824 Observer* observer = *observers_.begin();
825 observers_.erase(observer);
826 observer->OnSessionClosed(net_error);
830 scoped_ptr<base::Value> QuicClientSession::GetInfoAsValue(
831 const std::set<HostPortPair>& aliases) {
832 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
833 dict->SetString("version", QuicVersionToString(connection()->version()));
834 dict->SetInteger("open_streams", GetNumOpenStreams());
835 scoped_ptr<base::ListValue> stream_list(new base::ListValue());
836 for (base::hash_map<QuicStreamId, QuicDataStream*>::const_iterator it
837 = streams()->begin();
838 it != streams()->end();
839 ++it) {
840 stream_list->Append(new base::StringValue(
841 base::Uint64ToString(it->second->id())));
843 dict->Set("active_streams", stream_list.Pass());
845 dict->SetInteger("total_streams", num_total_streams_);
846 dict->SetString("peer_address", peer_address().ToString());
847 dict->SetString("connection_id", base::Uint64ToString(connection_id()));
848 dict->SetBoolean("connected", connection()->connected());
849 const QuicConnectionStats& stats = connection()->GetStats();
850 dict->SetInteger("packets_sent", stats.packets_sent);
851 dict->SetInteger("packets_received", stats.packets_received);
852 dict->SetInteger("packets_lost", stats.packets_lost);
853 SSLInfo ssl_info;
854 dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
856 scoped_ptr<base::ListValue> alias_list(new base::ListValue());
857 for (std::set<HostPortPair>::const_iterator it = aliases.begin();
858 it != aliases.end(); it++) {
859 alias_list->Append(new base::StringValue(it->ToString()));
861 dict->Set("aliases", alias_list.Pass());
863 return dict.Pass();
866 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
867 return weak_factory_.GetWeakPtr();
870 void QuicClientSession::OnReadError(int result) {
871 DVLOG(1) << "Closing session on read error: " << result;
872 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
873 NotifyFactoryOfSessionGoingAway();
874 CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
875 NotifyFactoryOfSessionClosedLater();
878 bool QuicClientSession::OnPacket(const QuicEncryptedPacket& packet,
879 IPEndPoint local_address,
880 IPEndPoint peer_address) {
881 connection()->ProcessUdpPacket(local_address, peer_address, packet);
882 if (!connection()->connected()) {
883 NotifyFactoryOfSessionClosedLater();
884 return false;
886 return true;
889 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
890 going_away_ = true;
891 if (stream_factory_)
892 stream_factory_->OnSessionGoingAway(this);
895 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
896 if (!streams()->empty())
897 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
899 if (!going_away_)
900 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
902 going_away_ = true;
903 DCHECK_EQ(0u, GetNumOpenStreams());
904 DCHECK(!connection()->connected());
905 base::ThreadTaskRunnerHandle::Get()->PostTask(
906 FROM_HERE, base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
907 weak_factory_.GetWeakPtr()));
910 void QuicClientSession::NotifyFactoryOfSessionClosed() {
911 if (!streams()->empty())
912 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
914 if (!going_away_)
915 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
917 going_away_ = true;
918 DCHECK_EQ(0u, GetNumOpenStreams());
919 // Will delete |this|.
920 if (stream_factory_)
921 stream_factory_->OnSessionClosed(this);
924 void QuicClientSession::OnConnectTimeout() {
925 DCHECK(callback_.is_null());
926 DCHECK(IsEncryptionEstablished());
928 if (IsCryptoHandshakeConfirmed())
929 return;
931 // TODO(rch): re-enable this code once beta is cut.
932 // if (stream_factory_)
933 // stream_factory_->OnSessionConnectTimeout(this);
934 // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
935 // DCHECK_EQ(0u, GetNumOpenStreams());
938 } // namespace net