Lots of random cleanups, mostly for native_theme_win.cc:
[chromium-blink-merge.git] / net / quic / quic_client_session.cc
blobfce3bf79465914477bfaea7a19c256bdd557888c
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/quic/crypto/proof_verifier_chromium.h"
17 #include "net/quic/crypto/quic_server_info.h"
18 #include "net/quic/quic_connection_helper.h"
19 #include "net/quic/quic_crypto_client_stream_factory.h"
20 #include "net/quic/quic_default_packet_writer.h"
21 #include "net/quic/quic_server_id.h"
22 #include "net/quic/quic_stream_factory.h"
23 #include "net/ssl/server_bound_cert_service.h"
24 #include "net/ssl/ssl_connection_status_flags.h"
25 #include "net/ssl/ssl_info.h"
26 #include "net/udp/datagram_client_socket.h"
28 namespace net {
30 namespace {
32 // The length of time to wait for a 0-RTT handshake to complete
33 // before allowing the requests to possibly proceed over TCP.
34 const int k0RttHandshakeTimeoutMs = 300;
36 // Histograms for tracking down the crashes from http://crbug.com/354669
37 // Note: these values must be kept in sync with the corresponding values in:
38 // tools/metrics/histograms/histograms.xml
39 enum Location {
40 DESTRUCTOR = 0,
41 ADD_OBSERVER = 1,
42 TRY_CREATE_STREAM = 2,
43 CREATE_OUTGOING_RELIABLE_STREAM = 3,
44 NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER = 4,
45 NOTIFY_FACTORY_OF_SESSION_CLOSED = 5,
46 NUM_LOCATIONS = 6,
49 void RecordUnexpectedOpenStreams(Location location) {
50 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
51 NUM_LOCATIONS);
54 void RecordUnexpectedObservers(Location location) {
55 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
56 NUM_LOCATIONS);
59 void RecordUnexpectedNotGoingAway(Location location) {
60 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
61 NUM_LOCATIONS);
64 // Histogram for recording the different reasons that a QUIC session is unable
65 // to complete the handshake.
66 enum HandshakeFailureReason {
67 HANDSHAKE_FAILURE_UNKNOWN = 0,
68 HANDSHAKE_FAILURE_BLACK_HOLE = 1,
69 HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
70 NUM_HANDSHAKE_FAILURE_REASONS = 3,
73 void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
74 UMA_HISTOGRAM_ENUMERATION(
75 "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason",
76 reason, NUM_HANDSHAKE_FAILURE_REASONS);
79 // Note: these values must be kept in sync with the corresponding values in:
80 // tools/metrics/histograms/histograms.xml
81 enum HandshakeState {
82 STATE_STARTED = 0,
83 STATE_ENCRYPTION_ESTABLISHED = 1,
84 STATE_HANDSHAKE_CONFIRMED = 2,
85 STATE_FAILED = 3,
86 NUM_HANDSHAKE_STATES = 4
89 void RecordHandshakeState(HandshakeState state) {
90 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
91 NUM_HANDSHAKE_STATES);
94 } // namespace
96 QuicClientSession::StreamRequest::StreamRequest() : stream_(NULL) {}
98 QuicClientSession::StreamRequest::~StreamRequest() {
99 CancelRequest();
102 int QuicClientSession::StreamRequest::StartRequest(
103 const base::WeakPtr<QuicClientSession>& session,
104 QuicReliableClientStream** stream,
105 const CompletionCallback& callback) {
106 session_ = session;
107 stream_ = stream;
108 int rv = session_->TryCreateStream(this, stream_);
109 if (rv == ERR_IO_PENDING) {
110 callback_ = callback;
113 return rv;
116 void QuicClientSession::StreamRequest::CancelRequest() {
117 if (session_)
118 session_->CancelRequest(this);
119 session_.reset();
120 callback_.Reset();
123 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
124 QuicReliableClientStream* stream) {
125 session_.reset();
126 *stream_ = stream;
127 ResetAndReturn(&callback_).Run(OK);
130 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
131 session_.reset();
132 ResetAndReturn(&callback_).Run(rv);
135 QuicClientSession::QuicClientSession(
136 QuicConnection* connection,
137 scoped_ptr<DatagramClientSocket> socket,
138 scoped_ptr<QuicDefaultPacketWriter> writer,
139 QuicStreamFactory* stream_factory,
140 QuicCryptoClientStreamFactory* crypto_client_stream_factory,
141 scoped_ptr<QuicServerInfo> server_info,
142 const QuicServerId& server_id,
143 const QuicConfig& config,
144 QuicCryptoClientConfig* crypto_config,
145 base::TaskRunner* task_runner,
146 NetLog* net_log)
147 : QuicClientSessionBase(connection,
148 config),
149 server_host_port_(server_id.host_port_pair()),
150 require_confirmation_(false),
151 stream_factory_(stream_factory),
152 socket_(socket.Pass()),
153 writer_(writer.Pass()),
154 read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
155 server_info_(server_info.Pass()),
156 read_pending_(false),
157 num_total_streams_(0),
158 task_runner_(task_runner),
159 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
160 logger_(net_log_),
161 num_packets_read_(0),
162 going_away_(false),
163 weak_factory_(this) {
164 crypto_stream_.reset(
165 crypto_client_stream_factory ?
166 crypto_client_stream_factory->CreateQuicCryptoClientStream(
167 server_id, this, crypto_config) :
168 new QuicCryptoClientStream(server_id, this,
169 new ProofVerifyContextChromium(net_log_),
170 crypto_config));
172 connection->set_debug_visitor(&logger_);
173 // TODO(rch): pass in full host port proxy pair
174 net_log_.BeginEvent(
175 NetLog::TYPE_QUIC_SESSION,
176 NetLog::StringCallback("host", &server_id.host()));
179 QuicClientSession::~QuicClientSession() {
180 if (!streams()->empty())
181 RecordUnexpectedOpenStreams(DESTRUCTOR);
182 if (!observers_.empty())
183 RecordUnexpectedObservers(DESTRUCTOR);
184 if (!going_away_)
185 RecordUnexpectedNotGoingAway(DESTRUCTOR);
187 while (!streams()->empty() ||
188 !observers_.empty() ||
189 !stream_requests_.empty()) {
190 // The session must be closed before it is destroyed.
191 DCHECK(streams()->empty());
192 CloseAllStreams(ERR_UNEXPECTED);
193 DCHECK(observers_.empty());
194 CloseAllObservers(ERR_UNEXPECTED);
196 connection()->set_debug_visitor(NULL);
197 net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
199 while (!stream_requests_.empty()) {
200 StreamRequest* request = stream_requests_.front();
201 stream_requests_.pop_front();
202 request->OnRequestCompleteFailure(ERR_ABORTED);
206 if (connection()->connected()) {
207 // Ensure that the connection is closed by the time the session is
208 // destroyed.
209 connection()->CloseConnection(QUIC_INTERNAL_ERROR, false);
212 if (IsEncryptionEstablished())
213 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
214 if (IsCryptoHandshakeConfirmed())
215 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
216 else
217 RecordHandshakeState(STATE_FAILED);
219 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
220 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
221 crypto_stream_->num_sent_client_hellos());
222 if (!IsCryptoHandshakeConfirmed())
223 return;
225 // Sending one client_hello means we had zero handshake-round-trips.
226 int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
228 // Don't bother with these histogram during tests, which mock out
229 // num_sent_client_hellos().
230 if (round_trip_handshakes < 0 || !stream_factory_)
231 return;
233 bool port_selected = stream_factory_->enable_port_selection();
234 SSLInfo ssl_info;
235 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert) {
236 if (port_selected) {
237 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
238 round_trip_handshakes, 0, 3, 4);
239 } else {
240 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
241 round_trip_handshakes, 0, 3, 4);
243 } else {
244 if (port_selected) {
245 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
246 round_trip_handshakes, 0, 3, 4);
247 } else {
248 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
249 round_trip_handshakes, 0, 3, 4);
252 const QuicConnectionStats stats = connection()->GetStats();
253 if (stats.max_sequence_reordering == 0)
254 return;
255 const uint64 kMaxReordering = 100;
256 uint64 reordering = kMaxReordering;
257 if (stats.min_rtt_us > 0 ) {
258 reordering =
259 GG_UINT64_C(100) * stats.max_time_reordering_us / stats.min_rtt_us;
261 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime",
262 reordering, 0, kMaxReordering, 50);
263 if (stats.min_rtt_us > 100 * 1000) {
264 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
265 reordering, 0, kMaxReordering, 50);
267 UMA_HISTOGRAM_COUNTS("Net.QuicSession.MaxReordering",
268 stats.max_sequence_reordering);
271 void QuicClientSession::OnStreamFrames(
272 const std::vector<QuicStreamFrame>& frames) {
273 // Record total number of stream frames.
274 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames.size());
276 // Record number of frames per stream in packet.
277 typedef std::map<QuicStreamId, size_t> FrameCounter;
278 FrameCounter frames_per_stream;
279 for (size_t i = 0; i < frames.size(); ++i) {
280 frames_per_stream[frames[i].stream_id]++;
282 for (FrameCounter::const_iterator it = frames_per_stream.begin();
283 it != frames_per_stream.end(); ++it) {
284 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
285 it->second);
288 return QuicSession::OnStreamFrames(frames);
291 void QuicClientSession::AddObserver(Observer* observer) {
292 if (going_away_) {
293 RecordUnexpectedObservers(ADD_OBSERVER);
294 observer->OnSessionClosed(ERR_UNEXPECTED);
295 return;
298 DCHECK(!ContainsKey(observers_, observer));
299 observers_.insert(observer);
302 void QuicClientSession::RemoveObserver(Observer* observer) {
303 DCHECK(ContainsKey(observers_, observer));
304 observers_.erase(observer);
307 int QuicClientSession::TryCreateStream(StreamRequest* request,
308 QuicReliableClientStream** stream) {
309 if (!crypto_stream_->encryption_established()) {
310 DLOG(DFATAL) << "Encryption not established.";
311 return ERR_CONNECTION_CLOSED;
314 if (goaway_received()) {
315 DVLOG(1) << "Going away.";
316 return ERR_CONNECTION_CLOSED;
319 if (!connection()->connected()) {
320 DVLOG(1) << "Already closed.";
321 return ERR_CONNECTION_CLOSED;
324 if (going_away_) {
325 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
326 return ERR_CONNECTION_CLOSED;
329 if (GetNumOpenStreams() < get_max_open_streams()) {
330 *stream = CreateOutgoingReliableStreamImpl();
331 return OK;
334 stream_requests_.push_back(request);
335 return ERR_IO_PENDING;
338 void QuicClientSession::CancelRequest(StreamRequest* request) {
339 // Remove |request| from the queue while preserving the order of the
340 // other elements.
341 StreamRequestQueue::iterator it =
342 std::find(stream_requests_.begin(), stream_requests_.end(), request);
343 if (it != stream_requests_.end()) {
344 it = stream_requests_.erase(it);
348 QuicReliableClientStream* QuicClientSession::CreateOutgoingDataStream() {
349 if (!crypto_stream_->encryption_established()) {
350 DVLOG(1) << "Encryption not active so no outgoing stream created.";
351 return NULL;
353 if (GetNumOpenStreams() >= get_max_open_streams()) {
354 DVLOG(1) << "Failed to create a new outgoing stream. "
355 << "Already " << GetNumOpenStreams() << " open.";
356 return NULL;
358 if (goaway_received()) {
359 DVLOG(1) << "Failed to create a new outgoing stream. "
360 << "Already received goaway.";
361 return NULL;
363 if (going_away_) {
364 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
365 return NULL;
367 return CreateOutgoingReliableStreamImpl();
370 QuicReliableClientStream*
371 QuicClientSession::CreateOutgoingReliableStreamImpl() {
372 DCHECK(connection()->connected());
373 QuicReliableClientStream* stream =
374 new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
375 ActivateStream(stream);
376 ++num_total_streams_;
377 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
378 return stream;
381 QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
382 return crypto_stream_.get();
385 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
386 // we learn about SSL info (sync vs async vs cached).
387 bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
388 ssl_info->Reset();
389 if (!cert_verify_result_) {
390 return false;
393 ssl_info->cert_status = cert_verify_result_->cert_status;
394 ssl_info->cert = cert_verify_result_->verified_cert;
396 // TODO(wtc): Define QUIC "cipher suites".
397 // Report the TLS cipher suite that most closely resembles the crypto
398 // parameters of the QUIC connection.
399 QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
400 int cipher_suite;
401 int security_bits;
402 switch (aead) {
403 case kAESG:
404 cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
405 security_bits = 128;
406 break;
407 case kCC12:
408 cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
409 security_bits = 256;
410 break;
411 default:
412 NOTREACHED();
413 return false;
415 int ssl_connection_status = 0;
416 ssl_connection_status |=
417 (cipher_suite & SSL_CONNECTION_CIPHERSUITE_MASK) <<
418 SSL_CONNECTION_CIPHERSUITE_SHIFT;
419 ssl_connection_status |=
420 (SSL_CONNECTION_VERSION_QUIC & SSL_CONNECTION_VERSION_MASK) <<
421 SSL_CONNECTION_VERSION_SHIFT;
423 ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
424 ssl_info->is_issued_by_known_root =
425 cert_verify_result_->is_issued_by_known_root;
427 ssl_info->connection_status = ssl_connection_status;
428 ssl_info->client_cert_sent = false;
429 ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent();
430 ssl_info->security_bits = security_bits;
431 ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
432 return true;
435 int QuicClientSession::CryptoConnect(bool require_confirmation,
436 const CompletionCallback& callback) {
437 require_confirmation_ = require_confirmation;
438 handshake_start_ = base::TimeTicks::Now();
439 RecordHandshakeState(STATE_STARTED);
440 if (!crypto_stream_->CryptoConnect()) {
441 // TODO(wtc): change crypto_stream_.CryptoConnect() to return a
442 // QuicErrorCode and map it to a net error code.
443 return ERR_CONNECTION_FAILED;
446 if (IsCryptoHandshakeConfirmed())
447 return OK;
449 // Unless we require handshake confirmation, activate the session if
450 // we have established initial encryption.
451 if (!require_confirmation_ && IsEncryptionEstablished()) {
452 // To mitigate the effects of hanging 0-RTT connections, set up a timer to
453 // cancel any requests, if the handshake takes too long.
454 task_runner_->PostDelayedTask(
455 FROM_HERE,
456 base::Bind(&QuicClientSession::OnConnectTimeout,
457 weak_factory_.GetWeakPtr()),
458 base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs));
459 return OK;
463 callback_ = callback;
464 return ERR_IO_PENDING;
467 int QuicClientSession::ResumeCryptoConnect(const CompletionCallback& callback) {
469 if (IsCryptoHandshakeConfirmed())
470 return OK;
472 if (!connection()->connected())
473 return ERR_QUIC_HANDSHAKE_FAILED;
475 callback_ = callback;
476 return ERR_IO_PENDING;
479 int QuicClientSession::GetNumSentClientHellos() const {
480 return crypto_stream_->num_sent_client_hellos();
483 bool QuicClientSession::CanPool(const std::string& hostname) const {
484 DCHECK(connection()->connected());
485 SSLInfo ssl_info;
486 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert) {
487 // We can always pool with insecure QUIC sessions.
488 return true;
491 bool unused = false;
492 // Pooling is prohibited if the server cert is not valid for the new domain,
493 // and for connections on which client certs were sent. It is also prohibited
494 // when channel ID was sent if the hosts are from different eTLDs+1.
495 if (!ssl_info.cert->VerifyNameMatch(hostname, &unused))
496 return false;
498 if (ssl_info.client_cert_sent)
499 return false;
501 if (ssl_info.channel_id_sent &&
502 ServerBoundCertService::GetDomainForHost(hostname) !=
503 ServerBoundCertService::GetDomainForHost(server_host_port_.host())) {
504 return false;
507 return true;
510 QuicDataStream* QuicClientSession::CreateIncomingDataStream(
511 QuicStreamId id) {
512 DLOG(ERROR) << "Server push not supported";
513 return NULL;
516 void QuicClientSession::CloseStream(QuicStreamId stream_id) {
517 ReliableQuicStream* stream = GetStream(stream_id);
518 if (stream) {
519 logger_.UpdateReceivedFrameCounts(
520 stream_id, stream->num_frames_received(),
521 stream->num_duplicate_frames_received());
523 QuicSession::CloseStream(stream_id);
524 OnClosedStream();
527 void QuicClientSession::SendRstStream(QuicStreamId id,
528 QuicRstStreamErrorCode error,
529 QuicStreamOffset bytes_written) {
530 QuicSession::SendRstStream(id, error, bytes_written);
531 OnClosedStream();
534 void QuicClientSession::OnClosedStream() {
535 if (GetNumOpenStreams() < get_max_open_streams() &&
536 !stream_requests_.empty() &&
537 crypto_stream_->encryption_established() &&
538 !goaway_received() &&
539 !going_away_ &&
540 connection()->connected()) {
541 StreamRequest* request = stream_requests_.front();
542 stream_requests_.pop_front();
543 request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
546 if (GetNumOpenStreams() == 0) {
547 stream_factory_->OnIdleSession(this);
551 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
552 if (!callback_.is_null() &&
553 (!require_confirmation_ || event == HANDSHAKE_CONFIRMED)) {
554 // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
555 // could be called because there are no error events in CryptoHandshakeEvent
556 // enum. If error events are added to CryptoHandshakeEvent, then the
557 // following code needs to changed.
558 base::ResetAndReturn(&callback_).Run(OK);
560 if (event == HANDSHAKE_CONFIRMED) {
561 UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime",
562 base::TimeTicks::Now() - handshake_start_);
563 ObserverSet::iterator it = observers_.begin();
564 while (it != observers_.end()) {
565 Observer* observer = *it;
566 ++it;
567 observer->OnCryptoHandshakeConfirmed();
570 QuicSession::OnCryptoHandshakeEvent(event);
573 void QuicClientSession::OnCryptoHandshakeMessageSent(
574 const CryptoHandshakeMessage& message) {
575 logger_.OnCryptoHandshakeMessageSent(message);
578 void QuicClientSession::OnCryptoHandshakeMessageReceived(
579 const CryptoHandshakeMessage& message) {
580 logger_.OnCryptoHandshakeMessageReceived(message);
583 void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
584 bool from_peer) {
585 DCHECK(!connection()->connected());
586 logger_.OnConnectionClosed(error, from_peer);
587 if (from_peer) {
588 UMA_HISTOGRAM_SPARSE_SLOWLY(
589 "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
590 } else {
591 UMA_HISTOGRAM_SPARSE_SLOWLY(
592 "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
595 if (error == QUIC_CONNECTION_TIMED_OUT) {
596 UMA_HISTOGRAM_COUNTS(
597 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
598 GetNumOpenStreams());
599 if (!IsCryptoHandshakeConfirmed()) {
600 UMA_HISTOGRAM_COUNTS(
601 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
602 GetNumOpenStreams());
603 UMA_HISTOGRAM_COUNTS(
604 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
605 num_total_streams_);
609 if (!IsCryptoHandshakeConfirmed()) {
610 if (error == QUIC_PUBLIC_RESET) {
611 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
612 } else if (connection()->GetStats().packets_received == 0) {
613 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
614 UMA_HISTOGRAM_SPARSE_SLOWLY(
615 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
616 error);
617 } else {
618 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
619 UMA_HISTOGRAM_SPARSE_SLOWLY(
620 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
621 error);
625 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
626 connection()->version());
627 NotifyFactoryOfSessionGoingAway();
628 if (!callback_.is_null()) {
629 base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
631 socket_->Close();
632 QuicSession::OnConnectionClosed(error, from_peer);
633 DCHECK(streams()->empty());
634 CloseAllStreams(ERR_UNEXPECTED);
635 CloseAllObservers(ERR_UNEXPECTED);
636 NotifyFactoryOfSessionClosedLater();
639 void QuicClientSession::OnSuccessfulVersionNegotiation(
640 const QuicVersion& version) {
641 logger_.OnSuccessfulVersionNegotiation(version);
642 QuicSession::OnSuccessfulVersionNegotiation(version);
645 void QuicClientSession::OnProofValid(
646 const QuicCryptoClientConfig::CachedState& cached) {
647 DCHECK(cached.proof_valid());
649 if (!server_info_ || !server_info_->IsReadyToPersist()) {
650 return;
653 QuicServerInfo::State* state = server_info_->mutable_state();
655 state->server_config = cached.server_config();
656 state->source_address_token = cached.source_address_token();
657 state->server_config_sig = cached.signature();
658 state->certs = cached.certs();
660 server_info_->Persist();
663 void QuicClientSession::OnProofVerifyDetailsAvailable(
664 const ProofVerifyDetails& verify_details) {
665 const CertVerifyResult* cert_verify_result_other =
666 &(reinterpret_cast<const ProofVerifyDetailsChromium*>(
667 &verify_details))->cert_verify_result;
668 CertVerifyResult* result_copy = new CertVerifyResult;
669 result_copy->CopyFrom(*cert_verify_result_other);
670 cert_verify_result_.reset(result_copy);
673 void QuicClientSession::StartReading() {
674 if (read_pending_) {
675 return;
677 read_pending_ = true;
678 int rv = socket_->Read(read_buffer_.get(),
679 read_buffer_->size(),
680 base::Bind(&QuicClientSession::OnReadComplete,
681 weak_factory_.GetWeakPtr()));
682 if (rv == ERR_IO_PENDING) {
683 num_packets_read_ = 0;
684 return;
687 if (++num_packets_read_ > 32) {
688 num_packets_read_ = 0;
689 // Data was read, process it.
690 // Schedule the work through the message loop to 1) prevent infinite
691 // recursion and 2) avoid blocking the thread for too long.
692 base::MessageLoop::current()->PostTask(
693 FROM_HERE,
694 base::Bind(&QuicClientSession::OnReadComplete,
695 weak_factory_.GetWeakPtr(), rv));
696 } else {
697 OnReadComplete(rv);
701 void QuicClientSession::CloseSessionOnError(int error) {
702 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
703 CloseSessionOnErrorInner(error, QUIC_INTERNAL_ERROR);
704 NotifyFactoryOfSessionClosed();
707 void QuicClientSession::CloseSessionOnErrorInner(int net_error,
708 QuicErrorCode quic_error) {
709 if (!callback_.is_null()) {
710 base::ResetAndReturn(&callback_).Run(net_error);
712 CloseAllStreams(net_error);
713 CloseAllObservers(net_error);
714 net_log_.AddEvent(
715 NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
716 NetLog::IntegerCallback("net_error", net_error));
718 if (connection()->connected())
719 connection()->CloseConnection(quic_error, false);
720 DCHECK(!connection()->connected());
723 void QuicClientSession::CloseAllStreams(int net_error) {
724 while (!streams()->empty()) {
725 ReliableQuicStream* stream = streams()->begin()->second;
726 QuicStreamId id = stream->id();
727 static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
728 CloseStream(id);
732 void QuicClientSession::CloseAllObservers(int net_error) {
733 while (!observers_.empty()) {
734 Observer* observer = *observers_.begin();
735 observers_.erase(observer);
736 observer->OnSessionClosed(net_error);
740 base::Value* QuicClientSession::GetInfoAsValue(
741 const std::set<HostPortPair>& aliases) {
742 base::DictionaryValue* dict = new base::DictionaryValue();
743 dict->SetString("version", QuicVersionToString(connection()->version()));
744 dict->SetInteger("open_streams", GetNumOpenStreams());
745 base::ListValue* stream_list = new base::ListValue();
746 for (base::hash_map<QuicStreamId, QuicDataStream*>::const_iterator it
747 = streams()->begin();
748 it != streams()->end();
749 ++it) {
750 stream_list->Append(new base::StringValue(
751 base::Uint64ToString(it->second->id())));
753 dict->Set("active_streams", stream_list);
755 dict->SetInteger("total_streams", num_total_streams_);
756 dict->SetString("peer_address", peer_address().ToString());
757 dict->SetString("connection_id", base::Uint64ToString(connection_id()));
758 dict->SetBoolean("connected", connection()->connected());
759 const QuicConnectionStats& stats = connection()->GetStats();
760 dict->SetInteger("packets_sent", stats.packets_sent);
761 dict->SetInteger("packets_received", stats.packets_received);
762 dict->SetInteger("packets_lost", stats.packets_lost);
763 SSLInfo ssl_info;
764 dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert);
766 base::ListValue* alias_list = new base::ListValue();
767 for (std::set<HostPortPair>::const_iterator it = aliases.begin();
768 it != aliases.end(); it++) {
769 alias_list->Append(new base::StringValue(it->ToString()));
771 dict->Set("aliases", alias_list);
773 return dict;
776 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
777 return weak_factory_.GetWeakPtr();
780 void QuicClientSession::OnReadComplete(int result) {
781 read_pending_ = false;
782 if (result == 0)
783 result = ERR_CONNECTION_CLOSED;
785 if (result < 0) {
786 DVLOG(1) << "Closing session on read error: " << result;
787 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
788 NotifyFactoryOfSessionGoingAway();
789 CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
790 NotifyFactoryOfSessionClosedLater();
791 return;
794 QuicEncryptedPacket packet(read_buffer_->data(), result);
795 IPEndPoint local_address;
796 IPEndPoint peer_address;
797 socket_->GetLocalAddress(&local_address);
798 socket_->GetPeerAddress(&peer_address);
799 // ProcessUdpPacket might result in |this| being deleted, so we
800 // use a weak pointer to be safe.
801 connection()->ProcessUdpPacket(local_address, peer_address, packet);
802 if (!connection()->connected()) {
803 NotifyFactoryOfSessionClosedLater();
804 return;
806 StartReading();
809 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
810 going_away_ = true;
811 if (stream_factory_)
812 stream_factory_->OnSessionGoingAway(this);
815 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
816 if (!streams()->empty())
817 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
819 if (!going_away_)
820 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
822 going_away_ = true;
823 DCHECK_EQ(0u, GetNumOpenStreams());
824 DCHECK(!connection()->connected());
825 base::MessageLoop::current()->PostTask(
826 FROM_HERE,
827 base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
828 weak_factory_.GetWeakPtr()));
831 void QuicClientSession::NotifyFactoryOfSessionClosed() {
832 if (!streams()->empty())
833 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
835 if (!going_away_)
836 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
838 going_away_ = true;
839 DCHECK_EQ(0u, GetNumOpenStreams());
840 // Will delete |this|.
841 if (stream_factory_)
842 stream_factory_->OnSessionClosed(this);
845 void QuicClientSession::OnConnectTimeout() {
846 DCHECK(callback_.is_null());
847 DCHECK(IsEncryptionEstablished());
849 if (IsCryptoHandshakeConfirmed())
850 return;
852 // TODO(rch): re-enable this code once beta is cut.
853 // if (stream_factory_)
854 // stream_factory_->OnSessionConnectTimeout(this);
855 // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
856 // DCHECK_EQ(0u, GetNumOpenStreams());
859 } // namespace net