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/stl_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/values.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
16 #include "net/base/network_activity_monitor.h"
17 #include "net/http/transport_security_state.h"
18 #include "net/quic/crypto/proof_verifier_chromium.h"
19 #include "net/quic/crypto/quic_server_info.h"
20 #include "net/quic/quic_connection_helper.h"
21 #include "net/quic/quic_crypto_client_stream_factory.h"
22 #include "net/quic/quic_server_id.h"
23 #include "net/quic/quic_stream_factory.h"
24 #include "net/spdy/spdy_session.h"
25 #include "net/ssl/channel_id_service.h"
26 #include "net/ssl/ssl_connection_status_flags.h"
27 #include "net/ssl/ssl_info.h"
28 #include "net/udp/datagram_client_socket.h"
34 // The length of time to wait for a 0-RTT handshake to complete
35 // before allowing the requests to possibly proceed over TCP.
36 const int k0RttHandshakeTimeoutMs
= 300;
38 // IPv6 packets have an additional 20 bytes of overhead than IPv4 packets.
39 const size_t kAdditionalOverheadForIPv6
= 20;
41 // Histograms for tracking down the crashes from http://crbug.com/354669
42 // Note: these values must be kept in sync with the corresponding values in:
43 // tools/metrics/histograms/histograms.xml
47 TRY_CREATE_STREAM
= 2,
48 CREATE_OUTGOING_RELIABLE_STREAM
= 3,
49 NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER
= 4,
50 NOTIFY_FACTORY_OF_SESSION_CLOSED
= 5,
54 void RecordUnexpectedOpenStreams(Location location
) {
55 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location
,
59 void RecordUnexpectedObservers(Location location
) {
60 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location
,
64 void RecordUnexpectedNotGoingAway(Location location
) {
65 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location
,
69 // Histogram for recording the different reasons that a QUIC session is unable
70 // to complete the handshake.
71 enum HandshakeFailureReason
{
72 HANDSHAKE_FAILURE_UNKNOWN
= 0,
73 HANDSHAKE_FAILURE_BLACK_HOLE
= 1,
74 HANDSHAKE_FAILURE_PUBLIC_RESET
= 2,
75 NUM_HANDSHAKE_FAILURE_REASONS
= 3,
78 void RecordHandshakeFailureReason(HandshakeFailureReason reason
) {
79 UMA_HISTOGRAM_ENUMERATION(
80 "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason",
81 reason
, NUM_HANDSHAKE_FAILURE_REASONS
);
84 // Note: these values must be kept in sync with the corresponding values in:
85 // tools/metrics/histograms/histograms.xml
88 STATE_ENCRYPTION_ESTABLISHED
= 1,
89 STATE_HANDSHAKE_CONFIRMED
= 2,
91 NUM_HANDSHAKE_STATES
= 4
94 void RecordHandshakeState(HandshakeState state
) {
95 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state
,
96 NUM_HANDSHAKE_STATES
);
99 base::Value
* NetLogQuicClientSessionCallback(
100 const QuicServerId
* server_id
,
101 bool require_confirmation
,
102 NetLog::LogLevel
/* log_level */) {
103 base::DictionaryValue
* dict
= new base::DictionaryValue();
104 dict
->SetString("host", server_id
->host());
105 dict
->SetInteger("port", server_id
->port());
106 dict
->SetBoolean("is_https", server_id
->is_https());
107 dict
->SetBoolean("require_confirmation", require_confirmation
);
113 QuicClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
115 QuicClientSession::StreamRequest::~StreamRequest() {
119 int QuicClientSession::StreamRequest::StartRequest(
120 const base::WeakPtr
<QuicClientSession
>& session
,
121 QuicReliableClientStream
** stream
,
122 const CompletionCallback
& callback
) {
125 int rv
= session_
->TryCreateStream(this, stream_
);
126 if (rv
== ERR_IO_PENDING
) {
127 callback_
= callback
;
133 void QuicClientSession::StreamRequest::CancelRequest() {
135 session_
->CancelRequest(this);
140 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
141 QuicReliableClientStream
* stream
) {
144 ResetAndReturn(&callback_
).Run(OK
);
147 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv
) {
149 ResetAndReturn(&callback_
).Run(rv
);
152 QuicClientSession::QuicClientSession(
153 QuicConnection
* connection
,
154 scoped_ptr
<DatagramClientSocket
> socket
,
155 QuicStreamFactory
* stream_factory
,
156 TransportSecurityState
* transport_security_state
,
157 scoped_ptr
<QuicServerInfo
> server_info
,
158 const QuicConfig
& config
,
159 base::TaskRunner
* task_runner
,
161 : QuicClientSessionBase(connection
, config
),
162 require_confirmation_(false),
163 stream_factory_(stream_factory
),
164 socket_(socket
.Pass()),
165 read_buffer_(new IOBufferWithSize(kMaxPacketSize
)),
166 transport_security_state_(transport_security_state
),
167 server_info_(server_info
.Pass()),
168 read_pending_(false),
169 num_total_streams_(0),
170 task_runner_(task_runner
),
171 net_log_(BoundNetLog::Make(net_log
, NetLog::SOURCE_QUIC_SESSION
)),
172 logger_(new QuicConnectionLogger(this, net_log_
)),
173 num_packets_read_(0),
175 weak_factory_(this) {
176 connection
->set_debug_visitor(logger_
);
178 if (socket
&& socket
->GetLocalAddress(&address
) == OK
&&
179 address
.GetFamily() == ADDRESS_FAMILY_IPV6
) {
180 connection
->set_max_packet_length(
181 connection
->max_packet_length() - kAdditionalOverheadForIPv6
);
185 void QuicClientSession::InitializeSession(
186 const QuicServerId
& server_id
,
187 QuicCryptoClientConfig
* crypto_config
,
188 QuicCryptoClientStreamFactory
* crypto_client_stream_factory
) {
189 server_host_port_
= server_id
.host_port_pair();
190 crypto_stream_
.reset(
191 crypto_client_stream_factory
?
192 crypto_client_stream_factory
->CreateQuicCryptoClientStream(
193 server_id
, this, crypto_config
) :
194 new QuicCryptoClientStream(server_id
, this,
195 new ProofVerifyContextChromium(net_log_
),
197 QuicClientSessionBase::InitializeSession();
198 // TODO(rch): pass in full host port proxy pair
199 net_log_
.BeginEvent(NetLog::TYPE_QUIC_SESSION
,
200 base::Bind(NetLogQuicClientSessionCallback
,
202 require_confirmation_
));
205 QuicClientSession::~QuicClientSession() {
206 if (!streams()->empty())
207 RecordUnexpectedOpenStreams(DESTRUCTOR
);
208 if (!observers_
.empty())
209 RecordUnexpectedObservers(DESTRUCTOR
);
211 RecordUnexpectedNotGoingAway(DESTRUCTOR
);
213 while (!streams()->empty() ||
214 !observers_
.empty() ||
215 !stream_requests_
.empty()) {
216 // The session must be closed before it is destroyed.
217 DCHECK(streams()->empty());
218 CloseAllStreams(ERR_UNEXPECTED
);
219 DCHECK(observers_
.empty());
220 CloseAllObservers(ERR_UNEXPECTED
);
222 connection()->set_debug_visitor(nullptr);
223 net_log_
.EndEvent(NetLog::TYPE_QUIC_SESSION
);
225 while (!stream_requests_
.empty()) {
226 StreamRequest
* request
= stream_requests_
.front();
227 stream_requests_
.pop_front();
228 request
->OnRequestCompleteFailure(ERR_ABORTED
);
232 if (connection()->connected()) {
233 // Ensure that the connection is closed by the time the session is
235 connection()->CloseConnection(QUIC_INTERNAL_ERROR
, false);
238 if (IsEncryptionEstablished())
239 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED
);
240 if (IsCryptoHandshakeConfirmed())
241 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED
);
243 RecordHandshakeState(STATE_FAILED
);
245 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_
);
246 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
247 crypto_stream_
->num_sent_client_hellos());
248 if (!IsCryptoHandshakeConfirmed())
251 // Sending one client_hello means we had zero handshake-round-trips.
252 int round_trip_handshakes
= crypto_stream_
->num_sent_client_hellos() - 1;
254 // Don't bother with these histogram during tests, which mock out
255 // num_sent_client_hellos().
256 if (round_trip_handshakes
< 0 || !stream_factory_
)
259 bool port_selected
= stream_factory_
->enable_port_selection();
261 if (!GetSSLInfo(&ssl_info
) || !ssl_info
.cert
.get()) {
263 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
264 round_trip_handshakes
, 0, 3, 4);
266 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
267 round_trip_handshakes
, 0, 3, 4);
268 if (require_confirmation_
) {
269 UMA_HISTOGRAM_CUSTOM_COUNTS(
270 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
271 round_trip_handshakes
, 0, 3, 4);
276 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
277 round_trip_handshakes
, 0, 3, 4);
279 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
280 round_trip_handshakes
, 0, 3, 4);
281 if (require_confirmation_
) {
282 UMA_HISTOGRAM_CUSTOM_COUNTS(
283 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
284 round_trip_handshakes
, 0, 3, 4);
288 const QuicConnectionStats stats
= connection()->GetStats();
289 if (stats
.max_sequence_reordering
== 0)
291 const base::HistogramBase::Sample kMaxReordering
= 100;
292 base::HistogramBase::Sample reordering
= kMaxReordering
;
293 if (stats
.min_rtt_us
> 0) {
294 reordering
= static_cast<base::HistogramBase::Sample
>(
295 100 * stats
.max_time_reordering_us
/ stats
.min_rtt_us
);
297 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime",
298 reordering
, 0, kMaxReordering
, 50);
299 if (stats
.min_rtt_us
> 100 * 1000) {
300 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
301 reordering
, 0, kMaxReordering
, 50);
303 UMA_HISTOGRAM_COUNTS("Net.QuicSession.MaxReordering",
304 stats
.max_sequence_reordering
);
307 void QuicClientSession::OnStreamFrames(
308 const std::vector
<QuicStreamFrame
>& frames
) {
309 // Record total number of stream frames.
310 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames
.size());
312 // Record number of frames per stream in packet.
313 typedef std::map
<QuicStreamId
, size_t> FrameCounter
;
314 FrameCounter frames_per_stream
;
315 for (size_t i
= 0; i
< frames
.size(); ++i
) {
316 frames_per_stream
[frames
[i
].stream_id
]++;
318 for (FrameCounter::const_iterator it
= frames_per_stream
.begin();
319 it
!= frames_per_stream
.end(); ++it
) {
320 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
324 return QuicSession::OnStreamFrames(frames
);
327 void QuicClientSession::AddObserver(Observer
* observer
) {
329 RecordUnexpectedObservers(ADD_OBSERVER
);
330 observer
->OnSessionClosed(ERR_UNEXPECTED
);
334 DCHECK(!ContainsKey(observers_
, observer
));
335 observers_
.insert(observer
);
338 void QuicClientSession::RemoveObserver(Observer
* observer
) {
339 DCHECK(ContainsKey(observers_
, observer
));
340 observers_
.erase(observer
);
343 int QuicClientSession::TryCreateStream(StreamRequest
* request
,
344 QuicReliableClientStream
** stream
) {
345 if (!crypto_stream_
->encryption_established()) {
346 DLOG(DFATAL
) << "Encryption not established.";
347 return ERR_CONNECTION_CLOSED
;
350 if (goaway_received()) {
351 DVLOG(1) << "Going away.";
352 return ERR_CONNECTION_CLOSED
;
355 if (!connection()->connected()) {
356 DVLOG(1) << "Already closed.";
357 return ERR_CONNECTION_CLOSED
;
361 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM
);
362 return ERR_CONNECTION_CLOSED
;
365 if (GetNumOpenStreams() < get_max_open_streams()) {
366 *stream
= CreateOutgoingReliableStreamImpl();
370 stream_requests_
.push_back(request
);
371 return ERR_IO_PENDING
;
374 void QuicClientSession::CancelRequest(StreamRequest
* request
) {
375 // Remove |request| from the queue while preserving the order of the
377 StreamRequestQueue::iterator it
=
378 std::find(stream_requests_
.begin(), stream_requests_
.end(), request
);
379 if (it
!= stream_requests_
.end()) {
380 it
= stream_requests_
.erase(it
);
384 QuicReliableClientStream
* QuicClientSession::CreateOutgoingDataStream() {
385 if (!crypto_stream_
->encryption_established()) {
386 DVLOG(1) << "Encryption not active so no outgoing stream created.";
389 if (GetNumOpenStreams() >= get_max_open_streams()) {
390 DVLOG(1) << "Failed to create a new outgoing stream. "
391 << "Already " << GetNumOpenStreams() << " open.";
394 if (goaway_received()) {
395 DVLOG(1) << "Failed to create a new outgoing stream. "
396 << "Already received goaway.";
400 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM
);
403 return CreateOutgoingReliableStreamImpl();
406 QuicReliableClientStream
*
407 QuicClientSession::CreateOutgoingReliableStreamImpl() {
408 DCHECK(connection()->connected());
409 QuicReliableClientStream
* stream
=
410 new QuicReliableClientStream(GetNextStreamId(), this, net_log_
);
411 ActivateStream(stream
);
412 ++num_total_streams_
;
413 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
417 QuicCryptoClientStream
* QuicClientSession::GetCryptoStream() {
418 return crypto_stream_
.get();
421 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
422 // we learn about SSL info (sync vs async vs cached).
423 bool QuicClientSession::GetSSLInfo(SSLInfo
* ssl_info
) const {
425 if (!cert_verify_result_
) {
429 ssl_info
->cert_status
= cert_verify_result_
->cert_status
;
430 ssl_info
->cert
= cert_verify_result_
->verified_cert
;
432 // TODO(wtc): Define QUIC "cipher suites".
433 // Report the TLS cipher suite that most closely resembles the crypto
434 // parameters of the QUIC connection.
435 QuicTag aead
= crypto_stream_
->crypto_negotiated_params().aead
;
440 cipher_suite
= 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
444 cipher_suite
= 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
451 int ssl_connection_status
= 0;
452 ssl_connection_status
|=
453 (cipher_suite
& SSL_CONNECTION_CIPHERSUITE_MASK
) <<
454 SSL_CONNECTION_CIPHERSUITE_SHIFT
;
455 ssl_connection_status
|=
456 (SSL_CONNECTION_VERSION_QUIC
& SSL_CONNECTION_VERSION_MASK
) <<
457 SSL_CONNECTION_VERSION_SHIFT
;
459 ssl_info
->public_key_hashes
= cert_verify_result_
->public_key_hashes
;
460 ssl_info
->is_issued_by_known_root
=
461 cert_verify_result_
->is_issued_by_known_root
;
463 ssl_info
->connection_status
= ssl_connection_status
;
464 ssl_info
->client_cert_sent
= false;
465 ssl_info
->channel_id_sent
= crypto_stream_
->WasChannelIDSent();
466 ssl_info
->security_bits
= security_bits
;
467 ssl_info
->handshake_type
= SSLInfo::HANDSHAKE_FULL
;
468 ssl_info
->pinning_failure_log
= pinning_failure_log_
;
472 int QuicClientSession::CryptoConnect(bool require_confirmation
,
473 const CompletionCallback
& callback
) {
474 require_confirmation_
= require_confirmation
;
475 handshake_start_
= base::TimeTicks::Now();
476 RecordHandshakeState(STATE_STARTED
);
477 DCHECK(flow_controller());
478 if (!crypto_stream_
->CryptoConnect()) {
479 // TODO(wtc): change crypto_stream_.CryptoConnect() to return a
480 // QuicErrorCode and map it to a net error code.
481 return ERR_CONNECTION_FAILED
;
484 if (IsCryptoHandshakeConfirmed())
487 // Unless we require handshake confirmation, activate the session if
488 // we have established initial encryption.
489 if (!require_confirmation_
&& IsEncryptionEstablished()) {
490 // To mitigate the effects of hanging 0-RTT connections, set up a timer to
491 // cancel any requests, if the handshake takes too long.
492 task_runner_
->PostDelayedTask(
494 base::Bind(&QuicClientSession::OnConnectTimeout
,
495 weak_factory_
.GetWeakPtr()),
496 base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs
));
501 callback_
= callback
;
502 return ERR_IO_PENDING
;
505 int QuicClientSession::ResumeCryptoConnect(const CompletionCallback
& callback
) {
507 if (IsCryptoHandshakeConfirmed())
510 if (!connection()->connected())
511 return ERR_QUIC_HANDSHAKE_FAILED
;
513 callback_
= callback
;
514 return ERR_IO_PENDING
;
517 int QuicClientSession::GetNumSentClientHellos() const {
518 return crypto_stream_
->num_sent_client_hellos();
521 bool QuicClientSession::CanPool(const std::string
& hostname
) const {
522 DCHECK(connection()->connected());
524 if (!GetSSLInfo(&ssl_info
) || !ssl_info
.cert
.get()) {
525 // We can always pool with insecure QUIC sessions.
529 return SpdySession::CanPool(transport_security_state_
, ssl_info
,
530 server_host_port_
.host(), hostname
);
533 QuicDataStream
* QuicClientSession::CreateIncomingDataStream(
535 DLOG(ERROR
) << "Server push not supported";
539 void QuicClientSession::CloseStream(QuicStreamId stream_id
) {
540 ReliableQuicStream
* stream
= GetStream(stream_id
);
542 logger_
->UpdateReceivedFrameCounts(
543 stream_id
, stream
->num_frames_received(),
544 stream
->num_duplicate_frames_received());
546 QuicSession::CloseStream(stream_id
);
550 void QuicClientSession::SendRstStream(QuicStreamId id
,
551 QuicRstStreamErrorCode error
,
552 QuicStreamOffset bytes_written
) {
553 QuicSession::SendRstStream(id
, error
, bytes_written
);
557 void QuicClientSession::OnClosedStream() {
558 if (GetNumOpenStreams() < get_max_open_streams() &&
559 !stream_requests_
.empty() &&
560 crypto_stream_
->encryption_established() &&
561 !goaway_received() &&
563 connection()->connected()) {
564 StreamRequest
* request
= stream_requests_
.front();
565 stream_requests_
.pop_front();
566 request
->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
569 if (GetNumOpenStreams() == 0) {
570 stream_factory_
->OnIdleSession(this);
574 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event
) {
575 if (!callback_
.is_null() &&
576 (!require_confirmation_
||
577 event
== HANDSHAKE_CONFIRMED
|| event
== ENCRYPTION_REESTABLISHED
)) {
578 // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
579 // could be called because there are no error events in CryptoHandshakeEvent
580 // enum. If error events are added to CryptoHandshakeEvent, then the
581 // following code needs to changed.
582 base::ResetAndReturn(&callback_
).Run(OK
);
584 if (event
== HANDSHAKE_CONFIRMED
) {
585 UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime",
586 base::TimeTicks::Now() - handshake_start_
);
587 ObserverSet::iterator it
= observers_
.begin();
588 while (it
!= observers_
.end()) {
589 Observer
* observer
= *it
;
591 observer
->OnCryptoHandshakeConfirmed();
594 server_info_
->OnExternalCacheHit();
596 QuicSession::OnCryptoHandshakeEvent(event
);
599 void QuicClientSession::OnCryptoHandshakeMessageSent(
600 const CryptoHandshakeMessage
& message
) {
601 logger_
->OnCryptoHandshakeMessageSent(message
);
604 void QuicClientSession::OnCryptoHandshakeMessageReceived(
605 const CryptoHandshakeMessage
& message
) {
606 logger_
->OnCryptoHandshakeMessageReceived(message
);
609 void QuicClientSession::OnConnectionClosed(QuicErrorCode error
,
611 DCHECK(!connection()->connected());
612 logger_
->OnConnectionClosed(error
, from_peer
);
614 UMA_HISTOGRAM_SPARSE_SLOWLY(
615 "Net.QuicSession.ConnectionCloseErrorCodeServer", error
);
617 UMA_HISTOGRAM_SPARSE_SLOWLY(
618 "Net.QuicSession.ConnectionCloseErrorCodeClient", error
);
621 if (error
== QUIC_CONNECTION_TIMED_OUT
) {
622 UMA_HISTOGRAM_COUNTS(
623 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
624 GetNumOpenStreams());
625 if (IsCryptoHandshakeConfirmed()) {
626 if (GetNumOpenStreams() > 0) {
627 UMA_HISTOGRAM_BOOLEAN(
628 "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
629 connection()->sent_packet_manager().HasUnackedPackets());
630 UMA_HISTOGRAM_COUNTS(
631 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
632 connection()->sent_packet_manager().consecutive_rto_count());
633 UMA_HISTOGRAM_COUNTS(
634 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
635 connection()->sent_packet_manager().consecutive_tlp_count());
637 if (connection()->sent_packet_manager().HasUnackedPackets()) {
639 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
640 "TimeSinceLastReceived.UnackedPackets",
641 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
644 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
645 "TimeSinceLastReceived.NoUnackedPackets",
646 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
650 UMA_HISTOGRAM_COUNTS(
651 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
652 GetNumOpenStreams());
653 UMA_HISTOGRAM_COUNTS(
654 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
659 if (!IsCryptoHandshakeConfirmed()) {
660 if (error
== QUIC_PUBLIC_RESET
) {
661 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET
);
662 } else if (connection()->GetStats().packets_received
== 0) {
663 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE
);
664 UMA_HISTOGRAM_SPARSE_SLOWLY(
665 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
668 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN
);
669 UMA_HISTOGRAM_SPARSE_SLOWLY(
670 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
675 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
676 connection()->version());
677 NotifyFactoryOfSessionGoingAway();
678 if (!callback_
.is_null()) {
679 base::ResetAndReturn(&callback_
).Run(ERR_QUIC_PROTOCOL_ERROR
);
682 QuicSession::OnConnectionClosed(error
, from_peer
);
683 DCHECK(streams()->empty());
684 CloseAllStreams(ERR_UNEXPECTED
);
685 CloseAllObservers(ERR_UNEXPECTED
);
686 NotifyFactoryOfSessionClosedLater();
689 void QuicClientSession::OnSuccessfulVersionNegotiation(
690 const QuicVersion
& version
) {
691 logger_
->OnSuccessfulVersionNegotiation(version
);
692 QuicSession::OnSuccessfulVersionNegotiation(version
);
695 void QuicClientSession::OnProofValid(
696 const QuicCryptoClientConfig::CachedState
& cached
) {
697 DCHECK(cached
.proof_valid());
703 QuicServerInfo::State
* state
= server_info_
->mutable_state();
705 state
->server_config
= cached
.server_config();
706 state
->source_address_token
= cached
.source_address_token();
707 state
->server_config_sig
= cached
.signature();
708 state
->certs
= cached
.certs();
710 server_info_
->Persist();
713 void QuicClientSession::OnProofVerifyDetailsAvailable(
714 const ProofVerifyDetails
& verify_details
) {
715 const ProofVerifyDetailsChromium
* verify_details_chromium
=
716 reinterpret_cast<const ProofVerifyDetailsChromium
*>(&verify_details
);
717 CertVerifyResult
* result_copy
= new CertVerifyResult
;
718 result_copy
->CopyFrom(verify_details_chromium
->cert_verify_result
);
719 cert_verify_result_
.reset(result_copy
);
720 pinning_failure_log_
= verify_details_chromium
->pinning_failure_log
;
721 logger_
->OnCertificateVerified(*cert_verify_result_
);
724 void QuicClientSession::StartReading() {
728 read_pending_
= true;
729 int rv
= socket_
->Read(read_buffer_
.get(),
730 read_buffer_
->size(),
731 base::Bind(&QuicClientSession::OnReadComplete
,
732 weak_factory_
.GetWeakPtr()));
733 if (rv
== ERR_IO_PENDING
) {
734 num_packets_read_
= 0;
738 if (++num_packets_read_
> 32) {
739 num_packets_read_
= 0;
740 // Data was read, process it.
741 // Schedule the work through the message loop to 1) prevent infinite
742 // recursion and 2) avoid blocking the thread for too long.
743 base::MessageLoop::current()->PostTask(
745 base::Bind(&QuicClientSession::OnReadComplete
,
746 weak_factory_
.GetWeakPtr(), rv
));
752 void QuicClientSession::CloseSessionOnError(int error
) {
753 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error
);
754 CloseSessionOnErrorInner(error
, QUIC_INTERNAL_ERROR
);
755 NotifyFactoryOfSessionClosed();
758 void QuicClientSession::CloseSessionOnErrorInner(int net_error
,
759 QuicErrorCode quic_error
) {
760 if (!callback_
.is_null()) {
761 base::ResetAndReturn(&callback_
).Run(net_error
);
763 CloseAllStreams(net_error
);
764 CloseAllObservers(net_error
);
766 NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR
,
767 NetLog::IntegerCallback("net_error", net_error
));
769 if (connection()->connected())
770 connection()->CloseConnection(quic_error
, false);
771 DCHECK(!connection()->connected());
774 void QuicClientSession::CloseAllStreams(int net_error
) {
775 while (!streams()->empty()) {
776 ReliableQuicStream
* stream
= streams()->begin()->second
;
777 QuicStreamId id
= stream
->id();
778 static_cast<QuicReliableClientStream
*>(stream
)->OnError(net_error
);
783 void QuicClientSession::CloseAllObservers(int net_error
) {
784 while (!observers_
.empty()) {
785 Observer
* observer
= *observers_
.begin();
786 observers_
.erase(observer
);
787 observer
->OnSessionClosed(net_error
);
791 base::Value
* QuicClientSession::GetInfoAsValue(
792 const std::set
<HostPortPair
>& aliases
) {
793 base::DictionaryValue
* dict
= new base::DictionaryValue();
794 dict
->SetString("version", QuicVersionToString(connection()->version()));
795 dict
->SetInteger("open_streams", GetNumOpenStreams());
796 base::ListValue
* stream_list
= new base::ListValue();
797 for (base::hash_map
<QuicStreamId
, QuicDataStream
*>::const_iterator it
798 = streams()->begin();
799 it
!= streams()->end();
801 stream_list
->Append(new base::StringValue(
802 base::Uint64ToString(it
->second
->id())));
804 dict
->Set("active_streams", stream_list
);
806 dict
->SetInteger("total_streams", num_total_streams_
);
807 dict
->SetString("peer_address", peer_address().ToString());
808 dict
->SetString("connection_id", base::Uint64ToString(connection_id()));
809 dict
->SetBoolean("connected", connection()->connected());
810 const QuicConnectionStats
& stats
= connection()->GetStats();
811 dict
->SetInteger("packets_sent", stats
.packets_sent
);
812 dict
->SetInteger("packets_received", stats
.packets_received
);
813 dict
->SetInteger("packets_lost", stats
.packets_lost
);
815 dict
->SetBoolean("secure", GetSSLInfo(&ssl_info
) && ssl_info
.cert
.get());
817 base::ListValue
* alias_list
= new base::ListValue();
818 for (std::set
<HostPortPair
>::const_iterator it
= aliases
.begin();
819 it
!= aliases
.end(); it
++) {
820 alias_list
->Append(new base::StringValue(it
->ToString()));
822 dict
->Set("aliases", alias_list
);
827 base::WeakPtr
<QuicClientSession
> QuicClientSession::GetWeakPtr() {
828 return weak_factory_
.GetWeakPtr();
831 void QuicClientSession::OnReadComplete(int result
) {
832 read_pending_
= false;
834 result
= ERR_CONNECTION_CLOSED
;
837 DVLOG(1) << "Closing session on read error: " << result
;
838 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result
);
839 NotifyFactoryOfSessionGoingAway();
840 CloseSessionOnErrorInner(result
, QUIC_PACKET_READ_ERROR
);
841 NotifyFactoryOfSessionClosedLater();
845 QuicEncryptedPacket
packet(read_buffer_
->data(), result
);
846 IPEndPoint local_address
;
847 IPEndPoint peer_address
;
848 socket_
->GetLocalAddress(&local_address
);
849 socket_
->GetPeerAddress(&peer_address
);
850 // ProcessUdpPacket might result in |this| being deleted, so we
851 // use a weak pointer to be safe.
852 connection()->ProcessUdpPacket(local_address
, peer_address
, packet
);
853 if (!connection()->connected()) {
854 NotifyFactoryOfSessionClosedLater();
860 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
863 stream_factory_
->OnSessionGoingAway(this);
866 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
867 if (!streams()->empty())
868 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER
);
871 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER
);
874 DCHECK_EQ(0u, GetNumOpenStreams());
875 DCHECK(!connection()->connected());
876 base::MessageLoop::current()->PostTask(
878 base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed
,
879 weak_factory_
.GetWeakPtr()));
882 void QuicClientSession::NotifyFactoryOfSessionClosed() {
883 if (!streams()->empty())
884 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED
);
887 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED
);
890 DCHECK_EQ(0u, GetNumOpenStreams());
891 // Will delete |this|.
893 stream_factory_
->OnSessionClosed(this);
896 void QuicClientSession::OnConnectTimeout() {
897 DCHECK(callback_
.is_null());
898 DCHECK(IsEncryptionEstablished());
900 if (IsCryptoHandshakeConfirmed())
903 // TODO(rch): re-enable this code once beta is cut.
904 // if (stream_factory_)
905 // stream_factory_->OnSessionConnectTimeout(this);
906 // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
907 // DCHECK_EQ(0u, GetNumOpenStreams());