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