Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / net / quic / quic_chromium_client_session.cc
blob0e7cb7b2debfa3fb6c163c6e23da05be8ee73fe9
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_chromium_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", reason,
83 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 QuicChromiumClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
121 QuicChromiumClientSession::StreamRequest::~StreamRequest() {
122 CancelRequest();
125 int QuicChromiumClientSession::StreamRequest::StartRequest(
126 const base::WeakPtr<QuicChromiumClientSession>& 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 QuicChromiumClientSession::StreamRequest::CancelRequest() {
140 if (session_)
141 session_->CancelRequest(this);
142 session_.reset();
143 callback_.Reset();
146 void QuicChromiumClientSession::StreamRequest::OnRequestCompleteSuccess(
147 QuicReliableClientStream* stream) {
148 session_.reset();
149 *stream_ = stream;
150 ResetAndReturn(&callback_).Run(OK);
153 void QuicChromiumClientSession::StreamRequest::OnRequestCompleteFailure(
154 int rv) {
155 session_.reset();
156 ResetAndReturn(&callback_).Run(rv);
159 QuicChromiumClientSession::QuicChromiumClientSession(
160 QuicConnection* connection,
161 scoped_ptr<DatagramClientSocket> socket,
162 QuicStreamFactory* stream_factory,
163 QuicCryptoClientStreamFactory* crypto_client_stream_factory,
164 TransportSecurityState* transport_security_state,
165 scoped_ptr<QuicServerInfo> server_info,
166 const QuicServerId& server_id,
167 int cert_verify_flags,
168 const QuicConfig& config,
169 QuicCryptoClientConfig* crypto_config,
170 const char* const connection_description,
171 base::TimeTicks dns_resolution_end_time,
172 base::TaskRunner* task_runner,
173 NetLog* net_log)
174 : QuicClientSessionBase(connection, config),
175 server_id_(server_id),
176 require_confirmation_(false),
177 stream_factory_(stream_factory),
178 socket_(socket.Pass()),
179 transport_security_state_(transport_security_state),
180 server_info_(server_info.Pass()),
181 num_total_streams_(0),
182 task_runner_(task_runner),
183 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
184 packet_reader_(socket_.get(), this, net_log_),
185 dns_resolution_end_time_(dns_resolution_end_time),
186 logger_(new QuicConnectionLogger(this, connection_description, net_log_)),
187 going_away_(false),
188 disabled_reason_(QUIC_DISABLED_NOT),
189 weak_factory_(this) {
190 crypto_stream_.reset(
191 crypto_client_stream_factory
192 ? crypto_client_stream_factory->CreateQuicCryptoClientStream(
193 server_id, this, crypto_config)
194 : new QuicCryptoClientStream(
195 server_id, this,
196 new ProofVerifyContextChromium(cert_verify_flags, net_log_),
197 crypto_config));
198 connection->set_debug_visitor(logger_.get());
199 net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION,
200 base::Bind(NetLogQuicClientSessionCallback, &server_id,
201 cert_verify_flags, require_confirmation_));
202 IPEndPoint address;
203 if (socket && socket->GetLocalAddress(&address) == OK &&
204 address.GetFamily() == ADDRESS_FAMILY_IPV6) {
205 connection->set_max_packet_length(connection->max_packet_length() -
206 kAdditionalOverheadForIPv6);
210 QuicChromiumClientSession::~QuicChromiumClientSession() {
211 if (!dynamic_streams().empty())
212 RecordUnexpectedOpenStreams(DESTRUCTOR);
213 if (!observers_.empty())
214 RecordUnexpectedObservers(DESTRUCTOR);
215 if (!going_away_)
216 RecordUnexpectedNotGoingAway(DESTRUCTOR);
218 while (!dynamic_streams().empty() || !observers_.empty() ||
219 !stream_requests_.empty()) {
220 // The session must be closed before it is destroyed.
221 DCHECK(dynamic_streams().empty());
222 CloseAllStreams(ERR_UNEXPECTED);
223 DCHECK(observers_.empty());
224 CloseAllObservers(ERR_UNEXPECTED);
226 connection()->set_debug_visitor(nullptr);
227 net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
229 while (!stream_requests_.empty()) {
230 StreamRequest* request = stream_requests_.front();
231 stream_requests_.pop_front();
232 request->OnRequestCompleteFailure(ERR_ABORTED);
236 if (connection()->connected()) {
237 // Ensure that the connection is closed by the time the session is
238 // destroyed.
239 connection()->CloseConnection(QUIC_INTERNAL_ERROR, false);
242 if (IsEncryptionEstablished())
243 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
244 if (IsCryptoHandshakeConfirmed())
245 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
246 else
247 RecordHandshakeState(STATE_FAILED);
249 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
250 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
251 crypto_stream_->num_sent_client_hellos());
252 if (!IsCryptoHandshakeConfirmed())
253 return;
255 // Sending one client_hello means we had zero handshake-round-trips.
256 int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
258 // Don't bother with these histogram during tests, which mock out
259 // num_sent_client_hellos().
260 if (round_trip_handshakes < 0 || !stream_factory_)
261 return;
263 bool port_selected = stream_factory_->enable_port_selection();
264 SSLInfo ssl_info;
265 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
266 if (port_selected) {
267 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
268 round_trip_handshakes, 0, 3, 4);
269 } else {
270 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
271 round_trip_handshakes, 0, 3, 4);
272 if (require_confirmation_) {
273 UMA_HISTOGRAM_CUSTOM_COUNTS(
274 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
275 round_trip_handshakes, 0, 3, 4);
278 } else {
279 if (port_selected) {
280 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
281 round_trip_handshakes, 0, 3, 4);
282 } else {
283 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
284 round_trip_handshakes, 0, 3, 4);
285 if (require_confirmation_) {
286 UMA_HISTOGRAM_CUSTOM_COUNTS(
287 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
288 round_trip_handshakes, 0, 3, 4);
292 const QuicConnectionStats stats = connection()->GetStats();
293 if (server_info_ && stats.min_rtt_us > 0) {
294 base::TimeTicks wait_for_data_start_time =
295 server_info_->wait_for_data_start_time();
296 base::TimeTicks wait_for_data_end_time =
297 server_info_->wait_for_data_end_time();
298 if (!wait_for_data_start_time.is_null() &&
299 !wait_for_data_end_time.is_null()) {
300 base::TimeDelta wait_time =
301 wait_for_data_end_time - wait_for_data_start_time;
302 const base::HistogramBase::Sample kMaxWaitToRtt = 1000;
303 base::HistogramBase::Sample wait_to_rtt =
304 static_cast<base::HistogramBase::Sample>(
305 100 * wait_time.InMicroseconds() / stats.min_rtt_us);
306 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicServerInfo.WaitForDataReadyToRtt",
307 wait_to_rtt, 0, kMaxWaitToRtt, 50);
311 // The MTU used by QUIC is limited to a fairly small set of predefined values
312 // (initial values and MTU discovery values), but does not fare well when
313 // bucketed. Because of that, a sparse histogram is used here.
314 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ClientSideMtu",
315 connection()->max_packet_length());
316 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ServerSideMtu",
317 stats.max_received_packet_size);
319 UMA_HISTOGRAM_COUNTS("Net.QuicSession.MtuProbesSent",
320 connection()->mtu_probe_count());
322 if (stats.max_sequence_reordering == 0)
323 return;
324 const base::HistogramBase::Sample kMaxReordering = 100;
325 base::HistogramBase::Sample reordering = kMaxReordering;
326 if (stats.min_rtt_us > 0) {
327 reordering = static_cast<base::HistogramBase::Sample>(
328 100 * stats.max_time_reordering_us / stats.min_rtt_us);
330 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime", reordering,
331 0, kMaxReordering, 50);
332 if (stats.min_rtt_us > 100 * 1000) {
333 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
334 reordering, 0, kMaxReordering, 50);
336 UMA_HISTOGRAM_COUNTS(
337 "Net.QuicSession.MaxReordering",
338 static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
341 void QuicChromiumClientSession::OnStreamFrame(const QuicStreamFrame& frame) {
342 // Record total number of stream frames.
343 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", 1);
345 // Record number of frames per stream in packet.
346 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket", 1);
348 return QuicSpdySession::OnStreamFrame(frame);
351 void QuicChromiumClientSession::AddObserver(Observer* observer) {
352 if (going_away_) {
353 RecordUnexpectedObservers(ADD_OBSERVER);
354 observer->OnSessionClosed(ERR_UNEXPECTED);
355 return;
358 DCHECK(!ContainsKey(observers_, observer));
359 observers_.insert(observer);
362 void QuicChromiumClientSession::RemoveObserver(Observer* observer) {
363 DCHECK(ContainsKey(observers_, observer));
364 observers_.erase(observer);
367 int QuicChromiumClientSession::TryCreateStream(
368 StreamRequest* request,
369 QuicReliableClientStream** stream) {
370 if (!crypto_stream_->encryption_established()) {
371 DLOG(DFATAL) << "Encryption not established.";
372 return ERR_CONNECTION_CLOSED;
375 if (goaway_received()) {
376 DVLOG(1) << "Going away.";
377 return ERR_CONNECTION_CLOSED;
380 if (!connection()->connected()) {
381 DVLOG(1) << "Already closed.";
382 return ERR_CONNECTION_CLOSED;
385 if (going_away_) {
386 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
387 return ERR_CONNECTION_CLOSED;
390 if (GetNumOpenStreams() < get_max_open_streams()) {
391 *stream = CreateOutgoingReliableStreamImpl();
392 return OK;
395 stream_requests_.push_back(request);
396 return ERR_IO_PENDING;
399 void QuicChromiumClientSession::CancelRequest(StreamRequest* request) {
400 // Remove |request| from the queue while preserving the order of the
401 // other elements.
402 StreamRequestQueue::iterator it =
403 std::find(stream_requests_.begin(), stream_requests_.end(), request);
404 if (it != stream_requests_.end()) {
405 it = stream_requests_.erase(it);
409 QuicReliableClientStream*
410 QuicChromiumClientSession::CreateOutgoingDynamicStream() {
411 if (!crypto_stream_->encryption_established()) {
412 DVLOG(1) << "Encryption not active so no outgoing stream created.";
413 return nullptr;
415 if (GetNumOpenStreams() >= get_max_open_streams()) {
416 DVLOG(1) << "Failed to create a new outgoing stream. "
417 << "Already " << GetNumOpenStreams() << " open.";
418 return nullptr;
420 if (goaway_received()) {
421 DVLOG(1) << "Failed to create a new outgoing stream. "
422 << "Already received goaway.";
423 return nullptr;
425 if (going_away_) {
426 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
427 return nullptr;
429 return CreateOutgoingReliableStreamImpl();
432 QuicReliableClientStream*
433 QuicChromiumClientSession::CreateOutgoingReliableStreamImpl() {
434 DCHECK(connection()->connected());
435 QuicReliableClientStream* stream =
436 new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
437 ActivateStream(stream);
438 ++num_total_streams_;
439 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
440 // The previous histogram puts 100 in a bucket betweeen 86-113 which does
441 // not shed light on if chrome ever things it has more than 100 streams open.
442 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.TooManyOpenStreams",
443 GetNumOpenStreams() > 100);
444 return stream;
447 QuicCryptoClientStream* QuicChromiumClientSession::GetCryptoStream() {
448 return crypto_stream_.get();
451 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
452 // we learn about SSL info (sync vs async vs cached).
453 bool QuicChromiumClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
454 ssl_info->Reset();
455 if (!cert_verify_result_) {
456 return false;
459 ssl_info->cert_status = cert_verify_result_->cert_status;
460 ssl_info->cert = cert_verify_result_->verified_cert;
462 // TODO(wtc): Define QUIC "cipher suites".
463 // Report the TLS cipher suite that most closely resembles the crypto
464 // parameters of the QUIC connection.
465 QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
466 uint16 cipher_suite;
467 int security_bits;
468 switch (aead) {
469 case kAESG:
470 cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
471 security_bits = 128;
472 break;
473 case kCC12:
474 cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
475 security_bits = 256;
476 break;
477 default:
478 NOTREACHED();
479 return false;
481 int ssl_connection_status = 0;
482 ssl_connection_status |= cipher_suite;
483 ssl_connection_status |=
484 (SSL_CONNECTION_VERSION_QUIC & SSL_CONNECTION_VERSION_MASK)
485 << SSL_CONNECTION_VERSION_SHIFT;
487 ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
488 ssl_info->is_issued_by_known_root =
489 cert_verify_result_->is_issued_by_known_root;
491 ssl_info->connection_status = ssl_connection_status;
492 ssl_info->client_cert_sent = false;
493 ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent();
494 ssl_info->security_bits = security_bits;
495 ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
496 ssl_info->pinning_failure_log = pinning_failure_log_;
497 return true;
500 int QuicChromiumClientSession::CryptoConnect(
501 bool require_confirmation,
502 const CompletionCallback& callback) {
503 require_confirmation_ = require_confirmation;
504 handshake_start_ = base::TimeTicks::Now();
505 RecordHandshakeState(STATE_STARTED);
506 DCHECK(flow_controller());
507 crypto_stream_->CryptoConnect();
509 if (IsCryptoHandshakeConfirmed())
510 return OK;
512 // Unless we require handshake confirmation, activate the session if
513 // we have established initial encryption.
514 if (!require_confirmation_ && IsEncryptionEstablished()) {
515 // To mitigate the effects of hanging 0-RTT connections, set up a timer to
516 // cancel any requests, if the handshake takes too long.
517 task_runner_->PostDelayedTask(
518 FROM_HERE, base::Bind(&QuicChromiumClientSession::OnConnectTimeout,
519 weak_factory_.GetWeakPtr()),
520 base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs));
521 return OK;
524 callback_ = callback;
525 return ERR_IO_PENDING;
528 int QuicChromiumClientSession::ResumeCryptoConnect(
529 const CompletionCallback& callback) {
530 if (IsCryptoHandshakeConfirmed())
531 return OK;
533 if (!connection()->connected())
534 return ERR_QUIC_HANDSHAKE_FAILED;
536 callback_ = callback;
537 return ERR_IO_PENDING;
540 int QuicChromiumClientSession::GetNumSentClientHellos() const {
541 return crypto_stream_->num_sent_client_hellos();
544 bool QuicChromiumClientSession::CanPool(const std::string& hostname,
545 PrivacyMode privacy_mode) const {
546 DCHECK(connection()->connected());
547 if (privacy_mode != server_id_.privacy_mode()) {
548 // Privacy mode must always match.
549 return false;
551 SSLInfo ssl_info;
552 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
553 // We can always pool with insecure QUIC sessions.
554 return true;
557 return SpdySession::CanPool(transport_security_state_, ssl_info,
558 server_id_.host(), hostname);
561 QuicDataStream* QuicChromiumClientSession::CreateIncomingDynamicStream(
562 QuicStreamId id) {
563 DLOG(ERROR) << "Server push not supported";
564 return nullptr;
567 void QuicChromiumClientSession::CloseStream(QuicStreamId stream_id) {
568 ReliableQuicStream* stream = GetStream(stream_id);
569 if (stream) {
570 logger_->UpdateReceivedFrameCounts(stream_id, stream->num_frames_received(),
571 stream->num_duplicate_frames_received());
573 QuicSpdySession::CloseStream(stream_id);
574 OnClosedStream();
577 void QuicChromiumClientSession::SendRstStream(QuicStreamId id,
578 QuicRstStreamErrorCode error,
579 QuicStreamOffset bytes_written) {
580 QuicSpdySession::SendRstStream(id, error, bytes_written);
581 OnClosedStream();
584 void QuicChromiumClientSession::OnClosedStream() {
585 if (GetNumOpenStreams() < get_max_open_streams() &&
586 !stream_requests_.empty() && crypto_stream_->encryption_established() &&
587 !goaway_received() && !going_away_ && 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 QuicChromiumClientSession::OnCryptoHandshakeEvent(
599 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_ || event == HANDSHAKE_CONFIRMED ||
608 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 QuicSpdySession::OnCryptoHandshakeEvent(event);
652 void QuicChromiumClientSession::OnCryptoHandshakeMessageSent(
653 const CryptoHandshakeMessage& message) {
654 logger_->OnCryptoHandshakeMessageSent(message);
657 void QuicChromiumClientSession::OnCryptoHandshakeMessageReceived(
658 const CryptoHandshakeMessage& message) {
659 logger_->OnCryptoHandshakeMessageReceived(message);
662 void QuicChromiumClientSession::OnConnectionClosed(QuicErrorCode error,
663 bool from_peer) {
664 DCHECK(!connection()->connected());
665 logger_->OnConnectionClosed(error, from_peer);
666 if (from_peer) {
667 if (IsCryptoHandshakeConfirmed()) {
668 UMA_HISTOGRAM_SPARSE_SLOWLY(
669 "Net.QuicSession.ConnectionCloseErrorCodeServer.HandshakeConfirmed",
670 error);
672 UMA_HISTOGRAM_SPARSE_SLOWLY(
673 "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
674 } else {
675 if (IsCryptoHandshakeConfirmed()) {
676 UMA_HISTOGRAM_SPARSE_SLOWLY(
677 "Net.QuicSession.ConnectionCloseErrorCodeClient.HandshakeConfirmed",
678 error);
680 UMA_HISTOGRAM_SPARSE_SLOWLY(
681 "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
684 if (error == QUIC_CONNECTION_TIMED_OUT) {
685 UMA_HISTOGRAM_COUNTS(
686 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
687 GetNumOpenStreams());
688 if (IsCryptoHandshakeConfirmed()) {
689 if (GetNumOpenStreams() > 0) {
690 disabled_reason_ = QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS;
691 UMA_HISTOGRAM_BOOLEAN(
692 "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
693 connection()->sent_packet_manager().HasUnackedPackets());
694 UMA_HISTOGRAM_COUNTS(
695 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
696 connection()->sent_packet_manager().consecutive_rto_count());
697 UMA_HISTOGRAM_COUNTS(
698 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
699 connection()->sent_packet_manager().consecutive_tlp_count());
701 if (connection()->sent_packet_manager().HasUnackedPackets()) {
702 UMA_HISTOGRAM_TIMES(
703 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
704 "TimeSinceLastReceived.UnackedPackets",
705 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
706 } else {
707 UMA_HISTOGRAM_TIMES(
708 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
709 "TimeSinceLastReceived.NoUnackedPackets",
710 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
713 } else {
714 UMA_HISTOGRAM_COUNTS(
715 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
716 GetNumOpenStreams());
717 UMA_HISTOGRAM_COUNTS(
718 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
719 num_total_streams_);
723 if (!IsCryptoHandshakeConfirmed()) {
724 if (error == QUIC_PUBLIC_RESET) {
725 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
726 } else if (connection()->GetStats().packets_received == 0) {
727 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
728 UMA_HISTOGRAM_SPARSE_SLOWLY(
729 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
730 error);
731 } else {
732 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
733 UMA_HISTOGRAM_SPARSE_SLOWLY(
734 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
735 error);
737 } else if (error == QUIC_PUBLIC_RESET) {
738 disabled_reason_ = QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE;
741 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
742 connection()->version());
743 NotifyFactoryOfSessionGoingAway();
744 if (!callback_.is_null()) {
745 base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
747 socket_->Close();
748 QuicSession::OnConnectionClosed(error, from_peer);
749 DCHECK(dynamic_streams().empty());
750 CloseAllStreams(ERR_UNEXPECTED);
751 CloseAllObservers(ERR_UNEXPECTED);
752 NotifyFactoryOfSessionClosedLater();
755 void QuicChromiumClientSession::OnSuccessfulVersionNegotiation(
756 const QuicVersion& version) {
757 logger_->OnSuccessfulVersionNegotiation(version);
758 QuicSpdySession::OnSuccessfulVersionNegotiation(version);
761 void QuicChromiumClientSession::OnProofValid(
762 const QuicCryptoClientConfig::CachedState& cached) {
763 DCHECK(cached.proof_valid());
765 if (!server_info_) {
766 return;
769 QuicServerInfo::State* state = server_info_->mutable_state();
771 state->server_config = cached.server_config();
772 state->source_address_token = cached.source_address_token();
773 state->server_config_sig = cached.signature();
774 state->certs = cached.certs();
776 server_info_->Persist();
779 void QuicChromiumClientSession::OnProofVerifyDetailsAvailable(
780 const ProofVerifyDetails& verify_details) {
781 const ProofVerifyDetailsChromium* verify_details_chromium =
782 reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
783 CertVerifyResult* result_copy = new CertVerifyResult;
784 result_copy->CopyFrom(verify_details_chromium->cert_verify_result);
785 cert_verify_result_.reset(result_copy);
786 pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
787 logger_->OnCertificateVerified(*cert_verify_result_);
790 void QuicChromiumClientSession::StartReading() {
791 packet_reader_.StartReading();
794 void QuicChromiumClientSession::CloseSessionOnError(int error,
795 QuicErrorCode quic_error) {
796 RecordAndCloseSessionOnError(error, quic_error);
797 NotifyFactoryOfSessionClosed();
800 void QuicChromiumClientSession::CloseSessionOnErrorAndNotifyFactoryLater(
801 int error,
802 QuicErrorCode quic_error) {
803 RecordAndCloseSessionOnError(error, quic_error);
804 NotifyFactoryOfSessionClosedLater();
807 void QuicChromiumClientSession::RecordAndCloseSessionOnError(
808 int error,
809 QuicErrorCode quic_error) {
810 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
811 CloseSessionOnErrorInner(error, quic_error);
814 void QuicChromiumClientSession::CloseSessionOnErrorInner(
815 int net_error,
816 QuicErrorCode quic_error) {
817 if (!callback_.is_null()) {
818 base::ResetAndReturn(&callback_).Run(net_error);
820 CloseAllStreams(net_error);
821 CloseAllObservers(net_error);
822 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
823 NetLog::IntegerCallback("net_error", net_error));
825 if (connection()->connected())
826 connection()->CloseConnection(quic_error, false);
827 DCHECK(!connection()->connected());
830 void QuicChromiumClientSession::CloseAllStreams(int net_error) {
831 while (!dynamic_streams().empty()) {
832 ReliableQuicStream* stream = dynamic_streams().begin()->second;
833 QuicStreamId id = stream->id();
834 static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
835 CloseStream(id);
839 void QuicChromiumClientSession::CloseAllObservers(int net_error) {
840 while (!observers_.empty()) {
841 Observer* observer = *observers_.begin();
842 observers_.erase(observer);
843 observer->OnSessionClosed(net_error);
847 scoped_ptr<base::Value> QuicChromiumClientSession::GetInfoAsValue(
848 const std::set<HostPortPair>& aliases) {
849 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
850 dict->SetString("version", QuicVersionToString(connection()->version()));
851 dict->SetInteger("open_streams", GetNumOpenStreams());
852 scoped_ptr<base::ListValue> stream_list(new base::ListValue());
853 for (base::hash_map<QuicStreamId, ReliableQuicStream*>::const_iterator it =
854 dynamic_streams().begin();
855 it != dynamic_streams().end(); ++it) {
856 stream_list->Append(
857 new base::StringValue(base::UintToString(it->second->id())));
859 dict->Set("active_streams", stream_list.Pass());
861 dict->SetInteger("total_streams", num_total_streams_);
862 dict->SetString("peer_address", peer_address().ToString());
863 dict->SetString("connection_id", base::Uint64ToString(connection_id()));
864 dict->SetBoolean("connected", connection()->connected());
865 const QuicConnectionStats& stats = connection()->GetStats();
866 dict->SetInteger("packets_sent", stats.packets_sent);
867 dict->SetInteger("packets_received", stats.packets_received);
868 dict->SetInteger("packets_lost", stats.packets_lost);
869 SSLInfo ssl_info;
870 dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
872 scoped_ptr<base::ListValue> alias_list(new base::ListValue());
873 for (std::set<HostPortPair>::const_iterator it = aliases.begin();
874 it != aliases.end(); it++) {
875 alias_list->Append(new base::StringValue(it->ToString()));
877 dict->Set("aliases", alias_list.Pass());
879 return dict.Pass();
882 base::WeakPtr<QuicChromiumClientSession>
883 QuicChromiumClientSession::GetWeakPtr() {
884 return weak_factory_.GetWeakPtr();
887 void QuicChromiumClientSession::OnReadError(int result) {
888 DVLOG(1) << "Closing session on read error: " << result;
889 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
890 NotifyFactoryOfSessionGoingAway();
891 CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
892 NotifyFactoryOfSessionClosedLater();
895 bool QuicChromiumClientSession::OnPacket(const QuicEncryptedPacket& packet,
896 IPEndPoint local_address,
897 IPEndPoint peer_address) {
898 connection()->ProcessUdpPacket(local_address, peer_address, packet);
899 if (!connection()->connected()) {
900 NotifyFactoryOfSessionClosedLater();
901 return false;
903 return true;
906 void QuicChromiumClientSession::NotifyFactoryOfSessionGoingAway() {
907 going_away_ = true;
908 if (stream_factory_)
909 stream_factory_->OnSessionGoingAway(this);
912 void QuicChromiumClientSession::NotifyFactoryOfSessionClosedLater() {
913 if (!dynamic_streams().empty())
914 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
916 if (!going_away_)
917 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
919 going_away_ = true;
920 DCHECK_EQ(0u, GetNumOpenStreams());
921 DCHECK(!connection()->connected());
922 base::ThreadTaskRunnerHandle::Get()->PostTask(
923 FROM_HERE,
924 base::Bind(&QuicChromiumClientSession::NotifyFactoryOfSessionClosed,
925 weak_factory_.GetWeakPtr()));
928 void QuicChromiumClientSession::NotifyFactoryOfSessionClosed() {
929 if (!dynamic_streams().empty())
930 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
932 if (!going_away_)
933 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
935 going_away_ = true;
936 DCHECK_EQ(0u, GetNumOpenStreams());
937 // Will delete |this|.
938 if (stream_factory_)
939 stream_factory_->OnSessionClosed(this);
942 void QuicChromiumClientSession::OnConnectTimeout() {
943 DCHECK(callback_.is_null());
944 DCHECK(IsEncryptionEstablished());
946 if (IsCryptoHandshakeConfirmed())
947 return;
949 // TODO(rch): re-enable this code once beta is cut.
950 // if (stream_factory_)
951 // stream_factory_->OnSessionConnectTimeout(this);
952 // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
953 // DCHECK_EQ(0u, GetNumOpenStreams());
956 } // namespace net