Remove PlatformFile from profile_browsertest
[chromium-blink-merge.git] / net / quic / quic_client_session.cc
blob7dd913545dbb113ce0577b6f3bb03fdfe028c0f7
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_session_key.h"
22 #include "net/quic/quic_stream_factory.h"
23 #include "net/ssl/ssl_connection_status_flags.h"
24 #include "net/ssl/ssl_info.h"
25 #include "net/udp/datagram_client_socket.h"
27 namespace net {
29 namespace {
31 // Histograms for tracking down the crashes from http://crbug.com/354669
32 // Note: these values must be kept in sync with the corresponding values in:
33 // tools/metrics/histograms/histograms.xml
34 enum Location {
35 DESTRUCTOR = 0,
36 ADD_OBSERVER = 1,
37 TRY_CREATE_STREAM = 2,
38 CREATE_OUTGOING_RELIABLE_STREAM = 3,
39 NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER = 4,
40 NOTIFY_FACTORY_OF_SESSION_CLOSED = 5,
41 NUM_LOCATIONS = 6,
44 void RecordUnexpectedOpenStreams(Location location) {
45 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
46 NUM_LOCATIONS);
49 void RecordUnexpectedObservers(Location location) {
50 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
51 NUM_LOCATIONS);
54 void RecordUnexpectedNotGoingAway(Location location) {
55 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
56 NUM_LOCATIONS);
59 // Note: these values must be kept in sync with the corresponding values in:
60 // tools/metrics/histograms/histograms.xml
61 enum HandshakeState {
62 STATE_STARTED = 0,
63 STATE_ENCRYPTION_ESTABLISHED = 1,
64 STATE_HANDSHAKE_CONFIRMED = 2,
65 STATE_FAILED = 3,
66 NUM_HANDSHAKE_STATES = 4
69 void RecordHandshakeState(HandshakeState state) {
70 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
71 NUM_HANDSHAKE_STATES);
74 } // namespace
76 QuicClientSession::StreamRequest::StreamRequest() : stream_(NULL) {}
78 QuicClientSession::StreamRequest::~StreamRequest() {
79 CancelRequest();
82 int QuicClientSession::StreamRequest::StartRequest(
83 const base::WeakPtr<QuicClientSession>& session,
84 QuicReliableClientStream** stream,
85 const CompletionCallback& callback) {
86 session_ = session;
87 stream_ = stream;
88 int rv = session_->TryCreateStream(this, stream_);
89 if (rv == ERR_IO_PENDING) {
90 callback_ = callback;
93 return rv;
96 void QuicClientSession::StreamRequest::CancelRequest() {
97 if (session_)
98 session_->CancelRequest(this);
99 session_.reset();
100 callback_.Reset();
103 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
104 QuicReliableClientStream* stream) {
105 session_.reset();
106 *stream_ = stream;
107 ResetAndReturn(&callback_).Run(OK);
110 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
111 session_.reset();
112 ResetAndReturn(&callback_).Run(rv);
115 QuicClientSession::QuicClientSession(
116 QuicConnection* connection,
117 scoped_ptr<DatagramClientSocket> socket,
118 scoped_ptr<QuicDefaultPacketWriter> writer,
119 QuicStreamFactory* stream_factory,
120 QuicCryptoClientStreamFactory* crypto_client_stream_factory,
121 scoped_ptr<QuicServerInfo> server_info,
122 const QuicSessionKey& server_key,
123 const QuicConfig& config,
124 QuicCryptoClientConfig* crypto_config,
125 NetLog* net_log)
126 : QuicClientSessionBase(connection, config),
127 require_confirmation_(false),
128 stream_factory_(stream_factory),
129 socket_(socket.Pass()),
130 writer_(writer.Pass()),
131 read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
132 server_info_(server_info.Pass()),
133 read_pending_(false),
134 num_total_streams_(0),
135 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
136 logger_(net_log_),
137 num_packets_read_(0),
138 going_away_(false),
139 weak_factory_(this) {
140 crypto_stream_.reset(
141 crypto_client_stream_factory ?
142 crypto_client_stream_factory->CreateQuicCryptoClientStream(
143 server_key, this, crypto_config) :
144 new QuicCryptoClientStream(server_key, this,
145 new ProofVerifyContextChromium(net_log_),
146 crypto_config));
148 connection->set_debug_visitor(&logger_);
149 // TODO(rch): pass in full host port proxy pair
150 net_log_.BeginEvent(
151 NetLog::TYPE_QUIC_SESSION,
152 NetLog::StringCallback("host", &server_key.host()));
155 QuicClientSession::~QuicClientSession() {
156 if (!streams()->empty())
157 RecordUnexpectedOpenStreams(DESTRUCTOR);
158 if (!observers_.empty())
159 RecordUnexpectedObservers(DESTRUCTOR);
160 if (!going_away_)
161 RecordUnexpectedNotGoingAway(DESTRUCTOR);
163 // The session must be closed before it is destroyed.
164 DCHECK(streams()->empty());
165 CloseAllStreams(ERR_UNEXPECTED);
166 DCHECK(observers_.empty());
167 CloseAllObservers(ERR_UNEXPECTED);
169 connection()->set_debug_visitor(NULL);
170 net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
172 while (!stream_requests_.empty()) {
173 StreamRequest* request = stream_requests_.front();
174 stream_requests_.pop_front();
175 request->OnRequestCompleteFailure(ERR_ABORTED);
178 if (IsEncryptionEstablished())
179 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
180 if (IsCryptoHandshakeConfirmed())
181 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
182 else
183 RecordHandshakeState(STATE_FAILED);
185 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
186 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
187 crypto_stream_->num_sent_client_hellos());
188 if (!IsCryptoHandshakeConfirmed())
189 return;
191 // Sending one client_hello means we had zero handshake-round-trips.
192 int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
194 // Don't bother with these histogram during tests, which mock out
195 // num_sent_client_hellos().
196 if (round_trip_handshakes < 0 || !stream_factory_)
197 return;
199 bool port_selected = stream_factory_->enable_port_selection();
200 SSLInfo ssl_info;
201 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert) {
202 if (port_selected) {
203 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
204 round_trip_handshakes, 0, 3, 4);
205 } else {
206 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
207 round_trip_handshakes, 0, 3, 4);
209 } else {
210 if (port_selected) {
211 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
212 round_trip_handshakes, 0, 3, 4);
213 } else {
214 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
215 round_trip_handshakes, 0, 3, 4);
220 bool QuicClientSession::OnStreamFrames(
221 const std::vector<QuicStreamFrame>& frames) {
222 // Record total number of stream frames.
223 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames.size());
225 // Record number of frames per stream in packet.
226 typedef std::map<QuicStreamId, size_t> FrameCounter;
227 FrameCounter frames_per_stream;
228 for (size_t i = 0; i < frames.size(); ++i) {
229 frames_per_stream[frames[i].stream_id]++;
231 for (FrameCounter::const_iterator it = frames_per_stream.begin();
232 it != frames_per_stream.end(); ++it) {
233 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
234 it->second);
237 return QuicSession::OnStreamFrames(frames);
240 void QuicClientSession::AddObserver(Observer* observer) {
241 if (going_away_)
242 RecordUnexpectedObservers(ADD_OBSERVER);
244 DCHECK(!ContainsKey(observers_, observer));
245 observers_.insert(observer);
248 void QuicClientSession::RemoveObserver(Observer* observer) {
249 DCHECK(ContainsKey(observers_, observer));
250 observers_.erase(observer);
253 int QuicClientSession::TryCreateStream(StreamRequest* request,
254 QuicReliableClientStream** stream) {
255 if (!crypto_stream_->encryption_established()) {
256 DLOG(DFATAL) << "Encryption not established.";
257 return ERR_CONNECTION_CLOSED;
260 if (goaway_received()) {
261 DVLOG(1) << "Going away.";
262 return ERR_CONNECTION_CLOSED;
265 if (!connection()->connected()) {
266 DVLOG(1) << "Already closed.";
267 return ERR_CONNECTION_CLOSED;
270 if (going_away_) {
271 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
272 return ERR_CONNECTION_CLOSED;
275 if (GetNumOpenStreams() < get_max_open_streams()) {
276 *stream = CreateOutgoingReliableStreamImpl();
277 return OK;
280 stream_requests_.push_back(request);
281 return ERR_IO_PENDING;
284 void QuicClientSession::CancelRequest(StreamRequest* request) {
285 // Remove |request| from the queue while preserving the order of the
286 // other elements.
287 StreamRequestQueue::iterator it =
288 std::find(stream_requests_.begin(), stream_requests_.end(), request);
289 if (it != stream_requests_.end()) {
290 it = stream_requests_.erase(it);
294 QuicReliableClientStream* QuicClientSession::CreateOutgoingDataStream() {
295 if (!crypto_stream_->encryption_established()) {
296 DVLOG(1) << "Encryption not active so no outgoing stream created.";
297 return NULL;
299 if (GetNumOpenStreams() >= get_max_open_streams()) {
300 DVLOG(1) << "Failed to create a new outgoing stream. "
301 << "Already " << GetNumOpenStreams() << " open.";
302 return NULL;
304 if (goaway_received()) {
305 DVLOG(1) << "Failed to create a new outgoing stream. "
306 << "Already received goaway.";
307 return NULL;
309 if (going_away_) {
310 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
311 return NULL;
313 return CreateOutgoingReliableStreamImpl();
316 QuicReliableClientStream*
317 QuicClientSession::CreateOutgoingReliableStreamImpl() {
318 DCHECK(connection()->connected());
319 QuicReliableClientStream* stream =
320 new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
321 ActivateStream(stream);
322 ++num_total_streams_;
323 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
324 return stream;
327 QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
328 return crypto_stream_.get();
331 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
332 // we learn about SSL info (sync vs async vs cached).
333 bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
334 ssl_info->Reset();
335 if (!cert_verify_result_) {
336 return false;
339 ssl_info->cert_status = cert_verify_result_->cert_status;
340 ssl_info->cert = cert_verify_result_->verified_cert;
342 // TODO(rtenneti): Figure out what to set for the following.
343 // Temporarily hard coded cipher_suite as 0xc031 to represent
344 // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (from
345 // net/ssl/ssl_cipher_suite_names.cc) and encryption as 256.
346 int cipher_suite = 0xc02f;
347 int ssl_connection_status = 0;
348 ssl_connection_status |=
349 (cipher_suite & SSL_CONNECTION_CIPHERSUITE_MASK) <<
350 SSL_CONNECTION_CIPHERSUITE_SHIFT;
351 ssl_connection_status |=
352 (SSL_CONNECTION_VERSION_TLS1_2 & SSL_CONNECTION_VERSION_MASK) <<
353 SSL_CONNECTION_VERSION_SHIFT;
355 ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
356 ssl_info->is_issued_by_known_root =
357 cert_verify_result_->is_issued_by_known_root;
359 ssl_info->connection_status = ssl_connection_status;
360 ssl_info->client_cert_sent = false;
361 ssl_info->channel_id_sent = false;
362 ssl_info->security_bits = 256;
363 ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
364 return true;
367 int QuicClientSession::CryptoConnect(bool require_confirmation,
368 const CompletionCallback& callback) {
369 require_confirmation_ = require_confirmation;
370 RecordHandshakeState(STATE_STARTED);
371 if (!crypto_stream_->CryptoConnect()) {
372 // TODO(wtc): change crypto_stream_.CryptoConnect() to return a
373 // QuicErrorCode and map it to a net error code.
374 return ERR_CONNECTION_FAILED;
377 bool can_notify = require_confirmation_ ?
378 IsCryptoHandshakeConfirmed() : IsEncryptionEstablished();
379 if (can_notify) {
380 return OK;
383 callback_ = callback;
384 return ERR_IO_PENDING;
387 int QuicClientSession::GetNumSentClientHellos() const {
388 return crypto_stream_->num_sent_client_hellos();
391 bool QuicClientSession::CanPool(const std::string& hostname) const {
392 // TODO(rch): When QUIC supports channel ID or client certificates, this
393 // logic will need to be revised.
394 DCHECK(connection()->connected());
395 SSLInfo ssl_info;
396 bool unused = false;
397 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert) {
398 // We can always pool with insecure QUIC sessions.
399 return true;
401 // Only pool secure QUIC sessions if the cert matches the new hostname.
402 return ssl_info.cert->VerifyNameMatch(hostname, &unused);
405 QuicDataStream* QuicClientSession::CreateIncomingDataStream(
406 QuicStreamId id) {
407 DLOG(ERROR) << "Server push not supported";
408 return NULL;
411 void QuicClientSession::CloseStream(QuicStreamId stream_id) {
412 QuicSession::CloseStream(stream_id);
413 OnClosedStream();
416 void QuicClientSession::SendRstStream(QuicStreamId id,
417 QuicRstStreamErrorCode error,
418 QuicStreamOffset bytes_written) {
419 QuicSession::SendRstStream(id, error, bytes_written);
420 OnClosedStream();
423 void QuicClientSession::OnClosedStream() {
424 if (GetNumOpenStreams() < get_max_open_streams() &&
425 !stream_requests_.empty() &&
426 crypto_stream_->encryption_established() &&
427 !goaway_received() &&
428 !going_away_ &&
429 connection()->connected()) {
430 StreamRequest* request = stream_requests_.front();
431 stream_requests_.pop_front();
432 request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
435 if (GetNumOpenStreams() == 0) {
436 stream_factory_->OnIdleSession(this);
440 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
441 if (!callback_.is_null() &&
442 (!require_confirmation_ || event == HANDSHAKE_CONFIRMED)) {
443 // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
444 // could be called because there are no error events in CryptoHandshakeEvent
445 // enum. If error events are added to CryptoHandshakeEvent, then the
446 // following code needs to changed.
447 base::ResetAndReturn(&callback_).Run(OK);
449 if (event == HANDSHAKE_CONFIRMED) {
450 ObserverSet::iterator it = observers_.begin();
451 while (it != observers_.end()) {
452 Observer* observer = *it;
453 ++it;
454 observer->OnCryptoHandshakeConfirmed();
457 QuicSession::OnCryptoHandshakeEvent(event);
460 void QuicClientSession::OnCryptoHandshakeMessageSent(
461 const CryptoHandshakeMessage& message) {
462 logger_.OnCryptoHandshakeMessageSent(message);
465 void QuicClientSession::OnCryptoHandshakeMessageReceived(
466 const CryptoHandshakeMessage& message) {
467 logger_.OnCryptoHandshakeMessageReceived(message);
470 void QuicClientSession::OnConnectionClosed(QuicErrorCode error,
471 bool from_peer) {
472 DCHECK(!connection()->connected());
473 logger_.OnConnectionClosed(error, from_peer);
474 if (from_peer) {
475 UMA_HISTOGRAM_SPARSE_SLOWLY(
476 "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
477 } else {
478 UMA_HISTOGRAM_SPARSE_SLOWLY(
479 "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
482 if (error == QUIC_CONNECTION_TIMED_OUT) {
483 UMA_HISTOGRAM_COUNTS(
484 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
485 GetNumOpenStreams());
486 if (!IsCryptoHandshakeConfirmed()) {
487 // If there have been any streams created, they were 0-RTT speculative
488 // requests that have not be serviced.
489 UMA_HISTOGRAM_COUNTS(
490 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
491 num_total_streams_);
495 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
496 connection()->version());
497 NotifyFactoryOfSessionGoingAway();
498 if (!callback_.is_null()) {
499 base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
501 socket_->Close();
502 QuicSession::OnConnectionClosed(error, from_peer);
503 DCHECK(streams()->empty());
504 CloseAllStreams(ERR_UNEXPECTED);
505 CloseAllObservers(ERR_UNEXPECTED);
506 NotifyFactoryOfSessionClosedLater();
509 void QuicClientSession::OnSuccessfulVersionNegotiation(
510 const QuicVersion& version) {
511 logger_.OnSuccessfulVersionNegotiation(version);
512 QuicSession::OnSuccessfulVersionNegotiation(version);
515 void QuicClientSession::OnProofValid(
516 const QuicCryptoClientConfig::CachedState& cached) {
517 DCHECK(cached.proof_valid());
519 if (!server_info_ || !server_info_->IsReadyToPersist()) {
520 return;
523 QuicServerInfo::State* state = server_info_->mutable_state();
525 state->server_config = cached.server_config();
526 state->source_address_token = cached.source_address_token();
527 state->server_config_sig = cached.signature();
528 state->certs = cached.certs();
530 server_info_->Persist();
533 void QuicClientSession::OnProofVerifyDetailsAvailable(
534 const ProofVerifyDetails& verify_details) {
535 const CertVerifyResult* cert_verify_result_other =
536 &(reinterpret_cast<const ProofVerifyDetailsChromium*>(
537 &verify_details))->cert_verify_result;
538 CertVerifyResult* result_copy = new CertVerifyResult;
539 result_copy->CopyFrom(*cert_verify_result_other);
540 cert_verify_result_.reset(result_copy);
543 void QuicClientSession::StartReading() {
544 if (read_pending_) {
545 return;
547 read_pending_ = true;
548 int rv = socket_->Read(read_buffer_.get(),
549 read_buffer_->size(),
550 base::Bind(&QuicClientSession::OnReadComplete,
551 weak_factory_.GetWeakPtr()));
552 if (rv == ERR_IO_PENDING) {
553 num_packets_read_ = 0;
554 return;
557 if (++num_packets_read_ > 32) {
558 num_packets_read_ = 0;
559 // Data was read, process it.
560 // Schedule the work through the message loop to avoid recursive
561 // callbacks.
562 base::MessageLoop::current()->PostTask(
563 FROM_HERE,
564 base::Bind(&QuicClientSession::OnReadComplete,
565 weak_factory_.GetWeakPtr(), rv));
566 } else {
567 OnReadComplete(rv);
571 void QuicClientSession::CloseSessionOnError(int error) {
572 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
573 CloseSessionOnErrorInner(error, QUIC_INTERNAL_ERROR);
574 NotifyFactoryOfSessionClosed();
577 void QuicClientSession::CloseSessionOnErrorInner(int net_error,
578 QuicErrorCode quic_error) {
579 if (!callback_.is_null()) {
580 base::ResetAndReturn(&callback_).Run(net_error);
582 CloseAllStreams(net_error);
583 CloseAllObservers(net_error);
584 net_log_.AddEvent(
585 NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
586 NetLog::IntegerCallback("net_error", net_error));
588 connection()->CloseConnection(quic_error, false);
589 DCHECK(!connection()->connected());
592 void QuicClientSession::CloseAllStreams(int net_error) {
593 while (!streams()->empty()) {
594 ReliableQuicStream* stream = streams()->begin()->second;
595 QuicStreamId id = stream->id();
596 static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
597 CloseStream(id);
601 void QuicClientSession::CloseAllObservers(int net_error) {
602 while (!observers_.empty()) {
603 Observer* observer = *observers_.begin();
604 observers_.erase(observer);
605 observer->OnSessionClosed(net_error);
609 base::Value* QuicClientSession::GetInfoAsValue(
610 const std::set<HostPortPair>& aliases) const {
611 base::DictionaryValue* dict = new base::DictionaryValue();
612 // TODO(rch): remove "host_port_pair" when Chrome 34 is stable.
613 dict->SetString("host_port_pair", aliases.begin()->ToString());
614 dict->SetString("version", QuicVersionToString(connection()->version()));
615 dict->SetInteger("open_streams", GetNumOpenStreams());
616 dict->SetInteger("total_streams", num_total_streams_);
617 dict->SetString("peer_address", peer_address().ToString());
618 dict->SetString("connection_id", base::Uint64ToString(connection_id()));
619 dict->SetBoolean("connected", connection()->connected());
620 SSLInfo ssl_info;
621 dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert);
623 base::ListValue* alias_list = new base::ListValue();
624 for (std::set<HostPortPair>::const_iterator it = aliases.begin();
625 it != aliases.end(); it++) {
626 alias_list->Append(new base::StringValue(it->ToString()));
628 dict->Set("aliases", alias_list);
630 return dict;
633 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
634 return weak_factory_.GetWeakPtr();
637 void QuicClientSession::OnReadComplete(int result) {
638 read_pending_ = false;
639 if (result == 0)
640 result = ERR_CONNECTION_CLOSED;
642 if (result < 0) {
643 DVLOG(1) << "Closing session on read error: " << result;
644 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
645 NotifyFactoryOfSessionGoingAway();
646 CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
647 NotifyFactoryOfSessionClosedLater();
648 return;
651 scoped_refptr<IOBufferWithSize> buffer(read_buffer_);
652 read_buffer_ = new IOBufferWithSize(kMaxPacketSize);
653 QuicEncryptedPacket packet(buffer->data(), result);
654 IPEndPoint local_address;
655 IPEndPoint peer_address;
656 socket_->GetLocalAddress(&local_address);
657 socket_->GetPeerAddress(&peer_address);
658 // ProcessUdpPacket might result in |this| being deleted, so we
659 // use a weak pointer to be safe.
660 connection()->ProcessUdpPacket(local_address, peer_address, packet);
661 if (!connection()->connected()) {
662 NotifyFactoryOfSessionClosedLater();
663 return;
665 StartReading();
668 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
669 going_away_ = true;
670 if (stream_factory_)
671 stream_factory_->OnSessionGoingAway(this);
674 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
675 if (!streams()->empty())
676 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
678 if (!going_away_)
679 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
681 going_away_ = true;
682 DCHECK_EQ(0u, GetNumOpenStreams());
683 DCHECK(!connection()->connected());
684 base::MessageLoop::current()->PostTask(
685 FROM_HERE,
686 base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
687 weak_factory_.GetWeakPtr()));
690 void QuicClientSession::NotifyFactoryOfSessionClosed() {
691 if (!streams()->empty())
692 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
694 if (!going_away_)
695 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
697 going_away_ = true;
698 DCHECK_EQ(0u, GetNumOpenStreams());
699 // Will delete |this|.
700 if (stream_factory_)
701 stream_factory_->OnSessionClosed(this);
704 } // namespace net