1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/quic/quic_client_session.h"
7 #include "base/callback_helpers.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/metrics/histogram.h"
10 #include "base/metrics/sparse_histogram.h"
11 #include "base/profiler/scoped_tracker.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/values.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/network_activity_monitor.h"
18 #include "net/http/transport_security_state.h"
19 #include "net/quic/crypto/proof_verifier_chromium.h"
20 #include "net/quic/crypto/quic_server_info.h"
21 #include "net/quic/quic_connection_helper.h"
22 #include "net/quic/quic_crypto_client_stream_factory.h"
23 #include "net/quic/quic_server_id.h"
24 #include "net/quic/quic_stream_factory.h"
25 #include "net/spdy/spdy_session.h"
26 #include "net/ssl/channel_id_service.h"
27 #include "net/ssl/ssl_connection_status_flags.h"
28 #include "net/ssl/ssl_info.h"
29 #include "net/udp/datagram_client_socket.h"
35 // The length of time to wait for a 0-RTT handshake to complete
36 // before allowing the requests to possibly proceed over TCP.
37 const int k0RttHandshakeTimeoutMs
= 300;
39 // IPv6 packets have an additional 20 bytes of overhead than IPv4 packets.
40 const size_t kAdditionalOverheadForIPv6
= 20;
42 // Histograms for tracking down the crashes from http://crbug.com/354669
43 // Note: these values must be kept in sync with the corresponding values in:
44 // tools/metrics/histograms/histograms.xml
48 TRY_CREATE_STREAM
= 2,
49 CREATE_OUTGOING_RELIABLE_STREAM
= 3,
50 NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER
= 4,
51 NOTIFY_FACTORY_OF_SESSION_CLOSED
= 5,
55 void RecordUnexpectedOpenStreams(Location location
) {
56 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location
,
60 void RecordUnexpectedObservers(Location location
) {
61 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location
,
65 void RecordUnexpectedNotGoingAway(Location location
) {
66 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location
,
70 // Histogram for recording the different reasons that a QUIC session is unable
71 // to complete the handshake.
72 enum HandshakeFailureReason
{
73 HANDSHAKE_FAILURE_UNKNOWN
= 0,
74 HANDSHAKE_FAILURE_BLACK_HOLE
= 1,
75 HANDSHAKE_FAILURE_PUBLIC_RESET
= 2,
76 NUM_HANDSHAKE_FAILURE_REASONS
= 3,
79 void RecordHandshakeFailureReason(HandshakeFailureReason reason
) {
80 UMA_HISTOGRAM_ENUMERATION(
81 "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason",
82 reason
, NUM_HANDSHAKE_FAILURE_REASONS
);
85 // Note: these values must be kept in sync with the corresponding values in:
86 // tools/metrics/histograms/histograms.xml
89 STATE_ENCRYPTION_ESTABLISHED
= 1,
90 STATE_HANDSHAKE_CONFIRMED
= 2,
92 NUM_HANDSHAKE_STATES
= 4
95 void RecordHandshakeState(HandshakeState state
) {
96 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state
,
97 NUM_HANDSHAKE_STATES
);
100 base::Value
* NetLogQuicClientSessionCallback(
101 const QuicServerId
* server_id
,
102 bool require_confirmation
,
103 NetLog::LogLevel
/* log_level */) {
104 base::DictionaryValue
* dict
= new base::DictionaryValue();
105 dict
->SetString("host", server_id
->host());
106 dict
->SetInteger("port", server_id
->port());
107 dict
->SetBoolean("is_https", server_id
->is_https());
108 dict
->SetBoolean("privacy_mode",
109 server_id
->privacy_mode() == PRIVACY_MODE_ENABLED
);
110 dict
->SetBoolean("require_confirmation", require_confirmation
);
116 QuicClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
118 QuicClientSession::StreamRequest::~StreamRequest() {
122 int QuicClientSession::StreamRequest::StartRequest(
123 const base::WeakPtr
<QuicClientSession
>& session
,
124 QuicReliableClientStream
** stream
,
125 const CompletionCallback
& callback
) {
128 int rv
= session_
->TryCreateStream(this, stream_
);
129 if (rv
== ERR_IO_PENDING
) {
130 callback_
= callback
;
136 void QuicClientSession::StreamRequest::CancelRequest() {
138 session_
->CancelRequest(this);
143 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
144 QuicReliableClientStream
* stream
) {
147 ResetAndReturn(&callback_
).Run(OK
);
150 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv
) {
152 ResetAndReturn(&callback_
).Run(rv
);
155 QuicClientSession::QuicClientSession(
156 QuicConnection
* connection
,
157 scoped_ptr
<DatagramClientSocket
> socket
,
158 QuicStreamFactory
* stream_factory
,
159 TransportSecurityState
* transport_security_state
,
160 scoped_ptr
<QuicServerInfo
> server_info
,
161 const QuicConfig
& config
,
162 const char* const connection_description
,
163 base::TimeTicks dns_resolution_end_time
,
164 base::TaskRunner
* task_runner
,
166 : QuicClientSessionBase(connection
, config
),
167 require_confirmation_(false),
168 stream_factory_(stream_factory
),
169 socket_(socket
.Pass()),
170 read_buffer_(new IOBufferWithSize(kMaxPacketSize
)),
171 transport_security_state_(transport_security_state
),
172 server_info_(server_info
.Pass()),
173 read_pending_(false),
174 num_total_streams_(0),
175 task_runner_(task_runner
),
176 net_log_(BoundNetLog::Make(net_log
, NetLog::SOURCE_QUIC_SESSION
)),
177 dns_resolution_end_time_(dns_resolution_end_time
),
178 logger_(new QuicConnectionLogger(this, connection_description
, net_log_
)),
179 num_packets_read_(0),
181 weak_factory_(this) {
182 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
183 tracked_objects::ScopedTracker
tracking_profile1(
184 FROM_HERE_WITH_EXPLICIT_FUNCTION(
185 "422516 QuicClientSession::QuicClientSession1"));
187 connection
->set_debug_visitor(logger_
.get());
189 // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed.
190 tracked_objects::ScopedTracker
tracking_profile2(
191 FROM_HERE_WITH_EXPLICIT_FUNCTION(
192 "422516 QuicClientSession::QuicClientSession2"));
193 if (socket
&& socket
->GetLocalAddress(&address
) == OK
&&
194 address
.GetFamily() == ADDRESS_FAMILY_IPV6
) {
195 connection
->set_max_packet_length(
196 connection
->max_packet_length() - kAdditionalOverheadForIPv6
);
200 void QuicClientSession::InitializeSession(
201 const QuicServerId
& server_id
,
202 QuicCryptoClientConfig
* crypto_config
,
203 QuicCryptoClientStreamFactory
* crypto_client_stream_factory
) {
204 server_id_
= server_id
;
205 crypto_stream_
.reset(
206 crypto_client_stream_factory
?
207 crypto_client_stream_factory
->CreateQuicCryptoClientStream(
208 server_id
, this, crypto_config
) :
209 new QuicCryptoClientStream(server_id
, this,
210 new ProofVerifyContextChromium(net_log_
),
212 QuicClientSessionBase::InitializeSession();
213 // TODO(rch): pass in full host port proxy pair
214 net_log_
.BeginEvent(NetLog::TYPE_QUIC_SESSION
,
215 base::Bind(NetLogQuicClientSessionCallback
,
217 require_confirmation_
));
220 QuicClientSession::~QuicClientSession() {
221 if (!streams()->empty())
222 RecordUnexpectedOpenStreams(DESTRUCTOR
);
223 if (!observers_
.empty())
224 RecordUnexpectedObservers(DESTRUCTOR
);
226 RecordUnexpectedNotGoingAway(DESTRUCTOR
);
228 while (!streams()->empty() ||
229 !observers_
.empty() ||
230 !stream_requests_
.empty()) {
231 // The session must be closed before it is destroyed.
232 DCHECK(streams()->empty());
233 CloseAllStreams(ERR_UNEXPECTED
);
234 DCHECK(observers_
.empty());
235 CloseAllObservers(ERR_UNEXPECTED
);
237 connection()->set_debug_visitor(nullptr);
238 net_log_
.EndEvent(NetLog::TYPE_QUIC_SESSION
);
240 while (!stream_requests_
.empty()) {
241 StreamRequest
* request
= stream_requests_
.front();
242 stream_requests_
.pop_front();
243 request
->OnRequestCompleteFailure(ERR_ABORTED
);
247 if (connection()->connected()) {
248 // Ensure that the connection is closed by the time the session is
250 connection()->CloseConnection(QUIC_INTERNAL_ERROR
, false);
253 if (IsEncryptionEstablished())
254 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED
);
255 if (IsCryptoHandshakeConfirmed())
256 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED
);
258 RecordHandshakeState(STATE_FAILED
);
260 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_
);
261 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
262 crypto_stream_
->num_sent_client_hellos());
263 if (!IsCryptoHandshakeConfirmed())
266 // Sending one client_hello means we had zero handshake-round-trips.
267 int round_trip_handshakes
= crypto_stream_
->num_sent_client_hellos() - 1;
269 // Don't bother with these histogram during tests, which mock out
270 // num_sent_client_hellos().
271 if (round_trip_handshakes
< 0 || !stream_factory_
)
274 bool port_selected
= stream_factory_
->enable_port_selection();
276 if (!GetSSLInfo(&ssl_info
) || !ssl_info
.cert
.get()) {
278 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
279 round_trip_handshakes
, 0, 3, 4);
281 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
282 round_trip_handshakes
, 0, 3, 4);
283 if (require_confirmation_
) {
284 UMA_HISTOGRAM_CUSTOM_COUNTS(
285 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
286 round_trip_handshakes
, 0, 3, 4);
291 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
292 round_trip_handshakes
, 0, 3, 4);
294 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
295 round_trip_handshakes
, 0, 3, 4);
296 if (require_confirmation_
) {
297 UMA_HISTOGRAM_CUSTOM_COUNTS(
298 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
299 round_trip_handshakes
, 0, 3, 4);
303 const QuicConnectionStats stats
= connection()->GetStats();
304 if (server_info_
&& stats
.min_rtt_us
> 0) {
305 base::TimeTicks wait_for_data_start_time
=
306 server_info_
->wait_for_data_start_time();
307 base::TimeTicks wait_for_data_end_time
=
308 server_info_
->wait_for_data_end_time();
309 if (!wait_for_data_start_time
.is_null() &&
310 !wait_for_data_end_time
.is_null()) {
311 base::TimeDelta wait_time
=
312 wait_for_data_end_time
- wait_for_data_start_time
;
313 const base::HistogramBase::Sample kMaxWaitToRtt
= 1000;
314 base::HistogramBase::Sample wait_to_rtt
=
315 static_cast<base::HistogramBase::Sample
>(
316 100 * wait_time
.InMicroseconds() / stats
.min_rtt_us
);
317 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicServerInfo.WaitForDataReadyToRtt",
318 wait_to_rtt
, 0, kMaxWaitToRtt
, 50);
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",
331 reordering
, 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 QuicClientSession::OnStreamFrames(
342 const std::vector
<QuicStreamFrame
>& frames
) {
343 // Record total number of stream frames.
344 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames
.size());
346 // Record number of frames per stream in packet.
347 typedef std::map
<QuicStreamId
, size_t> FrameCounter
;
348 FrameCounter frames_per_stream
;
349 for (size_t i
= 0; i
< frames
.size(); ++i
) {
350 frames_per_stream
[frames
[i
].stream_id
]++;
352 for (FrameCounter::const_iterator it
= frames_per_stream
.begin();
353 it
!= frames_per_stream
.end(); ++it
) {
354 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
358 return QuicSession::OnStreamFrames(frames
);
361 void QuicClientSession::AddObserver(Observer
* observer
) {
363 RecordUnexpectedObservers(ADD_OBSERVER
);
364 observer
->OnSessionClosed(ERR_UNEXPECTED
);
368 DCHECK(!ContainsKey(observers_
, observer
));
369 observers_
.insert(observer
);
372 void QuicClientSession::RemoveObserver(Observer
* observer
) {
373 DCHECK(ContainsKey(observers_
, observer
));
374 observers_
.erase(observer
);
377 int QuicClientSession::TryCreateStream(StreamRequest
* request
,
378 QuicReliableClientStream
** stream
) {
379 if (!crypto_stream_
->encryption_established()) {
380 DLOG(DFATAL
) << "Encryption not established.";
381 return ERR_CONNECTION_CLOSED
;
384 if (goaway_received()) {
385 DVLOG(1) << "Going away.";
386 return ERR_CONNECTION_CLOSED
;
389 if (!connection()->connected()) {
390 DVLOG(1) << "Already closed.";
391 return ERR_CONNECTION_CLOSED
;
395 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM
);
396 return ERR_CONNECTION_CLOSED
;
399 if (GetNumOpenStreams() < get_max_open_streams()) {
400 *stream
= CreateOutgoingReliableStreamImpl();
404 stream_requests_
.push_back(request
);
405 return ERR_IO_PENDING
;
408 void QuicClientSession::CancelRequest(StreamRequest
* request
) {
409 // Remove |request| from the queue while preserving the order of the
411 StreamRequestQueue::iterator it
=
412 std::find(stream_requests_
.begin(), stream_requests_
.end(), request
);
413 if (it
!= stream_requests_
.end()) {
414 it
= stream_requests_
.erase(it
);
418 QuicReliableClientStream
* QuicClientSession::CreateOutgoingDataStream() {
419 if (!crypto_stream_
->encryption_established()) {
420 DVLOG(1) << "Encryption not active so no outgoing stream created.";
423 if (GetNumOpenStreams() >= get_max_open_streams()) {
424 DVLOG(1) << "Failed to create a new outgoing stream. "
425 << "Already " << GetNumOpenStreams() << " open.";
428 if (goaway_received()) {
429 DVLOG(1) << "Failed to create a new outgoing stream. "
430 << "Already received goaway.";
434 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM
);
437 return CreateOutgoingReliableStreamImpl();
440 QuicReliableClientStream
*
441 QuicClientSession::CreateOutgoingReliableStreamImpl() {
442 DCHECK(connection()->connected());
443 QuicReliableClientStream
* stream
=
444 new QuicReliableClientStream(GetNextStreamId(), this, net_log_
);
445 ActivateStream(stream
);
446 ++num_total_streams_
;
447 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
451 QuicCryptoClientStream
* QuicClientSession::GetCryptoStream() {
452 return crypto_stream_
.get();
455 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
456 // we learn about SSL info (sync vs async vs cached).
457 bool QuicClientSession::GetSSLInfo(SSLInfo
* ssl_info
) const {
459 if (!cert_verify_result_
) {
463 ssl_info
->cert_status
= cert_verify_result_
->cert_status
;
464 ssl_info
->cert
= cert_verify_result_
->verified_cert
;
466 // TODO(wtc): Define QUIC "cipher suites".
467 // Report the TLS cipher suite that most closely resembles the crypto
468 // parameters of the QUIC connection.
469 QuicTag aead
= crypto_stream_
->crypto_negotiated_params().aead
;
474 cipher_suite
= 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
478 cipher_suite
= 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
485 int ssl_connection_status
= 0;
486 ssl_connection_status
|= cipher_suite
;
487 ssl_connection_status
|=
488 (SSL_CONNECTION_VERSION_QUIC
& SSL_CONNECTION_VERSION_MASK
) <<
489 SSL_CONNECTION_VERSION_SHIFT
;
491 ssl_info
->public_key_hashes
= cert_verify_result_
->public_key_hashes
;
492 ssl_info
->is_issued_by_known_root
=
493 cert_verify_result_
->is_issued_by_known_root
;
495 ssl_info
->connection_status
= ssl_connection_status
;
496 ssl_info
->client_cert_sent
= false;
497 ssl_info
->channel_id_sent
= crypto_stream_
->WasChannelIDSent();
498 ssl_info
->security_bits
= security_bits
;
499 ssl_info
->handshake_type
= SSLInfo::HANDSHAKE_FULL
;
500 ssl_info
->pinning_failure_log
= pinning_failure_log_
;
504 int QuicClientSession::CryptoConnect(bool require_confirmation
,
505 const CompletionCallback
& callback
) {
506 require_confirmation_
= require_confirmation
;
507 handshake_start_
= base::TimeTicks::Now();
508 RecordHandshakeState(STATE_STARTED
);
509 DCHECK(flow_controller());
510 crypto_stream_
->CryptoConnect();
512 if (IsCryptoHandshakeConfirmed())
515 // Unless we require handshake confirmation, activate the session if
516 // we have established initial encryption.
517 if (!require_confirmation_
&& IsEncryptionEstablished()) {
518 // To mitigate the effects of hanging 0-RTT connections, set up a timer to
519 // cancel any requests, if the handshake takes too long.
520 task_runner_
->PostDelayedTask(
522 base::Bind(&QuicClientSession::OnConnectTimeout
,
523 weak_factory_
.GetWeakPtr()),
524 base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs
));
529 callback_
= callback
;
530 return ERR_IO_PENDING
;
533 int QuicClientSession::ResumeCryptoConnect(const CompletionCallback
& callback
) {
535 if (IsCryptoHandshakeConfirmed())
538 if (!connection()->connected())
539 return ERR_QUIC_HANDSHAKE_FAILED
;
541 callback_
= callback
;
542 return ERR_IO_PENDING
;
545 int QuicClientSession::GetNumSentClientHellos() const {
546 return crypto_stream_
->num_sent_client_hellos();
549 bool QuicClientSession::CanPool(const std::string
& hostname
,
550 PrivacyMode privacy_mode
) const {
551 DCHECK(connection()->connected());
552 if (privacy_mode
!= server_id_
.privacy_mode()) {
553 // Privacy mode must always match.
557 if (!GetSSLInfo(&ssl_info
) || !ssl_info
.cert
.get()) {
558 // We can always pool with insecure QUIC sessions.
562 return SpdySession::CanPool(transport_security_state_
, ssl_info
,
563 server_id_
.host(), hostname
);
566 QuicDataStream
* QuicClientSession::CreateIncomingDataStream(
568 DLOG(ERROR
) << "Server push not supported";
572 void QuicClientSession::CloseStream(QuicStreamId stream_id
) {
573 ReliableQuicStream
* stream
= GetStream(stream_id
);
575 logger_
->UpdateReceivedFrameCounts(
576 stream_id
, stream
->num_frames_received(),
577 stream
->num_duplicate_frames_received());
579 QuicSession::CloseStream(stream_id
);
583 void QuicClientSession::SendRstStream(QuicStreamId id
,
584 QuicRstStreamErrorCode error
,
585 QuicStreamOffset bytes_written
) {
586 QuicSession::SendRstStream(id
, error
, bytes_written
);
590 void QuicClientSession::OnClosedStream() {
591 if (GetNumOpenStreams() < get_max_open_streams() &&
592 !stream_requests_
.empty() &&
593 crypto_stream_
->encryption_established() &&
594 !goaway_received() &&
596 connection()->connected()) {
597 StreamRequest
* request
= stream_requests_
.front();
598 stream_requests_
.pop_front();
599 request
->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
602 if (GetNumOpenStreams() == 0) {
603 stream_factory_
->OnIdleSession(this);
607 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event
) {
608 if (!callback_
.is_null() &&
609 (!require_confirmation_
||
610 event
== HANDSHAKE_CONFIRMED
|| event
== ENCRYPTION_REESTABLISHED
)) {
611 // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
612 // could be called because there are no error events in CryptoHandshakeEvent
613 // enum. If error events are added to CryptoHandshakeEvent, then the
614 // following code needs to changed.
615 base::ResetAndReturn(&callback_
).Run(OK
);
617 if (event
== HANDSHAKE_CONFIRMED
) {
618 UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime",
619 base::TimeTicks::Now() - handshake_start_
);
621 // TODO(rtenneti): Should we delete this histogram?
622 // Track how long it has taken to finish handshake once we start waiting
623 // for reading of QUIC server information from disk cache. We could use
624 // this data to compare total time taken if we were to cancel the disk
625 // cache read vs waiting for the read to complete.
626 base::TimeTicks wait_for_data_start_time
=
627 server_info_
->wait_for_data_start_time();
628 if (!wait_for_data_start_time
.is_null()) {
630 "Net.QuicServerInfo.WaitForDataReady.HandshakeConfirmedTime",
631 base::TimeTicks::Now() - wait_for_data_start_time
);
634 // Track how long it has taken to finish handshake after we have finished
635 // DNS host resolution.
636 if (!dns_resolution_end_time_
.is_null()) {
638 "Net.QuicSession.HostResolution.HandshakeConfirmedTime",
639 base::TimeTicks::Now() - dns_resolution_end_time_
);
642 ObserverSet::iterator it
= observers_
.begin();
643 while (it
!= observers_
.end()) {
644 Observer
* observer
= *it
;
646 observer
->OnCryptoHandshakeConfirmed();
649 server_info_
->OnExternalCacheHit();
651 QuicSession::OnCryptoHandshakeEvent(event
);
654 void QuicClientSession::OnCryptoHandshakeMessageSent(
655 const CryptoHandshakeMessage
& message
) {
656 logger_
->OnCryptoHandshakeMessageSent(message
);
659 void QuicClientSession::OnCryptoHandshakeMessageReceived(
660 const CryptoHandshakeMessage
& message
) {
661 logger_
->OnCryptoHandshakeMessageReceived(message
);
664 void QuicClientSession::OnConnectionClosed(QuicErrorCode error
,
666 DCHECK(!connection()->connected());
667 logger_
->OnConnectionClosed(error
, from_peer
);
669 UMA_HISTOGRAM_SPARSE_SLOWLY(
670 "Net.QuicSession.ConnectionCloseErrorCodeServer", error
);
672 UMA_HISTOGRAM_SPARSE_SLOWLY(
673 "Net.QuicSession.ConnectionCloseErrorCodeClient", error
);
676 if (error
== QUIC_CONNECTION_TIMED_OUT
) {
677 UMA_HISTOGRAM_COUNTS(
678 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
679 GetNumOpenStreams());
680 if (IsCryptoHandshakeConfirmed()) {
681 if (GetNumOpenStreams() > 0) {
682 UMA_HISTOGRAM_BOOLEAN(
683 "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
684 connection()->sent_packet_manager().HasUnackedPackets());
685 UMA_HISTOGRAM_COUNTS(
686 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
687 connection()->sent_packet_manager().consecutive_rto_count());
688 UMA_HISTOGRAM_COUNTS(
689 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
690 connection()->sent_packet_manager().consecutive_tlp_count());
692 if (connection()->sent_packet_manager().HasUnackedPackets()) {
694 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
695 "TimeSinceLastReceived.UnackedPackets",
696 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
699 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
700 "TimeSinceLastReceived.NoUnackedPackets",
701 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
705 UMA_HISTOGRAM_COUNTS(
706 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
707 GetNumOpenStreams());
708 UMA_HISTOGRAM_COUNTS(
709 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
714 if (!IsCryptoHandshakeConfirmed()) {
715 if (error
== QUIC_PUBLIC_RESET
) {
716 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET
);
717 } else if (connection()->GetStats().packets_received
== 0) {
718 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE
);
719 UMA_HISTOGRAM_SPARSE_SLOWLY(
720 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
723 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN
);
724 UMA_HISTOGRAM_SPARSE_SLOWLY(
725 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
730 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
731 connection()->version());
732 NotifyFactoryOfSessionGoingAway();
733 if (!callback_
.is_null()) {
734 base::ResetAndReturn(&callback_
).Run(ERR_QUIC_PROTOCOL_ERROR
);
737 QuicSession::OnConnectionClosed(error
, from_peer
);
738 DCHECK(streams()->empty());
739 CloseAllStreams(ERR_UNEXPECTED
);
740 CloseAllObservers(ERR_UNEXPECTED
);
741 NotifyFactoryOfSessionClosedLater();
744 void QuicClientSession::OnSuccessfulVersionNegotiation(
745 const QuicVersion
& version
) {
746 logger_
->OnSuccessfulVersionNegotiation(version
);
747 QuicSession::OnSuccessfulVersionNegotiation(version
);
750 void QuicClientSession::OnProofValid(
751 const QuicCryptoClientConfig::CachedState
& cached
) {
752 DCHECK(cached
.proof_valid());
758 QuicServerInfo::State
* state
= server_info_
->mutable_state();
760 state
->server_config
= cached
.server_config();
761 state
->source_address_token
= cached
.source_address_token();
762 state
->server_config_sig
= cached
.signature();
763 state
->certs
= cached
.certs();
765 server_info_
->Persist();
768 void QuicClientSession::OnProofVerifyDetailsAvailable(
769 const ProofVerifyDetails
& verify_details
) {
770 const ProofVerifyDetailsChromium
* verify_details_chromium
=
771 reinterpret_cast<const ProofVerifyDetailsChromium
*>(&verify_details
);
772 CertVerifyResult
* result_copy
= new CertVerifyResult
;
773 result_copy
->CopyFrom(verify_details_chromium
->cert_verify_result
);
774 cert_verify_result_
.reset(result_copy
);
775 pinning_failure_log_
= verify_details_chromium
->pinning_failure_log
;
776 logger_
->OnCertificateVerified(*cert_verify_result_
);
779 void QuicClientSession::StartReading() {
783 read_pending_
= true;
784 int rv
= socket_
->Read(read_buffer_
.get(),
785 read_buffer_
->size(),
786 base::Bind(&QuicClientSession::OnReadComplete
,
787 weak_factory_
.GetWeakPtr()));
788 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv
== ERR_IO_PENDING
);
789 if (rv
== ERR_IO_PENDING
) {
790 num_packets_read_
= 0;
794 if (++num_packets_read_
> 32) {
795 num_packets_read_
= 0;
796 // Data was read, process it.
797 // Schedule the work through the message loop to 1) prevent infinite
798 // recursion and 2) avoid blocking the thread for too long.
799 base::MessageLoop::current()->PostTask(
801 base::Bind(&QuicClientSession::OnReadComplete
,
802 weak_factory_
.GetWeakPtr(), rv
));
808 void QuicClientSession::CloseSessionOnError(int error
) {
809 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error
);
810 CloseSessionOnErrorInner(error
, QUIC_INTERNAL_ERROR
);
811 NotifyFactoryOfSessionClosed();
814 void QuicClientSession::CloseSessionOnErrorInner(int net_error
,
815 QuicErrorCode quic_error
) {
816 if (!callback_
.is_null()) {
817 base::ResetAndReturn(&callback_
).Run(net_error
);
819 CloseAllStreams(net_error
);
820 CloseAllObservers(net_error
);
822 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 QuicClientSession::CloseAllStreams(int net_error
) {
831 while (!streams()->empty()) {
832 ReliableQuicStream
* stream
= streams()->begin()->second
;
833 QuicStreamId id
= stream
->id();
834 static_cast<QuicReliableClientStream
*>(stream
)->OnError(net_error
);
839 void QuicClientSession::CloseAllObservers(int net_error
) {
840 while (!observers_
.empty()) {
841 Observer
* observer
= *observers_
.begin();
842 observers_
.erase(observer
);
843 observer
->OnSessionClosed(net_error
);
847 base::Value
* QuicClientSession::GetInfoAsValue(
848 const std::set
<HostPortPair
>& aliases
) {
849 base::DictionaryValue
* dict
= new base::DictionaryValue();
850 dict
->SetString("version", QuicVersionToString(connection()->version()));
851 dict
->SetInteger("open_streams", GetNumOpenStreams());
852 base::ListValue
* stream_list
= new base::ListValue();
853 for (base::hash_map
<QuicStreamId
, QuicDataStream
*>::const_iterator it
854 = streams()->begin();
855 it
!= streams()->end();
857 stream_list
->Append(new base::StringValue(
858 base::Uint64ToString(it
->second
->id())));
860 dict
->Set("active_streams", stream_list
);
862 dict
->SetInteger("total_streams", num_total_streams_
);
863 dict
->SetString("peer_address", peer_address().ToString());
864 dict
->SetString("connection_id", base::Uint64ToString(connection_id()));
865 dict
->SetBoolean("connected", connection()->connected());
866 const QuicConnectionStats
& stats
= connection()->GetStats();
867 dict
->SetInteger("packets_sent", stats
.packets_sent
);
868 dict
->SetInteger("packets_received", stats
.packets_received
);
869 dict
->SetInteger("packets_lost", stats
.packets_lost
);
871 dict
->SetBoolean("secure", GetSSLInfo(&ssl_info
) && ssl_info
.cert
.get());
873 base::ListValue
* alias_list
= new base::ListValue();
874 for (std::set
<HostPortPair
>::const_iterator it
= aliases
.begin();
875 it
!= aliases
.end(); it
++) {
876 alias_list
->Append(new base::StringValue(it
->ToString()));
878 dict
->Set("aliases", alias_list
);
883 base::WeakPtr
<QuicClientSession
> QuicClientSession::GetWeakPtr() {
884 return weak_factory_
.GetWeakPtr();
887 void QuicClientSession::OnReadComplete(int result
) {
888 read_pending_
= false;
890 result
= ERR_CONNECTION_CLOSED
;
893 DVLOG(1) << "Closing session on read error: " << result
;
894 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result
);
895 NotifyFactoryOfSessionGoingAway();
896 CloseSessionOnErrorInner(result
, QUIC_PACKET_READ_ERROR
);
897 NotifyFactoryOfSessionClosedLater();
901 QuicEncryptedPacket
packet(read_buffer_
->data(), result
);
902 IPEndPoint local_address
;
903 IPEndPoint peer_address
;
904 socket_
->GetLocalAddress(&local_address
);
905 socket_
->GetPeerAddress(&peer_address
);
906 // ProcessUdpPacket might result in |this| being deleted, so we
907 // use a weak pointer to be safe.
908 connection()->ProcessUdpPacket(local_address
, peer_address
, packet
);
909 if (!connection()->connected()) {
910 NotifyFactoryOfSessionClosedLater();
916 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
919 stream_factory_
->OnSessionGoingAway(this);
922 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
923 if (!streams()->empty())
924 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER
);
927 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER
);
930 DCHECK_EQ(0u, GetNumOpenStreams());
931 DCHECK(!connection()->connected());
932 base::MessageLoop::current()->PostTask(
934 base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed
,
935 weak_factory_
.GetWeakPtr()));
938 void QuicClientSession::NotifyFactoryOfSessionClosed() {
939 if (!streams()->empty())
940 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED
);
943 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED
);
946 DCHECK_EQ(0u, GetNumOpenStreams());
947 // Will delete |this|.
949 stream_factory_
->OnSessionClosed(this);
952 void QuicClientSession::OnConnectTimeout() {
953 DCHECK(callback_
.is_null());
954 DCHECK(IsEncryptionEstablished());
956 if (IsCryptoHandshakeConfirmed())
959 // TODO(rch): re-enable this code once beta is cut.
960 // if (stream_factory_)
961 // stream_factory_->OnSessionConnectTimeout(this);
962 // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
963 // DCHECK_EQ(0u, GetNumOpenStreams());