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"
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
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,
44 void RecordUnexpectedOpenStreams(Location location
) {
45 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location
,
49 void RecordUnexpectedObservers(Location location
) {
50 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location
,
54 void RecordUnexpectedNotGoingAway(Location location
) {
55 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location
,
59 // Note: these values must be kept in sync with the corresponding values in:
60 // tools/metrics/histograms/histograms.xml
63 STATE_ENCRYPTION_ESTABLISHED
= 1,
64 STATE_HANDSHAKE_CONFIRMED
= 2,
66 NUM_HANDSHAKE_STATES
= 4
69 void RecordHandshakeState(HandshakeState state
) {
70 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state
,
71 NUM_HANDSHAKE_STATES
);
76 QuicClientSession::StreamRequest::StreamRequest() : stream_(NULL
) {}
78 QuicClientSession::StreamRequest::~StreamRequest() {
82 int QuicClientSession::StreamRequest::StartRequest(
83 const base::WeakPtr
<QuicClientSession
>& session
,
84 QuicReliableClientStream
** stream
,
85 const CompletionCallback
& callback
) {
88 int rv
= session_
->TryCreateStream(this, stream_
);
89 if (rv
== ERR_IO_PENDING
) {
96 void QuicClientSession::StreamRequest::CancelRequest() {
98 session_
->CancelRequest(this);
103 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
104 QuicReliableClientStream
* stream
) {
107 ResetAndReturn(&callback_
).Run(OK
);
110 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv
) {
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
,
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
)),
137 num_packets_read_(0),
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_
),
148 connection
->set_debug_visitor(&logger_
);
149 // TODO(rch): pass in full host port proxy pair
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
);
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
);
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())
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_
)
199 bool port_selected
= stream_factory_
->enable_port_selection();
201 if (!GetSSLInfo(&ssl_info
) || !ssl_info
.cert
) {
203 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
204 round_trip_handshakes
, 0, 3, 4);
206 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
207 round_trip_handshakes
, 0, 3, 4);
211 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
212 round_trip_handshakes
, 0, 3, 4);
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",
237 return QuicSession::OnStreamFrames(frames
);
240 void QuicClientSession::AddObserver(Observer
* observer
) {
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
;
271 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM
);
272 return ERR_CONNECTION_CLOSED
;
275 if (GetNumOpenStreams() < get_max_open_streams()) {
276 *stream
= CreateOutgoingReliableStreamImpl();
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
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.";
299 if (GetNumOpenStreams() >= get_max_open_streams()) {
300 DVLOG(1) << "Failed to create a new outgoing stream. "
301 << "Already " << GetNumOpenStreams() << " open.";
304 if (goaway_received()) {
305 DVLOG(1) << "Failed to create a new outgoing stream. "
306 << "Already received goaway.";
310 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM
);
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());
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 {
335 if (!cert_verify_result_
) {
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
;
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();
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());
397 if (!GetSSLInfo(&ssl_info
) || !ssl_info
.cert
) {
398 // We can always pool with insecure QUIC sessions.
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(
407 DLOG(ERROR
) << "Server push not supported";
411 void QuicClientSession::CloseStream(QuicStreamId stream_id
) {
412 QuicSession::CloseStream(stream_id
);
416 void QuicClientSession::SendRstStream(QuicStreamId id
,
417 QuicRstStreamErrorCode error
,
418 QuicStreamOffset bytes_written
) {
419 QuicSession::SendRstStream(id
, error
, bytes_written
);
423 void QuicClientSession::OnClosedStream() {
424 if (GetNumOpenStreams() < get_max_open_streams() &&
425 !stream_requests_
.empty() &&
426 crypto_stream_
->encryption_established() &&
427 !goaway_received() &&
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
;
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
,
472 DCHECK(!connection()->connected());
473 logger_
.OnConnectionClosed(error
, from_peer
);
475 UMA_HISTOGRAM_SPARSE_SLOWLY(
476 "Net.QuicSession.ConnectionCloseErrorCodeServer", error
);
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",
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
);
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()) {
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() {
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;
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
562 base::MessageLoop::current()->PostTask(
564 base::Bind(&QuicClientSession::OnReadComplete
,
565 weak_factory_
.GetWeakPtr(), 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
);
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
);
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());
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
);
633 base::WeakPtr
<QuicClientSession
> QuicClientSession::GetWeakPtr() {
634 return weak_factory_
.GetWeakPtr();
637 void QuicClientSession::OnReadComplete(int result
) {
638 read_pending_
= false;
640 result
= ERR_CONNECTION_CLOSED
;
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();
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();
668 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
671 stream_factory_
->OnSessionGoingAway(this);
674 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
675 if (!streams()->empty())
676 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER
);
679 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER
);
682 DCHECK_EQ(0u, GetNumOpenStreams());
683 DCHECK(!connection()->connected());
684 base::MessageLoop::current()->PostTask(
686 base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed
,
687 weak_factory_
.GetWeakPtr()));
690 void QuicClientSession::NotifyFactoryOfSessionClosed() {
691 if (!streams()->empty())
692 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED
);
695 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED
);
698 DCHECK_EQ(0u, GetNumOpenStreams());
699 // Will delete |this|.
701 stream_factory_
->OnSessionClosed(this);