MacViews: Get c/b/ui/views/tabs to build on Mac
[chromium-blink-merge.git] / net / quic / quic_client_session.cc
blob60bcbb50b386a8ba1f588cf1dcee635df78c346f
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/http/transport_security_state.h"
17 #include "net/quic/crypto/proof_verifier_chromium.h"
18 #include "net/quic/crypto/quic_server_info.h"
19 #include "net/quic/quic_connection_helper.h"
20 #include "net/quic/quic_crypto_client_stream_factory.h"
21 #include "net/quic/quic_server_id.h"
22 #include "net/quic/quic_stream_factory.h"
23 #include "net/spdy/spdy_session.h"
24 #include "net/ssl/channel_id_service.h"
25 #include "net/ssl/ssl_connection_status_flags.h"
26 #include "net/ssl/ssl_info.h"
27 #include "net/udp/datagram_client_socket.h"
29 namespace net {
31 namespace {
33 // The length of time to wait for a 0-RTT handshake to complete
34 // before allowing the requests to possibly proceed over TCP.
35 const int k0RttHandshakeTimeoutMs = 300;
37 // Histograms for tracking down the crashes from http://crbug.com/354669
38 // Note: these values must be kept in sync with the corresponding values in:
39 // tools/metrics/histograms/histograms.xml
40 enum Location {
41 DESTRUCTOR = 0,
42 ADD_OBSERVER = 1,
43 TRY_CREATE_STREAM = 2,
44 CREATE_OUTGOING_RELIABLE_STREAM = 3,
45 NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER = 4,
46 NOTIFY_FACTORY_OF_SESSION_CLOSED = 5,
47 NUM_LOCATIONS = 6,
50 void RecordUnexpectedOpenStreams(Location location) {
51 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
52 NUM_LOCATIONS);
55 void RecordUnexpectedObservers(Location location) {
56 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
57 NUM_LOCATIONS);
60 void RecordUnexpectedNotGoingAway(Location location) {
61 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
62 NUM_LOCATIONS);
65 // Histogram for recording the different reasons that a QUIC session is unable
66 // to complete the handshake.
67 enum HandshakeFailureReason {
68 HANDSHAKE_FAILURE_UNKNOWN = 0,
69 HANDSHAKE_FAILURE_BLACK_HOLE = 1,
70 HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
71 NUM_HANDSHAKE_FAILURE_REASONS = 3,
74 void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
75 UMA_HISTOGRAM_ENUMERATION(
76 "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason",
77 reason, NUM_HANDSHAKE_FAILURE_REASONS);
80 // Note: these values must be kept in sync with the corresponding values in:
81 // tools/metrics/histograms/histograms.xml
82 enum HandshakeState {
83 STATE_STARTED = 0,
84 STATE_ENCRYPTION_ESTABLISHED = 1,
85 STATE_HANDSHAKE_CONFIRMED = 2,
86 STATE_FAILED = 3,
87 NUM_HANDSHAKE_STATES = 4
90 void RecordHandshakeState(HandshakeState state) {
91 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
92 NUM_HANDSHAKE_STATES);
95 base::Value* NetLogQuicClientSessionCallback(
96 const QuicServerId* server_id,
97 bool require_confirmation,
98 NetLog::LogLevel /* log_level */) {
99 base::DictionaryValue* dict = new base::DictionaryValue();
100 dict->SetString("host", server_id->host());
101 dict->SetInteger("port", server_id->port());
102 dict->SetBoolean("is_https", server_id->is_https());
103 dict->SetBoolean("require_confirmation", require_confirmation);
104 return dict;
107 } // namespace
109 QuicClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
111 QuicClientSession::StreamRequest::~StreamRequest() {
112 CancelRequest();
115 int QuicClientSession::StreamRequest::StartRequest(
116 const base::WeakPtr<QuicClientSession>& session,
117 QuicReliableClientStream** stream,
118 const CompletionCallback& callback) {
119 session_ = session;
120 stream_ = stream;
121 int rv = session_->TryCreateStream(this, stream_);
122 if (rv == ERR_IO_PENDING) {
123 callback_ = callback;
126 return rv;
129 void QuicClientSession::StreamRequest::CancelRequest() {
130 if (session_)
131 session_->CancelRequest(this);
132 session_.reset();
133 callback_.Reset();
136 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
137 QuicReliableClientStream* stream) {
138 session_.reset();
139 *stream_ = stream;
140 ResetAndReturn(&callback_).Run(OK);
143 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
144 session_.reset();
145 ResetAndReturn(&callback_).Run(rv);
148 QuicClientSession::QuicClientSession(
149 QuicConnection* connection,
150 scoped_ptr<DatagramClientSocket> socket,
151 QuicStreamFactory* stream_factory,
152 TransportSecurityState* transport_security_state,
153 scoped_ptr<QuicServerInfo> server_info,
154 const QuicConfig& config,
155 base::TaskRunner* task_runner,
156 NetLog* net_log)
157 : QuicClientSessionBase(connection, config),
158 require_confirmation_(false),
159 stream_factory_(stream_factory),
160 socket_(socket.Pass()),
161 read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
162 transport_security_state_(transport_security_state),
163 server_info_(server_info.Pass()),
164 read_pending_(false),
165 num_total_streams_(0),
166 task_runner_(task_runner),
167 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
168 logger_(new QuicConnectionLogger(this, net_log_)),
169 num_packets_read_(0),
170 going_away_(false),
171 weak_factory_(this) {
172 connection->set_debug_visitor(logger_);
175 void QuicClientSession::InitializeSession(
176 const QuicServerId& server_id,
177 QuicCryptoClientConfig* crypto_config,
178 QuicCryptoClientStreamFactory* crypto_client_stream_factory) {
179 server_host_port_ = server_id.host_port_pair();
180 crypto_stream_.reset(
181 crypto_client_stream_factory ?
182 crypto_client_stream_factory->CreateQuicCryptoClientStream(
183 server_id, this, crypto_config) :
184 new QuicCryptoClientStream(server_id, this,
185 new ProofVerifyContextChromium(net_log_),
186 crypto_config));
187 QuicClientSessionBase::InitializeSession();
188 // TODO(rch): pass in full host port proxy pair
189 net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION,
190 base::Bind(NetLogQuicClientSessionCallback,
191 &server_id,
192 require_confirmation_));
195 QuicClientSession::~QuicClientSession() {
196 if (!streams()->empty())
197 RecordUnexpectedOpenStreams(DESTRUCTOR);
198 if (!observers_.empty())
199 RecordUnexpectedObservers(DESTRUCTOR);
200 if (!going_away_)
201 RecordUnexpectedNotGoingAway(DESTRUCTOR);
203 while (!streams()->empty() ||
204 !observers_.empty() ||
205 !stream_requests_.empty()) {
206 // The session must be closed before it is destroyed.
207 DCHECK(streams()->empty());
208 CloseAllStreams(ERR_UNEXPECTED);
209 DCHECK(observers_.empty());
210 CloseAllObservers(ERR_UNEXPECTED);
212 connection()->set_debug_visitor(nullptr);
213 net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
215 while (!stream_requests_.empty()) {
216 StreamRequest* request = stream_requests_.front();
217 stream_requests_.pop_front();
218 request->OnRequestCompleteFailure(ERR_ABORTED);
222 if (connection()->connected()) {
223 // Ensure that the connection is closed by the time the session is
224 // destroyed.
225 connection()->CloseConnection(QUIC_INTERNAL_ERROR, false);
228 if (IsEncryptionEstablished())
229 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
230 if (IsCryptoHandshakeConfirmed())
231 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
232 else
233 RecordHandshakeState(STATE_FAILED);
235 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
236 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
237 crypto_stream_->num_sent_client_hellos());
238 if (!IsCryptoHandshakeConfirmed())
239 return;
241 // Sending one client_hello means we had zero handshake-round-trips.
242 int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
244 // Don't bother with these histogram during tests, which mock out
245 // num_sent_client_hellos().
246 if (round_trip_handshakes < 0 || !stream_factory_)
247 return;
249 bool port_selected = stream_factory_->enable_port_selection();
250 SSLInfo ssl_info;
251 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
252 if (port_selected) {
253 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
254 round_trip_handshakes, 0, 3, 4);
255 } else {
256 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
257 round_trip_handshakes, 0, 3, 4);
258 if (require_confirmation_) {
259 UMA_HISTOGRAM_CUSTOM_COUNTS(
260 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
261 round_trip_handshakes, 0, 3, 4);
264 } else {
265 if (port_selected) {
266 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
267 round_trip_handshakes, 0, 3, 4);
268 } else {
269 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
270 round_trip_handshakes, 0, 3, 4);
271 if (require_confirmation_) {
272 UMA_HISTOGRAM_CUSTOM_COUNTS(
273 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
274 round_trip_handshakes, 0, 3, 4);
278 const QuicConnectionStats stats = connection()->GetStats();
279 if (stats.max_sequence_reordering == 0)
280 return;
281 const base::HistogramBase::Sample kMaxReordering = 100;
282 base::HistogramBase::Sample reordering = kMaxReordering;
283 if (stats.min_rtt_us > 0) {
284 reordering = static_cast<base::HistogramBase::Sample>(
285 100 * stats.max_time_reordering_us / stats.min_rtt_us);
287 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime",
288 reordering, 0, kMaxReordering, 50);
289 if (stats.min_rtt_us > 100 * 1000) {
290 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
291 reordering, 0, kMaxReordering, 50);
293 UMA_HISTOGRAM_COUNTS("Net.QuicSession.MaxReordering",
294 stats.max_sequence_reordering);
297 void QuicClientSession::OnStreamFrames(
298 const std::vector<QuicStreamFrame>& frames) {
299 // Record total number of stream frames.
300 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames.size());
302 // Record number of frames per stream in packet.
303 typedef std::map<QuicStreamId, size_t> FrameCounter;
304 FrameCounter frames_per_stream;
305 for (size_t i = 0; i < frames.size(); ++i) {
306 frames_per_stream[frames[i].stream_id]++;
308 for (FrameCounter::const_iterator it = frames_per_stream.begin();
309 it != frames_per_stream.end(); ++it) {
310 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
311 it->second);
314 return QuicSession::OnStreamFrames(frames);
317 void QuicClientSession::AddObserver(Observer* observer) {
318 if (going_away_) {
319 RecordUnexpectedObservers(ADD_OBSERVER);
320 observer->OnSessionClosed(ERR_UNEXPECTED);
321 return;
324 DCHECK(!ContainsKey(observers_, observer));
325 observers_.insert(observer);
328 void QuicClientSession::RemoveObserver(Observer* observer) {
329 DCHECK(ContainsKey(observers_, observer));
330 observers_.erase(observer);
333 int QuicClientSession::TryCreateStream(StreamRequest* request,
334 QuicReliableClientStream** stream) {
335 if (!crypto_stream_->encryption_established()) {
336 DLOG(DFATAL) << "Encryption not established.";
337 return ERR_CONNECTION_CLOSED;
340 if (goaway_received()) {
341 DVLOG(1) << "Going away.";
342 return ERR_CONNECTION_CLOSED;
345 if (!connection()->connected()) {
346 DVLOG(1) << "Already closed.";
347 return ERR_CONNECTION_CLOSED;
350 if (going_away_) {
351 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
352 return ERR_CONNECTION_CLOSED;
355 if (GetNumOpenStreams() < get_max_open_streams()) {
356 *stream = CreateOutgoingReliableStreamImpl();
357 return OK;
360 stream_requests_.push_back(request);
361 return ERR_IO_PENDING;
364 void QuicClientSession::CancelRequest(StreamRequest* request) {
365 // Remove |request| from the queue while preserving the order of the
366 // other elements.
367 StreamRequestQueue::iterator it =
368 std::find(stream_requests_.begin(), stream_requests_.end(), request);
369 if (it != stream_requests_.end()) {
370 it = stream_requests_.erase(it);
374 QuicReliableClientStream* QuicClientSession::CreateOutgoingDataStream() {
375 if (!crypto_stream_->encryption_established()) {
376 DVLOG(1) << "Encryption not active so no outgoing stream created.";
377 return nullptr;
379 if (GetNumOpenStreams() >= get_max_open_streams()) {
380 DVLOG(1) << "Failed to create a new outgoing stream. "
381 << "Already " << GetNumOpenStreams() << " open.";
382 return nullptr;
384 if (goaway_received()) {
385 DVLOG(1) << "Failed to create a new outgoing stream. "
386 << "Already received goaway.";
387 return nullptr;
389 if (going_away_) {
390 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
391 return nullptr;
393 return CreateOutgoingReliableStreamImpl();
396 QuicReliableClientStream*
397 QuicClientSession::CreateOutgoingReliableStreamImpl() {
398 DCHECK(connection()->connected());
399 QuicReliableClientStream* stream =
400 new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
401 ActivateStream(stream);
402 ++num_total_streams_;
403 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
404 return stream;
407 QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
408 return crypto_stream_.get();
411 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
412 // we learn about SSL info (sync vs async vs cached).
413 bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
414 ssl_info->Reset();
415 if (!cert_verify_result_) {
416 return false;
419 ssl_info->cert_status = cert_verify_result_->cert_status;
420 ssl_info->cert = cert_verify_result_->verified_cert;
422 // TODO(wtc): Define QUIC "cipher suites".
423 // Report the TLS cipher suite that most closely resembles the crypto
424 // parameters of the QUIC connection.
425 QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
426 int cipher_suite;
427 int security_bits;
428 switch (aead) {
429 case kAESG:
430 cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
431 security_bits = 128;
432 break;
433 case kCC12:
434 cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
435 security_bits = 256;
436 break;
437 default:
438 NOTREACHED();
439 return false;
441 int ssl_connection_status = 0;
442 ssl_connection_status |=
443 (cipher_suite & SSL_CONNECTION_CIPHERSUITE_MASK) <<
444 SSL_CONNECTION_CIPHERSUITE_SHIFT;
445 ssl_connection_status |=
446 (SSL_CONNECTION_VERSION_QUIC & SSL_CONNECTION_VERSION_MASK) <<
447 SSL_CONNECTION_VERSION_SHIFT;
449 ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
450 ssl_info->is_issued_by_known_root =
451 cert_verify_result_->is_issued_by_known_root;
453 ssl_info->connection_status = ssl_connection_status;
454 ssl_info->client_cert_sent = false;
455 ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent();
456 ssl_info->security_bits = security_bits;
457 ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
458 ssl_info->pinning_failure_log = pinning_failure_log_;
459 return true;
462 int QuicClientSession::CryptoConnect(bool require_confirmation,
463 const CompletionCallback& callback) {
464 require_confirmation_ = require_confirmation;
465 handshake_start_ = base::TimeTicks::Now();
466 RecordHandshakeState(STATE_STARTED);
467 DCHECK(flow_controller());
468 if (!crypto_stream_->CryptoConnect()) {
469 // TODO(wtc): change crypto_stream_.CryptoConnect() to return a
470 // QuicErrorCode and map it to a net error code.
471 return ERR_CONNECTION_FAILED;
474 if (IsCryptoHandshakeConfirmed())
475 return OK;
477 // Unless we require handshake confirmation, activate the session if
478 // we have established initial encryption.
479 if (!require_confirmation_ && IsEncryptionEstablished()) {
480 // To mitigate the effects of hanging 0-RTT connections, set up a timer to
481 // cancel any requests, if the handshake takes too long.
482 task_runner_->PostDelayedTask(
483 FROM_HERE,
484 base::Bind(&QuicClientSession::OnConnectTimeout,
485 weak_factory_.GetWeakPtr()),
486 base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs));
487 return OK;
491 callback_ = callback;
492 return ERR_IO_PENDING;
495 int QuicClientSession::ResumeCryptoConnect(const CompletionCallback& callback) {
497 if (IsCryptoHandshakeConfirmed())
498 return OK;
500 if (!connection()->connected())
501 return ERR_QUIC_HANDSHAKE_FAILED;
503 callback_ = callback;
504 return ERR_IO_PENDING;
507 int QuicClientSession::GetNumSentClientHellos() const {
508 return crypto_stream_->num_sent_client_hellos();
511 bool QuicClientSession::CanPool(const std::string& hostname) const {
512 DCHECK(connection()->connected());
513 SSLInfo ssl_info;
514 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
515 // We can always pool with insecure QUIC sessions.
516 return true;
519 return SpdySession::CanPool(transport_security_state_, ssl_info,
520 server_host_port_.host(), hostname);
523 QuicDataStream* QuicClientSession::CreateIncomingDataStream(
524 QuicStreamId id) {
525 DLOG(ERROR) << "Server push not supported";
526 return nullptr;
529 void QuicClientSession::CloseStream(QuicStreamId stream_id) {
530 ReliableQuicStream* stream = GetStream(stream_id);
531 if (stream) {
532 logger_->UpdateReceivedFrameCounts(
533 stream_id, stream->num_frames_received(),
534 stream->num_duplicate_frames_received());
536 QuicSession::CloseStream(stream_id);
537 OnClosedStream();
540 void QuicClientSession::SendRstStream(QuicStreamId id,
541 QuicRstStreamErrorCode error,
542 QuicStreamOffset bytes_written) {
543 QuicSession::SendRstStream(id, error, bytes_written);
544 OnClosedStream();
547 void QuicClientSession::OnClosedStream() {
548 if (GetNumOpenStreams() < get_max_open_streams() &&
549 !stream_requests_.empty() &&
550 crypto_stream_->encryption_established() &&
551 !goaway_received() &&
552 !going_away_ &&
553 connection()->connected()) {
554 StreamRequest* request = stream_requests_.front();
555 stream_requests_.pop_front();
556 request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
559 if (GetNumOpenStreams() == 0) {
560 stream_factory_->OnIdleSession(this);
564 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
565 if (!callback_.is_null() &&
566 (!require_confirmation_ ||
567 event == HANDSHAKE_CONFIRMED || event == ENCRYPTION_REESTABLISHED)) {
568 // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
569 // could be called because there are no error events in CryptoHandshakeEvent
570 // enum. If error events are added to CryptoHandshakeEvent, then the
571 // following code needs to changed.
572 base::ResetAndReturn(&callback_).Run(OK);
574 if (event == HANDSHAKE_CONFIRMED) {
575 UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime",
576 base::TimeTicks::Now() - handshake_start_);
577 ObserverSet::iterator it = observers_.begin();
578 while (it != observers_.end()) {
579 Observer* observer = *it;
580 ++it;
581 observer->OnCryptoHandshakeConfirmed();
584 QuicSession::OnCryptoHandshakeEvent(event);
587 void QuicClientSession::OnCryptoHandshakeMessageSent(
588 const CryptoHandshakeMessage& message) {
589 logger_->OnCryptoHandshakeMessageSent(message);
592 void QuicClientSession::OnCryptoHandshakeMessageReceived(
593 const CryptoHandshakeMessage& message) {
594 logger_->OnCryptoHandshakeMessageReceived(message);
597 void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
598 bool from_peer) {
599 DCHECK(!connection()->connected());
600 logger_->OnConnectionClosed(error, from_peer);
601 if (from_peer) {
602 UMA_HISTOGRAM_SPARSE_SLOWLY(
603 "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
604 } else {
605 UMA_HISTOGRAM_SPARSE_SLOWLY(
606 "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
609 if (error == QUIC_CONNECTION_TIMED_OUT) {
610 UMA_HISTOGRAM_COUNTS(
611 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
612 GetNumOpenStreams());
613 if (IsCryptoHandshakeConfirmed()) {
614 if (GetNumOpenStreams() > 0) {
615 UMA_HISTOGRAM_BOOLEAN(
616 "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
617 connection()->sent_packet_manager().HasUnackedPackets());
618 UMA_HISTOGRAM_COUNTS(
619 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
620 connection()->sent_packet_manager().consecutive_rto_count());
621 UMA_HISTOGRAM_COUNTS(
622 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
623 connection()->sent_packet_manager().consecutive_tlp_count());
625 } else {
626 UMA_HISTOGRAM_COUNTS(
627 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
628 GetNumOpenStreams());
629 UMA_HISTOGRAM_COUNTS(
630 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
631 num_total_streams_);
635 if (!IsCryptoHandshakeConfirmed()) {
636 if (error == QUIC_PUBLIC_RESET) {
637 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
638 } else if (connection()->GetStats().packets_received == 0) {
639 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
640 UMA_HISTOGRAM_SPARSE_SLOWLY(
641 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
642 error);
643 } else {
644 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
645 UMA_HISTOGRAM_SPARSE_SLOWLY(
646 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
647 error);
651 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
652 connection()->version());
653 NotifyFactoryOfSessionGoingAway();
654 if (!callback_.is_null()) {
655 base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
657 socket_->Close();
658 QuicSession::OnConnectionClosed(error, from_peer);
659 DCHECK(streams()->empty());
660 CloseAllStreams(ERR_UNEXPECTED);
661 CloseAllObservers(ERR_UNEXPECTED);
662 NotifyFactoryOfSessionClosedLater();
665 void QuicClientSession::OnSuccessfulVersionNegotiation(
666 const QuicVersion& version) {
667 logger_->OnSuccessfulVersionNegotiation(version);
668 QuicSession::OnSuccessfulVersionNegotiation(version);
671 void QuicClientSession::OnProofValid(
672 const QuicCryptoClientConfig::CachedState& cached) {
673 DCHECK(cached.proof_valid());
675 if (!server_info_ || !server_info_->IsReadyToPersist()) {
676 return;
679 QuicServerInfo::State* state = server_info_->mutable_state();
681 state->server_config = cached.server_config();
682 state->source_address_token = cached.source_address_token();
683 state->server_config_sig = cached.signature();
684 state->certs = cached.certs();
686 server_info_->Persist();
689 void QuicClientSession::OnProofVerifyDetailsAvailable(
690 const ProofVerifyDetails& verify_details) {
691 const ProofVerifyDetailsChromium* verify_details_chromium =
692 reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
693 CertVerifyResult* result_copy = new CertVerifyResult;
694 result_copy->CopyFrom(verify_details_chromium->cert_verify_result);
695 cert_verify_result_.reset(result_copy);
696 pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
697 logger_->OnCertificateVerified(*cert_verify_result_);
700 void QuicClientSession::StartReading() {
701 if (read_pending_) {
702 return;
704 read_pending_ = true;
705 int rv = socket_->Read(read_buffer_.get(),
706 read_buffer_->size(),
707 base::Bind(&QuicClientSession::OnReadComplete,
708 weak_factory_.GetWeakPtr()));
709 if (rv == ERR_IO_PENDING) {
710 num_packets_read_ = 0;
711 return;
714 if (++num_packets_read_ > 32) {
715 num_packets_read_ = 0;
716 // Data was read, process it.
717 // Schedule the work through the message loop to 1) prevent infinite
718 // recursion and 2) avoid blocking the thread for too long.
719 base::MessageLoop::current()->PostTask(
720 FROM_HERE,
721 base::Bind(&QuicClientSession::OnReadComplete,
722 weak_factory_.GetWeakPtr(), rv));
723 } else {
724 OnReadComplete(rv);
728 void QuicClientSession::CloseSessionOnError(int error) {
729 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
730 CloseSessionOnErrorInner(error, QUIC_INTERNAL_ERROR);
731 NotifyFactoryOfSessionClosed();
734 void QuicClientSession::CloseSessionOnErrorInner(int net_error,
735 QuicErrorCode quic_error) {
736 if (!callback_.is_null()) {
737 base::ResetAndReturn(&callback_).Run(net_error);
739 CloseAllStreams(net_error);
740 CloseAllObservers(net_error);
741 net_log_.AddEvent(
742 NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
743 NetLog::IntegerCallback("net_error", net_error));
745 if (connection()->connected())
746 connection()->CloseConnection(quic_error, false);
747 DCHECK(!connection()->connected());
750 void QuicClientSession::CloseAllStreams(int net_error) {
751 while (!streams()->empty()) {
752 ReliableQuicStream* stream = streams()->begin()->second;
753 QuicStreamId id = stream->id();
754 static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
755 CloseStream(id);
759 void QuicClientSession::CloseAllObservers(int net_error) {
760 while (!observers_.empty()) {
761 Observer* observer = *observers_.begin();
762 observers_.erase(observer);
763 observer->OnSessionClosed(net_error);
767 base::Value* QuicClientSession::GetInfoAsValue(
768 const std::set<HostPortPair>& aliases) {
769 base::DictionaryValue* dict = new base::DictionaryValue();
770 dict->SetString("version", QuicVersionToString(connection()->version()));
771 dict->SetInteger("open_streams", GetNumOpenStreams());
772 base::ListValue* stream_list = new base::ListValue();
773 for (base::hash_map<QuicStreamId, QuicDataStream*>::const_iterator it
774 = streams()->begin();
775 it != streams()->end();
776 ++it) {
777 stream_list->Append(new base::StringValue(
778 base::Uint64ToString(it->second->id())));
780 dict->Set("active_streams", stream_list);
782 dict->SetInteger("total_streams", num_total_streams_);
783 dict->SetString("peer_address", peer_address().ToString());
784 dict->SetString("connection_id", base::Uint64ToString(connection_id()));
785 dict->SetBoolean("connected", connection()->connected());
786 const QuicConnectionStats& stats = connection()->GetStats();
787 dict->SetInteger("packets_sent", stats.packets_sent);
788 dict->SetInteger("packets_received", stats.packets_received);
789 dict->SetInteger("packets_lost", stats.packets_lost);
790 SSLInfo ssl_info;
791 dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
793 base::ListValue* alias_list = new base::ListValue();
794 for (std::set<HostPortPair>::const_iterator it = aliases.begin();
795 it != aliases.end(); it++) {
796 alias_list->Append(new base::StringValue(it->ToString()));
798 dict->Set("aliases", alias_list);
800 return dict;
803 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
804 return weak_factory_.GetWeakPtr();
807 void QuicClientSession::OnReadComplete(int result) {
808 read_pending_ = false;
809 if (result == 0)
810 result = ERR_CONNECTION_CLOSED;
812 if (result < 0) {
813 DVLOG(1) << "Closing session on read error: " << result;
814 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
815 NotifyFactoryOfSessionGoingAway();
816 CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
817 NotifyFactoryOfSessionClosedLater();
818 return;
821 QuicEncryptedPacket packet(read_buffer_->data(), result);
822 IPEndPoint local_address;
823 IPEndPoint peer_address;
824 socket_->GetLocalAddress(&local_address);
825 socket_->GetPeerAddress(&peer_address);
826 // ProcessUdpPacket might result in |this| being deleted, so we
827 // use a weak pointer to be safe.
828 connection()->ProcessUdpPacket(local_address, peer_address, packet);
829 if (!connection()->connected()) {
830 NotifyFactoryOfSessionClosedLater();
831 return;
833 StartReading();
836 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
837 going_away_ = true;
838 if (stream_factory_)
839 stream_factory_->OnSessionGoingAway(this);
842 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
843 if (!streams()->empty())
844 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
846 if (!going_away_)
847 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
849 going_away_ = true;
850 DCHECK_EQ(0u, GetNumOpenStreams());
851 DCHECK(!connection()->connected());
852 base::MessageLoop::current()->PostTask(
853 FROM_HERE,
854 base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
855 weak_factory_.GetWeakPtr()));
858 void QuicClientSession::NotifyFactoryOfSessionClosed() {
859 if (!streams()->empty())
860 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
862 if (!going_away_)
863 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
865 going_away_ = true;
866 DCHECK_EQ(0u, GetNumOpenStreams());
867 // Will delete |this|.
868 if (stream_factory_)
869 stream_factory_->OnSessionClosed(this);
872 void QuicClientSession::OnConnectTimeout() {
873 DCHECK(callback_.is_null());
874 DCHECK(IsEncryptionEstablished());
876 if (IsCryptoHandshakeConfirmed())
877 return;
879 // TODO(rch): re-enable this code once beta is cut.
880 // if (stream_factory_)
881 // stream_factory_->OnSessionConnectTimeout(this);
882 // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
883 // DCHECK_EQ(0u, GetNumOpenStreams());
886 } // namespace net