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"
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
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,
56 void RecordUnexpectedOpenStreams(Location location
) {
57 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location
,
61 void RecordUnexpectedObservers(Location location
) {
62 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location
,
66 void RecordUnexpectedNotGoingAway(Location location
) {
67 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location
,
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
90 STATE_ENCRYPTION_ESTABLISHED
= 1,
91 STATE_HANDSHAKE_CONFIRMED
= 2,
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
);
119 QuicChromiumClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
121 QuicChromiumClientSession::StreamRequest::~StreamRequest() {
125 int QuicChromiumClientSession::StreamRequest::StartRequest(
126 const base::WeakPtr
<QuicChromiumClientSession
>& session
,
127 QuicReliableClientStream
** stream
,
128 const CompletionCallback
& callback
) {
131 int rv
= session_
->TryCreateStream(this, stream_
);
132 if (rv
== ERR_IO_PENDING
) {
133 callback_
= callback
;
139 void QuicChromiumClientSession::StreamRequest::CancelRequest() {
141 session_
->CancelRequest(this);
146 void QuicChromiumClientSession::StreamRequest::OnRequestCompleteSuccess(
147 QuicReliableClientStream
* stream
) {
150 ResetAndReturn(&callback_
).Run(OK
);
153 void QuicChromiumClientSession::StreamRequest::OnRequestCompleteFailure(
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
,
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_
)),
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(
196 new ProofVerifyContextChromium(cert_verify_flags
, net_log_
),
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_
));
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
);
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
239 connection()->CloseConnection(QUIC_INTERNAL_ERROR
, false);
242 if (IsEncryptionEstablished())
243 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED
);
244 if (IsCryptoHandshakeConfirmed())
245 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED
);
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())
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_
)
263 bool port_selected
= stream_factory_
->enable_port_selection();
265 if (!GetSSLInfo(&ssl_info
) || !ssl_info
.cert
.get()) {
267 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
268 round_trip_handshakes
, 0, 3, 4);
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);
280 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
281 round_trip_handshakes
, 0, 3, 4);
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)
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
) {
353 RecordUnexpectedObservers(ADD_OBSERVER
);
354 observer
->OnSessionClosed(ERR_UNEXPECTED
);
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
;
386 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM
);
387 return ERR_CONNECTION_CLOSED
;
390 if (GetNumOpenStreams() < get_max_open_streams()) {
391 *stream
= CreateOutgoingReliableStreamImpl();
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
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.";
415 if (GetNumOpenStreams() >= get_max_open_streams()) {
416 DVLOG(1) << "Failed to create a new outgoing stream. "
417 << "Already " << GetNumOpenStreams() << " open.";
420 if (goaway_received()) {
421 DVLOG(1) << "Failed to create a new outgoing stream. "
422 << "Already received goaway.";
426 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM
);
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);
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 {
455 if (!cert_verify_result_
) {
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
;
470 cipher_suite
= 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
474 cipher_suite
= 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
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_
;
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())
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
));
524 callback_
= callback
;
525 return ERR_IO_PENDING
;
528 int QuicChromiumClientSession::ResumeCryptoConnect(
529 const CompletionCallback
& callback
) {
530 if (IsCryptoHandshakeConfirmed())
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.
552 if (!GetSSLInfo(&ssl_info
) || !ssl_info
.cert
.get()) {
553 // We can always pool with insecure QUIC sessions.
557 return SpdySession::CanPool(transport_security_state_
, ssl_info
,
558 server_id_
.host(), hostname
);
561 QuicDataStream
* QuicChromiumClientSession::CreateIncomingDynamicStream(
563 DLOG(ERROR
) << "Server push not supported";
567 void QuicChromiumClientSession::CloseStream(QuicStreamId stream_id
) {
568 ReliableQuicStream
* stream
= GetStream(stream_id
);
570 logger_
->UpdateReceivedFrameCounts(stream_id
, stream
->num_frames_received(),
571 stream
->num_duplicate_frames_received());
573 QuicSpdySession::CloseStream(stream_id
);
577 void QuicChromiumClientSession::SendRstStream(QuicStreamId id
,
578 QuicRstStreamErrorCode error
,
579 QuicStreamOffset bytes_written
) {
580 QuicSpdySession::SendRstStream(id
, error
, bytes_written
);
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()))) {
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_
);
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()) {
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()) {
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
;
644 observer
->OnCryptoHandshakeConfirmed();
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
,
664 DCHECK(!connection()->connected());
665 logger_
->OnConnectionClosed(error
, from_peer
);
667 if (IsCryptoHandshakeConfirmed()) {
668 UMA_HISTOGRAM_SPARSE_SLOWLY(
669 "Net.QuicSession.ConnectionCloseErrorCodeServer.HandshakeConfirmed",
672 UMA_HISTOGRAM_SPARSE_SLOWLY(
673 "Net.QuicSession.ConnectionCloseErrorCodeServer", error
);
675 if (IsCryptoHandshakeConfirmed()) {
676 UMA_HISTOGRAM_SPARSE_SLOWLY(
677 "Net.QuicSession.ConnectionCloseErrorCodeClient.HandshakeConfirmed",
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()) {
703 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
704 "TimeSinceLastReceived.UnackedPackets",
705 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
708 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
709 "TimeSinceLastReceived.NoUnackedPackets",
710 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
714 UMA_HISTOGRAM_COUNTS(
715 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
716 GetNumOpenStreams());
717 UMA_HISTOGRAM_COUNTS(
718 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
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",
732 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN
);
733 UMA_HISTOGRAM_SPARSE_SLOWLY(
734 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
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
);
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());
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(
802 QuicErrorCode quic_error
) {
803 RecordAndCloseSessionOnError(error
, quic_error
);
804 NotifyFactoryOfSessionClosedLater();
807 void QuicChromiumClientSession::RecordAndCloseSessionOnError(
809 QuicErrorCode quic_error
) {
810 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error
);
811 CloseSessionOnErrorInner(error
, quic_error
);
814 void QuicChromiumClientSession::CloseSessionOnErrorInner(
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
);
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
) {
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
);
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());
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();
906 void QuicChromiumClientSession::NotifyFactoryOfSessionGoingAway() {
909 stream_factory_
->OnSessionGoingAway(this);
912 void QuicChromiumClientSession::NotifyFactoryOfSessionClosedLater() {
913 if (!dynamic_streams().empty())
914 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER
);
917 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER
);
920 DCHECK_EQ(0u, GetNumOpenStreams());
921 DCHECK(!connection()->connected());
922 base::ThreadTaskRunnerHandle::Get()->PostTask(
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
);
933 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED
);
936 DCHECK_EQ(0u, GetNumOpenStreams());
937 // Will delete |this|.
939 stream_factory_
->OnSessionClosed(this);
942 void QuicChromiumClientSession::OnConnectTimeout() {
943 DCHECK(callback_
.is_null());
944 DCHECK(IsEncryptionEstablished());
946 if (IsCryptoHandshakeConfirmed())
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());