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"
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 // IPv6 packets have an additional 20 bytes of overhead than IPv4 packets.
38 const size_t kAdditionalOverheadForIPv6 = 20;
40 // Histograms for tracking down the crashes from http://crbug.com/354669
41 // Note: these values must be kept in sync with the corresponding values in:
42 // tools/metrics/histograms/histograms.xml
46 TRY_CREATE_STREAM = 2,
47 CREATE_OUTGOING_RELIABLE_STREAM = 3,
48 NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER = 4,
49 NOTIFY_FACTORY_OF_SESSION_CLOSED = 5,
53 void RecordUnexpectedOpenStreams(Location location) {
54 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
58 void RecordUnexpectedObservers(Location location) {
59 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
63 void RecordUnexpectedNotGoingAway(Location location) {
64 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
68 // Histogram for recording the different reasons that a QUIC session is unable
69 // to complete the handshake.
70 enum HandshakeFailureReason {
71 HANDSHAKE_FAILURE_UNKNOWN = 0,
72 HANDSHAKE_FAILURE_BLACK_HOLE = 1,
73 HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
74 NUM_HANDSHAKE_FAILURE_REASONS = 3,
77 void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
78 UMA_HISTOGRAM_ENUMERATION(
79 "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason",
80 reason, NUM_HANDSHAKE_FAILURE_REASONS);
83 // Note: these values must be kept in sync with the corresponding values in:
84 // tools/metrics/histograms/histograms.xml
87 STATE_ENCRYPTION_ESTABLISHED = 1,
88 STATE_HANDSHAKE_CONFIRMED = 2,
90 NUM_HANDSHAKE_STATES = 4
93 void RecordHandshakeState(HandshakeState state) {
94 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
95 NUM_HANDSHAKE_STATES);
98 base::Value* NetLogQuicClientSessionCallback(
99 const QuicServerId* server_id,
100 bool require_confirmation,
101 NetLog::LogLevel /* log_level */) {
102 base::DictionaryValue* dict = new base::DictionaryValue();
103 dict->SetString("host", server_id->host());
104 dict->SetInteger("port", server_id->port());
105 dict->SetBoolean("is_https", server_id->is_https());
106 dict->SetBoolean("require_confirmation", require_confirmation);
112 QuicClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
114 QuicClientSession::StreamRequest::~StreamRequest() {
118 int QuicClientSession::StreamRequest::StartRequest(
119 const base::WeakPtr<QuicClientSession>& session,
120 QuicReliableClientStream** stream,
121 const CompletionCallback& callback) {
124 int rv = session_->TryCreateStream(this, stream_);
125 if (rv == ERR_IO_PENDING) {
126 callback_ = callback;
132 void QuicClientSession::StreamRequest::CancelRequest() {
134 session_->CancelRequest(this);
139 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
140 QuicReliableClientStream* stream) {
143 ResetAndReturn(&callback_).Run(OK);
146 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
148 ResetAndReturn(&callback_).Run(rv);
151 QuicClientSession::QuicClientSession(
152 QuicConnection* connection,
153 scoped_ptr<DatagramClientSocket> socket,
154 QuicStreamFactory* stream_factory,
155 TransportSecurityState* transport_security_state,
156 scoped_ptr<QuicServerInfo> server_info,
157 const QuicConfig& config,
159 base::TaskRunner* task_runner,
161 : QuicClientSessionBase(connection, config, is_secure),
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());
638 UMA_HISTOGRAM_COUNTS(
639 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
640 GetNumOpenStreams());
641 UMA_HISTOGRAM_COUNTS(
642 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
647 if (!IsCryptoHandshakeConfirmed()) {
648 if (error == QUIC_PUBLIC_RESET) {
649 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
650 } else if (connection()->GetStats().packets_received == 0) {
651 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
652 UMA_HISTOGRAM_SPARSE_SLOWLY(
653 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
656 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
657 UMA_HISTOGRAM_SPARSE_SLOWLY(
658 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
663 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
664 connection()->version());
665 NotifyFactoryOfSessionGoingAway();
666 if (!callback_.is_null()) {
667 base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
670 QuicSession::OnConnectionClosed(error, from_peer);
671 DCHECK(streams()->empty());
672 CloseAllStreams(ERR_UNEXPECTED);
673 CloseAllObservers(ERR_UNEXPECTED);
674 NotifyFactoryOfSessionClosedLater();
677 void QuicClientSession::OnSuccessfulVersionNegotiation(
678 const QuicVersion& version) {
679 logger_->OnSuccessfulVersionNegotiation(version);
680 QuicSession::OnSuccessfulVersionNegotiation(version);
683 void QuicClientSession::OnProofValid(
684 const QuicCryptoClientConfig::CachedState& cached) {
685 DCHECK(cached.proof_valid());
691 QuicServerInfo::State* state = server_info_->mutable_state();
693 state->server_config = cached.server_config();
694 state->source_address_token = cached.source_address_token();
695 state->server_config_sig = cached.signature();
696 state->certs = cached.certs();
698 server_info_->Persist();
701 void QuicClientSession::OnProofVerifyDetailsAvailable(
702 const ProofVerifyDetails& verify_details) {
703 const ProofVerifyDetailsChromium* verify_details_chromium =
704 reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
705 CertVerifyResult* result_copy = new CertVerifyResult;
706 result_copy->CopyFrom(verify_details_chromium->cert_verify_result);
707 cert_verify_result_.reset(result_copy);
708 pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
709 logger_->OnCertificateVerified(*cert_verify_result_);
712 void QuicClientSession::StartReading() {
716 read_pending_ = true;
717 int rv = socket_->Read(read_buffer_.get(),
718 read_buffer_->size(),
719 base::Bind(&QuicClientSession::OnReadComplete,
720 weak_factory_.GetWeakPtr()));
721 if (rv == ERR_IO_PENDING) {
722 num_packets_read_ = 0;
726 if (++num_packets_read_ > 32) {
727 num_packets_read_ = 0;
728 // Data was read, process it.
729 // Schedule the work through the message loop to 1) prevent infinite
730 // recursion and 2) avoid blocking the thread for too long.
731 base::MessageLoop::current()->PostTask(
733 base::Bind(&QuicClientSession::OnReadComplete,
734 weak_factory_.GetWeakPtr(), rv));
740 void QuicClientSession::CloseSessionOnError(int error) {
741 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
742 CloseSessionOnErrorInner(error, QUIC_INTERNAL_ERROR);
743 NotifyFactoryOfSessionClosed();
746 void QuicClientSession::CloseSessionOnErrorInner(int net_error,
747 QuicErrorCode quic_error) {
748 if (!callback_.is_null()) {
749 base::ResetAndReturn(&callback_).Run(net_error);
751 CloseAllStreams(net_error);
752 CloseAllObservers(net_error);
754 NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
755 NetLog::IntegerCallback("net_error", net_error));
757 if (connection()->connected())
758 connection()->CloseConnection(quic_error, false);
759 DCHECK(!connection()->connected());
762 void QuicClientSession::CloseAllStreams(int net_error) {
763 while (!streams()->empty()) {
764 ReliableQuicStream* stream = streams()->begin()->second;
765 QuicStreamId id = stream->id();
766 static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
771 void QuicClientSession::CloseAllObservers(int net_error) {
772 while (!observers_.empty()) {
773 Observer* observer = *observers_.begin();
774 observers_.erase(observer);
775 observer->OnSessionClosed(net_error);
779 base::Value* QuicClientSession::GetInfoAsValue(
780 const std::set<HostPortPair>& aliases) {
781 base::DictionaryValue* dict = new base::DictionaryValue();
782 dict->SetString("version", QuicVersionToString(connection()->version()));
783 dict->SetInteger("open_streams", GetNumOpenStreams());
784 base::ListValue* stream_list = new base::ListValue();
785 for (base::hash_map<QuicStreamId, QuicDataStream*>::const_iterator it
786 = streams()->begin();
787 it != streams()->end();
789 stream_list->Append(new base::StringValue(
790 base::Uint64ToString(it->second->id())));
792 dict->Set("active_streams", stream_list);
794 dict->SetInteger("total_streams", num_total_streams_);
795 dict->SetString("peer_address", peer_address().ToString());
796 dict->SetString("connection_id", base::Uint64ToString(connection_id()));
797 dict->SetBoolean("connected", connection()->connected());
798 const QuicConnectionStats& stats = connection()->GetStats();
799 dict->SetInteger("packets_sent", stats.packets_sent);
800 dict->SetInteger("packets_received", stats.packets_received);
801 dict->SetInteger("packets_lost", stats.packets_lost);
803 dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
805 base::ListValue* alias_list = new base::ListValue();
806 for (std::set<HostPortPair>::const_iterator it = aliases.begin();
807 it != aliases.end(); it++) {
808 alias_list->Append(new base::StringValue(it->ToString()));
810 dict->Set("aliases", alias_list);
815 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
816 return weak_factory_.GetWeakPtr();
819 void QuicClientSession::OnReadComplete(int result) {
820 read_pending_ = false;
822 result = ERR_CONNECTION_CLOSED;
825 DVLOG(1) << "Closing session on read error: " << result;
826 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
827 NotifyFactoryOfSessionGoingAway();
828 CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
829 NotifyFactoryOfSessionClosedLater();
833 QuicEncryptedPacket packet(read_buffer_->data(), result);
834 IPEndPoint local_address;
835 IPEndPoint peer_address;
836 socket_->GetLocalAddress(&local_address);
837 socket_->GetPeerAddress(&peer_address);
838 // ProcessUdpPacket might result in |this| being deleted, so we
839 // use a weak pointer to be safe.
840 connection()->ProcessUdpPacket(local_address, peer_address, packet);
841 if (!connection()->connected()) {
842 NotifyFactoryOfSessionClosedLater();
848 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
851 stream_factory_->OnSessionGoingAway(this);
854 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
855 if (!streams()->empty())
856 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
859 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
862 DCHECK_EQ(0u, GetNumOpenStreams());
863 DCHECK(!connection()->connected());
864 base::MessageLoop::current()->PostTask(
866 base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
867 weak_factory_.GetWeakPtr()));
870 void QuicClientSession::NotifyFactoryOfSessionClosed() {
871 if (!streams()->empty())
872 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
875 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
878 DCHECK_EQ(0u, GetNumOpenStreams());
879 // Will delete |this|.
881 stream_factory_->OnSessionClosed(this);
884 void QuicClientSession::OnConnectTimeout() {
885 DCHECK(callback_.is_null());
886 DCHECK(IsEncryptionEstablished());
888 if (IsCryptoHandshakeConfirmed())
891 // TODO(rch): re-enable this code once beta is cut.
892 // if (stream_factory_)
893 // stream_factory_->OnSessionConnectTimeout(this);
894 // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
895 // DCHECK_EQ(0u, GetNumOpenStreams());