Rewrite AndroidSyncSettings to be significantly simpler.
[chromium-blink-merge.git] / net / quic / quic_client_session.cc
blobee87c81cd93217e22bd1d4ee196adbf63b98a10f
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"
31 namespace net {
33 namespace {
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
45 enum Location {
46 DESTRUCTOR = 0,
47 ADD_OBSERVER = 1,
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,
52 NUM_LOCATIONS = 6,
55 void RecordUnexpectedOpenStreams(Location location) {
56 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
57 NUM_LOCATIONS);
60 void RecordUnexpectedObservers(Location location) {
61 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
62 NUM_LOCATIONS);
65 void RecordUnexpectedNotGoingAway(Location location) {
66 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
67 NUM_LOCATIONS);
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
87 enum HandshakeState {
88 STATE_STARTED = 0,
89 STATE_ENCRYPTION_ESTABLISHED = 1,
90 STATE_HANDSHAKE_CONFIRMED = 2,
91 STATE_FAILED = 3,
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);
111 return dict;
114 } // namespace
116 QuicClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
118 QuicClientSession::StreamRequest::~StreamRequest() {
119 CancelRequest();
122 int QuicClientSession::StreamRequest::StartRequest(
123 const base::WeakPtr<QuicClientSession>& session,
124 QuicReliableClientStream** stream,
125 const CompletionCallback& callback) {
126 session_ = session;
127 stream_ = stream;
128 int rv = session_->TryCreateStream(this, stream_);
129 if (rv == ERR_IO_PENDING) {
130 callback_ = callback;
133 return rv;
136 void QuicClientSession::StreamRequest::CancelRequest() {
137 if (session_)
138 session_->CancelRequest(this);
139 session_.reset();
140 callback_.Reset();
143 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
144 QuicReliableClientStream* stream) {
145 session_.reset();
146 *stream_ = stream;
147 ResetAndReturn(&callback_).Run(OK);
150 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
151 session_.reset();
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::TaskRunner* task_runner,
164 NetLog* net_log)
165 : QuicClientSessionBase(connection, config),
166 require_confirmation_(false),
167 stream_factory_(stream_factory),
168 socket_(socket.Pass()),
169 read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
170 transport_security_state_(transport_security_state),
171 server_info_(server_info.Pass()),
172 read_pending_(false),
173 num_total_streams_(0),
174 task_runner_(task_runner),
175 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
176 logger_(new QuicConnectionLogger(this, connection_description, net_log_)),
177 num_packets_read_(0),
178 going_away_(false),
179 weak_factory_(this) {
180 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
181 tracked_objects::ScopedTracker tracking_profile1(
182 FROM_HERE_WITH_EXPLICIT_FUNCTION(
183 "422516 QuicClientSession::QuicClientSession1"));
185 connection->set_debug_visitor(logger_);
186 IPEndPoint address;
187 // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed.
188 tracked_objects::ScopedTracker tracking_profile2(
189 FROM_HERE_WITH_EXPLICIT_FUNCTION(
190 "422516 QuicClientSession::QuicClientSession2"));
191 if (socket && socket->GetLocalAddress(&address) == OK &&
192 address.GetFamily() == ADDRESS_FAMILY_IPV6) {
193 connection->set_max_packet_length(
194 connection->max_packet_length() - kAdditionalOverheadForIPv6);
198 void QuicClientSession::InitializeSession(
199 const QuicServerId& server_id,
200 QuicCryptoClientConfig* crypto_config,
201 QuicCryptoClientStreamFactory* crypto_client_stream_factory) {
202 server_id_ = server_id;
203 crypto_stream_.reset(
204 crypto_client_stream_factory ?
205 crypto_client_stream_factory->CreateQuicCryptoClientStream(
206 server_id, this, crypto_config) :
207 new QuicCryptoClientStream(server_id, this,
208 new ProofVerifyContextChromium(net_log_),
209 crypto_config));
210 QuicClientSessionBase::InitializeSession();
211 // TODO(rch): pass in full host port proxy pair
212 net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION,
213 base::Bind(NetLogQuicClientSessionCallback,
214 &server_id,
215 require_confirmation_));
218 QuicClientSession::~QuicClientSession() {
219 if (!streams()->empty())
220 RecordUnexpectedOpenStreams(DESTRUCTOR);
221 if (!observers_.empty())
222 RecordUnexpectedObservers(DESTRUCTOR);
223 if (!going_away_)
224 RecordUnexpectedNotGoingAway(DESTRUCTOR);
226 while (!streams()->empty() ||
227 !observers_.empty() ||
228 !stream_requests_.empty()) {
229 // The session must be closed before it is destroyed.
230 DCHECK(streams()->empty());
231 CloseAllStreams(ERR_UNEXPECTED);
232 DCHECK(observers_.empty());
233 CloseAllObservers(ERR_UNEXPECTED);
235 connection()->set_debug_visitor(nullptr);
236 net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
238 while (!stream_requests_.empty()) {
239 StreamRequest* request = stream_requests_.front();
240 stream_requests_.pop_front();
241 request->OnRequestCompleteFailure(ERR_ABORTED);
245 if (connection()->connected()) {
246 // Ensure that the connection is closed by the time the session is
247 // destroyed.
248 connection()->CloseConnection(QUIC_INTERNAL_ERROR, false);
251 if (IsEncryptionEstablished())
252 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
253 if (IsCryptoHandshakeConfirmed())
254 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
255 else
256 RecordHandshakeState(STATE_FAILED);
258 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
259 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
260 crypto_stream_->num_sent_client_hellos());
261 if (!IsCryptoHandshakeConfirmed())
262 return;
264 // Sending one client_hello means we had zero handshake-round-trips.
265 int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
267 // Don't bother with these histogram during tests, which mock out
268 // num_sent_client_hellos().
269 if (round_trip_handshakes < 0 || !stream_factory_)
270 return;
272 bool port_selected = stream_factory_->enable_port_selection();
273 SSLInfo ssl_info;
274 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
275 if (port_selected) {
276 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
277 round_trip_handshakes, 0, 3, 4);
278 } else {
279 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
280 round_trip_handshakes, 0, 3, 4);
281 if (require_confirmation_) {
282 UMA_HISTOGRAM_CUSTOM_COUNTS(
283 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
284 round_trip_handshakes, 0, 3, 4);
287 } else {
288 if (port_selected) {
289 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
290 round_trip_handshakes, 0, 3, 4);
291 } else {
292 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
293 round_trip_handshakes, 0, 3, 4);
294 if (require_confirmation_) {
295 UMA_HISTOGRAM_CUSTOM_COUNTS(
296 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
297 round_trip_handshakes, 0, 3, 4);
301 const QuicConnectionStats stats = connection()->GetStats();
302 if (server_info_ && stats.min_rtt_us > 0) {
303 base::TimeTicks wait_for_data_start_time =
304 server_info_->wait_for_data_start_time();
305 base::TimeTicks wait_for_data_end_time =
306 server_info_->wait_for_data_end_time();
307 if (!wait_for_data_start_time.is_null() &&
308 !wait_for_data_end_time.is_null()) {
309 base::TimeDelta wait_time =
310 wait_for_data_end_time - wait_for_data_start_time;
311 const base::HistogramBase::Sample kMaxWaitToRtt = 1000;
312 base::HistogramBase::Sample wait_to_rtt =
313 static_cast<base::HistogramBase::Sample>(
314 100 * wait_time.InMicroseconds() / stats.min_rtt_us);
315 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicServerInfo.WaitForDataReadyToRtt",
316 wait_to_rtt, 0, kMaxWaitToRtt, 50);
320 if (stats.max_sequence_reordering == 0)
321 return;
322 const base::HistogramBase::Sample kMaxReordering = 100;
323 base::HistogramBase::Sample reordering = kMaxReordering;
324 if (stats.min_rtt_us > 0) {
325 reordering = static_cast<base::HistogramBase::Sample>(
326 100 * stats.max_time_reordering_us / stats.min_rtt_us);
328 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime",
329 reordering, 0, kMaxReordering, 50);
330 if (stats.min_rtt_us > 100 * 1000) {
331 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
332 reordering, 0, kMaxReordering, 50);
334 UMA_HISTOGRAM_COUNTS(
335 "Net.QuicSession.MaxReordering",
336 static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
339 void QuicClientSession::OnStreamFrames(
340 const std::vector<QuicStreamFrame>& frames) {
341 // Record total number of stream frames.
342 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames.size());
344 // Record number of frames per stream in packet.
345 typedef std::map<QuicStreamId, size_t> FrameCounter;
346 FrameCounter frames_per_stream;
347 for (size_t i = 0; i < frames.size(); ++i) {
348 frames_per_stream[frames[i].stream_id]++;
350 for (FrameCounter::const_iterator it = frames_per_stream.begin();
351 it != frames_per_stream.end(); ++it) {
352 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
353 it->second);
356 return QuicSession::OnStreamFrames(frames);
359 void QuicClientSession::AddObserver(Observer* observer) {
360 if (going_away_) {
361 RecordUnexpectedObservers(ADD_OBSERVER);
362 observer->OnSessionClosed(ERR_UNEXPECTED);
363 return;
366 DCHECK(!ContainsKey(observers_, observer));
367 observers_.insert(observer);
370 void QuicClientSession::RemoveObserver(Observer* observer) {
371 DCHECK(ContainsKey(observers_, observer));
372 observers_.erase(observer);
375 int QuicClientSession::TryCreateStream(StreamRequest* request,
376 QuicReliableClientStream** stream) {
377 if (!crypto_stream_->encryption_established()) {
378 DLOG(DFATAL) << "Encryption not established.";
379 return ERR_CONNECTION_CLOSED;
382 if (goaway_received()) {
383 DVLOG(1) << "Going away.";
384 return ERR_CONNECTION_CLOSED;
387 if (!connection()->connected()) {
388 DVLOG(1) << "Already closed.";
389 return ERR_CONNECTION_CLOSED;
392 if (going_away_) {
393 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
394 return ERR_CONNECTION_CLOSED;
397 if (GetNumOpenStreams() < get_max_open_streams()) {
398 *stream = CreateOutgoingReliableStreamImpl();
399 return OK;
402 stream_requests_.push_back(request);
403 return ERR_IO_PENDING;
406 void QuicClientSession::CancelRequest(StreamRequest* request) {
407 // Remove |request| from the queue while preserving the order of the
408 // other elements.
409 StreamRequestQueue::iterator it =
410 std::find(stream_requests_.begin(), stream_requests_.end(), request);
411 if (it != stream_requests_.end()) {
412 it = stream_requests_.erase(it);
416 QuicReliableClientStream* QuicClientSession::CreateOutgoingDataStream() {
417 if (!crypto_stream_->encryption_established()) {
418 DVLOG(1) << "Encryption not active so no outgoing stream created.";
419 return nullptr;
421 if (GetNumOpenStreams() >= get_max_open_streams()) {
422 DVLOG(1) << "Failed to create a new outgoing stream. "
423 << "Already " << GetNumOpenStreams() << " open.";
424 return nullptr;
426 if (goaway_received()) {
427 DVLOG(1) << "Failed to create a new outgoing stream. "
428 << "Already received goaway.";
429 return nullptr;
431 if (going_away_) {
432 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
433 return nullptr;
435 return CreateOutgoingReliableStreamImpl();
438 QuicReliableClientStream*
439 QuicClientSession::CreateOutgoingReliableStreamImpl() {
440 DCHECK(connection()->connected());
441 QuicReliableClientStream* stream =
442 new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
443 ActivateStream(stream);
444 ++num_total_streams_;
445 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
446 return stream;
449 QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
450 return crypto_stream_.get();
453 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
454 // we learn about SSL info (sync vs async vs cached).
455 bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
456 ssl_info->Reset();
457 if (!cert_verify_result_) {
458 return false;
461 ssl_info->cert_status = cert_verify_result_->cert_status;
462 ssl_info->cert = cert_verify_result_->verified_cert;
464 // TODO(wtc): Define QUIC "cipher suites".
465 // Report the TLS cipher suite that most closely resembles the crypto
466 // parameters of the QUIC connection.
467 QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
468 uint16 cipher_suite;
469 int security_bits;
470 switch (aead) {
471 case kAESG:
472 cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
473 security_bits = 128;
474 break;
475 case kCC12:
476 cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
477 security_bits = 256;
478 break;
479 default:
480 NOTREACHED();
481 return false;
483 int ssl_connection_status = 0;
484 ssl_connection_status |= cipher_suite;
485 ssl_connection_status |=
486 (SSL_CONNECTION_VERSION_QUIC & SSL_CONNECTION_VERSION_MASK) <<
487 SSL_CONNECTION_VERSION_SHIFT;
489 ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
490 ssl_info->is_issued_by_known_root =
491 cert_verify_result_->is_issued_by_known_root;
493 ssl_info->connection_status = ssl_connection_status;
494 ssl_info->client_cert_sent = false;
495 ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent();
496 ssl_info->security_bits = security_bits;
497 ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
498 ssl_info->pinning_failure_log = pinning_failure_log_;
499 return true;
502 int QuicClientSession::CryptoConnect(bool require_confirmation,
503 const CompletionCallback& callback) {
504 require_confirmation_ = require_confirmation;
505 handshake_start_ = base::TimeTicks::Now();
506 RecordHandshakeState(STATE_STARTED);
507 DCHECK(flow_controller());
508 crypto_stream_->CryptoConnect();
510 if (IsCryptoHandshakeConfirmed())
511 return OK;
513 // Unless we require handshake confirmation, activate the session if
514 // we have established initial encryption.
515 if (!require_confirmation_ && IsEncryptionEstablished()) {
516 // To mitigate the effects of hanging 0-RTT connections, set up a timer to
517 // cancel any requests, if the handshake takes too long.
518 task_runner_->PostDelayedTask(
519 FROM_HERE,
520 base::Bind(&QuicClientSession::OnConnectTimeout,
521 weak_factory_.GetWeakPtr()),
522 base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs));
523 return OK;
527 callback_ = callback;
528 return ERR_IO_PENDING;
531 int QuicClientSession::ResumeCryptoConnect(const CompletionCallback& callback) {
533 if (IsCryptoHandshakeConfirmed())
534 return OK;
536 if (!connection()->connected())
537 return ERR_QUIC_HANDSHAKE_FAILED;
539 callback_ = callback;
540 return ERR_IO_PENDING;
543 int QuicClientSession::GetNumSentClientHellos() const {
544 return crypto_stream_->num_sent_client_hellos();
547 bool QuicClientSession::CanPool(const std::string& hostname,
548 PrivacyMode privacy_mode) const {
549 DCHECK(connection()->connected());
550 if (privacy_mode != server_id_.privacy_mode()) {
551 // Privacy mode must always match.
552 return false;
554 SSLInfo ssl_info;
555 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
556 // We can always pool with insecure QUIC sessions.
557 return true;
560 return SpdySession::CanPool(transport_security_state_, ssl_info,
561 server_id_.host(), hostname);
564 QuicDataStream* QuicClientSession::CreateIncomingDataStream(
565 QuicStreamId id) {
566 DLOG(ERROR) << "Server push not supported";
567 return nullptr;
570 void QuicClientSession::CloseStream(QuicStreamId stream_id) {
571 ReliableQuicStream* stream = GetStream(stream_id);
572 if (stream) {
573 logger_->UpdateReceivedFrameCounts(
574 stream_id, stream->num_frames_received(),
575 stream->num_duplicate_frames_received());
577 QuicSession::CloseStream(stream_id);
578 OnClosedStream();
581 void QuicClientSession::SendRstStream(QuicStreamId id,
582 QuicRstStreamErrorCode error,
583 QuicStreamOffset bytes_written) {
584 QuicSession::SendRstStream(id, error, bytes_written);
585 OnClosedStream();
588 void QuicClientSession::OnClosedStream() {
589 if (GetNumOpenStreams() < get_max_open_streams() &&
590 !stream_requests_.empty() &&
591 crypto_stream_->encryption_established() &&
592 !goaway_received() &&
593 !going_away_ &&
594 connection()->connected()) {
595 StreamRequest* request = stream_requests_.front();
596 stream_requests_.pop_front();
597 request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
600 if (GetNumOpenStreams() == 0) {
601 stream_factory_->OnIdleSession(this);
605 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
606 if (!callback_.is_null() &&
607 (!require_confirmation_ ||
608 event == HANDSHAKE_CONFIRMED || event == ENCRYPTION_REESTABLISHED)) {
609 // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
610 // could be called because there are no error events in CryptoHandshakeEvent
611 // enum. If error events are added to CryptoHandshakeEvent, then the
612 // following code needs to changed.
613 base::ResetAndReturn(&callback_).Run(OK);
615 if (event == HANDSHAKE_CONFIRMED) {
616 UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime",
617 base::TimeTicks::Now() - handshake_start_);
618 if (server_info_) {
619 // 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()) {
626 UMA_HISTOGRAM_TIMES(
627 "Net.QuicServerInfo.WaitForDataReady.HandshakeConfirmedTime",
628 base::TimeTicks::Now() - wait_for_data_start_time);
632 ObserverSet::iterator it = observers_.begin();
633 while (it != observers_.end()) {
634 Observer* observer = *it;
635 ++it;
636 observer->OnCryptoHandshakeConfirmed();
638 if (server_info_)
639 server_info_->OnExternalCacheHit();
641 QuicSession::OnCryptoHandshakeEvent(event);
644 void QuicClientSession::OnCryptoHandshakeMessageSent(
645 const CryptoHandshakeMessage& message) {
646 logger_->OnCryptoHandshakeMessageSent(message);
649 void QuicClientSession::OnCryptoHandshakeMessageReceived(
650 const CryptoHandshakeMessage& message) {
651 logger_->OnCryptoHandshakeMessageReceived(message);
654 void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
655 bool from_peer) {
656 DCHECK(!connection()->connected());
657 logger_->OnConnectionClosed(error, from_peer);
658 if (from_peer) {
659 UMA_HISTOGRAM_SPARSE_SLOWLY(
660 "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
661 } else {
662 UMA_HISTOGRAM_SPARSE_SLOWLY(
663 "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
666 if (error == QUIC_CONNECTION_TIMED_OUT) {
667 UMA_HISTOGRAM_COUNTS(
668 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
669 GetNumOpenStreams());
670 if (IsCryptoHandshakeConfirmed()) {
671 if (GetNumOpenStreams() > 0) {
672 UMA_HISTOGRAM_BOOLEAN(
673 "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
674 connection()->sent_packet_manager().HasUnackedPackets());
675 UMA_HISTOGRAM_COUNTS(
676 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
677 connection()->sent_packet_manager().consecutive_rto_count());
678 UMA_HISTOGRAM_COUNTS(
679 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
680 connection()->sent_packet_manager().consecutive_tlp_count());
682 if (connection()->sent_packet_manager().HasUnackedPackets()) {
683 UMA_HISTOGRAM_TIMES(
684 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
685 "TimeSinceLastReceived.UnackedPackets",
686 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
687 } else {
688 UMA_HISTOGRAM_TIMES(
689 "Net.QuicSession.LocallyTimedOutWithOpenStreams."
690 "TimeSinceLastReceived.NoUnackedPackets",
691 NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
694 } else {
695 UMA_HISTOGRAM_COUNTS(
696 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
697 GetNumOpenStreams());
698 UMA_HISTOGRAM_COUNTS(
699 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
700 num_total_streams_);
704 if (!IsCryptoHandshakeConfirmed()) {
705 if (error == QUIC_PUBLIC_RESET) {
706 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
707 } else if (connection()->GetStats().packets_received == 0) {
708 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
709 UMA_HISTOGRAM_SPARSE_SLOWLY(
710 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
711 error);
712 } else {
713 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
714 UMA_HISTOGRAM_SPARSE_SLOWLY(
715 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
716 error);
720 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
721 connection()->version());
722 NotifyFactoryOfSessionGoingAway();
723 if (!callback_.is_null()) {
724 base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
726 socket_->Close();
727 QuicSession::OnConnectionClosed(error, from_peer);
728 DCHECK(streams()->empty());
729 CloseAllStreams(ERR_UNEXPECTED);
730 CloseAllObservers(ERR_UNEXPECTED);
731 NotifyFactoryOfSessionClosedLater();
734 void QuicClientSession::OnSuccessfulVersionNegotiation(
735 const QuicVersion& version) {
736 logger_->OnSuccessfulVersionNegotiation(version);
737 QuicSession::OnSuccessfulVersionNegotiation(version);
740 void QuicClientSession::OnProofValid(
741 const QuicCryptoClientConfig::CachedState& cached) {
742 DCHECK(cached.proof_valid());
744 if (!server_info_) {
745 return;
748 QuicServerInfo::State* state = server_info_->mutable_state();
750 state->server_config = cached.server_config();
751 state->source_address_token = cached.source_address_token();
752 state->server_config_sig = cached.signature();
753 state->certs = cached.certs();
755 server_info_->Persist();
758 void QuicClientSession::OnProofVerifyDetailsAvailable(
759 const ProofVerifyDetails& verify_details) {
760 const ProofVerifyDetailsChromium* verify_details_chromium =
761 reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
762 CertVerifyResult* result_copy = new CertVerifyResult;
763 result_copy->CopyFrom(verify_details_chromium->cert_verify_result);
764 cert_verify_result_.reset(result_copy);
765 pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
766 logger_->OnCertificateVerified(*cert_verify_result_);
769 void QuicClientSession::StartReading() {
770 if (read_pending_) {
771 return;
773 read_pending_ = true;
774 int rv = socket_->Read(read_buffer_.get(),
775 read_buffer_->size(),
776 base::Bind(&QuicClientSession::OnReadComplete,
777 weak_factory_.GetWeakPtr()));
778 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING);
779 if (rv == ERR_IO_PENDING) {
780 num_packets_read_ = 0;
781 return;
784 if (++num_packets_read_ > 32) {
785 num_packets_read_ = 0;
786 // Data was read, process it.
787 // Schedule the work through the message loop to 1) prevent infinite
788 // recursion and 2) avoid blocking the thread for too long.
789 base::MessageLoop::current()->PostTask(
790 FROM_HERE,
791 base::Bind(&QuicClientSession::OnReadComplete,
792 weak_factory_.GetWeakPtr(), rv));
793 } else {
794 OnReadComplete(rv);
798 void QuicClientSession::CloseSessionOnError(int error) {
799 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
800 CloseSessionOnErrorInner(error, QUIC_INTERNAL_ERROR);
801 NotifyFactoryOfSessionClosed();
804 void QuicClientSession::CloseSessionOnErrorInner(int net_error,
805 QuicErrorCode quic_error) {
806 if (!callback_.is_null()) {
807 base::ResetAndReturn(&callback_).Run(net_error);
809 CloseAllStreams(net_error);
810 CloseAllObservers(net_error);
811 net_log_.AddEvent(
812 NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
813 NetLog::IntegerCallback("net_error", net_error));
815 if (connection()->connected())
816 connection()->CloseConnection(quic_error, false);
817 DCHECK(!connection()->connected());
820 void QuicClientSession::CloseAllStreams(int net_error) {
821 while (!streams()->empty()) {
822 ReliableQuicStream* stream = streams()->begin()->second;
823 QuicStreamId id = stream->id();
824 static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
825 CloseStream(id);
829 void QuicClientSession::CloseAllObservers(int net_error) {
830 while (!observers_.empty()) {
831 Observer* observer = *observers_.begin();
832 observers_.erase(observer);
833 observer->OnSessionClosed(net_error);
837 base::Value* QuicClientSession::GetInfoAsValue(
838 const std::set<HostPortPair>& aliases) {
839 base::DictionaryValue* dict = new base::DictionaryValue();
840 dict->SetString("version", QuicVersionToString(connection()->version()));
841 dict->SetInteger("open_streams", GetNumOpenStreams());
842 base::ListValue* stream_list = new base::ListValue();
843 for (base::hash_map<QuicStreamId, QuicDataStream*>::const_iterator it
844 = streams()->begin();
845 it != streams()->end();
846 ++it) {
847 stream_list->Append(new base::StringValue(
848 base::Uint64ToString(it->second->id())));
850 dict->Set("active_streams", stream_list);
852 dict->SetInteger("total_streams", num_total_streams_);
853 dict->SetString("peer_address", peer_address().ToString());
854 dict->SetString("connection_id", base::Uint64ToString(connection_id()));
855 dict->SetBoolean("connected", connection()->connected());
856 const QuicConnectionStats& stats = connection()->GetStats();
857 dict->SetInteger("packets_sent", stats.packets_sent);
858 dict->SetInteger("packets_received", stats.packets_received);
859 dict->SetInteger("packets_lost", stats.packets_lost);
860 SSLInfo ssl_info;
861 dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
863 base::ListValue* alias_list = new base::ListValue();
864 for (std::set<HostPortPair>::const_iterator it = aliases.begin();
865 it != aliases.end(); it++) {
866 alias_list->Append(new base::StringValue(it->ToString()));
868 dict->Set("aliases", alias_list);
870 return dict;
873 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
874 return weak_factory_.GetWeakPtr();
877 void QuicClientSession::OnReadComplete(int result) {
878 read_pending_ = false;
879 if (result == 0)
880 result = ERR_CONNECTION_CLOSED;
882 if (result < 0) {
883 DVLOG(1) << "Closing session on read error: " << result;
884 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
885 NotifyFactoryOfSessionGoingAway();
886 CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
887 NotifyFactoryOfSessionClosedLater();
888 return;
891 QuicEncryptedPacket packet(read_buffer_->data(), result);
892 IPEndPoint local_address;
893 IPEndPoint peer_address;
894 socket_->GetLocalAddress(&local_address);
895 socket_->GetPeerAddress(&peer_address);
896 // ProcessUdpPacket might result in |this| being deleted, so we
897 // use a weak pointer to be safe.
898 connection()->ProcessUdpPacket(local_address, peer_address, packet);
899 if (!connection()->connected()) {
900 NotifyFactoryOfSessionClosedLater();
901 return;
903 StartReading();
906 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
907 going_away_ = true;
908 if (stream_factory_)
909 stream_factory_->OnSessionGoingAway(this);
912 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
913 if (!streams()->empty())
914 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
916 if (!going_away_)
917 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
919 going_away_ = true;
920 DCHECK_EQ(0u, GetNumOpenStreams());
921 DCHECK(!connection()->connected());
922 base::MessageLoop::current()->PostTask(
923 FROM_HERE,
924 base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
925 weak_factory_.GetWeakPtr()));
928 void QuicClientSession::NotifyFactoryOfSessionClosed() {
929 if (!streams()->empty())
930 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
932 if (!going_away_)
933 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
935 going_away_ = true;
936 DCHECK_EQ(0u, GetNumOpenStreams());
937 // Will delete |this|.
938 if (stream_factory_)
939 stream_factory_->OnSessionClosed(this);
942 void QuicClientSession::OnConnectTimeout() {
943 DCHECK(callback_.is_null());
944 DCHECK(IsEncryptionEstablished());
946 if (IsCryptoHandshakeConfirmed())
947 return;
949 // TODO(rch): re-enable this code once beta is cut.
950 // if (stream_factory_)
951 // stream_factory_->OnSessionConnectTimeout(this);
952 // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
953 // DCHECK_EQ(0u, GetNumOpenStreams());
956 } // namespace net