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.
4
5 #include "net/quic/quic_client_session.h"
6
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"
28
29 namespace net {
30
31 namespace {
32
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;
36
37 // Histograms for tracking down the crashes from http://crbug.com/354669
38 // Note: these values must be kept in sync with the corresponding values in:
39 // tools/metrics/histograms/histograms.xml
40 enum Location {
41 DESTRUCTOR = 0,
42 ADD_OBSERVER = 1,
43 TRY_CREATE_STREAM = 2,
44 CREATE_OUTGOING_RELIABLE_STREAM = 3,
45 NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER = 4,
46 NOTIFY_FACTORY_OF_SESSION_CLOSED = 5,
47 NUM_LOCATIONS = 6,
48 };
49
RecordUnexpectedOpenStreams(Location location)50 void RecordUnexpectedOpenStreams(Location location) {
51 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
52 NUM_LOCATIONS);
53 }
54
RecordUnexpectedObservers(Location location)55 void RecordUnexpectedObservers(Location location) {
56 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
57 NUM_LOCATIONS);
58 }
59
RecordUnexpectedNotGoingAway(Location location)60 void RecordUnexpectedNotGoingAway(Location location) {
61 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
62 NUM_LOCATIONS);
63 }
64
65 // Histogram for recording the different reasons that a QUIC session is unable
66 // to complete the handshake.
67 enum HandshakeFailureReason {
68 HANDSHAKE_FAILURE_UNKNOWN = 0,
69 HANDSHAKE_FAILURE_BLACK_HOLE = 1,
70 HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
71 NUM_HANDSHAKE_FAILURE_REASONS = 3,
72 };
73
RecordHandshakeFailureReason(HandshakeFailureReason reason)74 void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
75 UMA_HISTOGRAM_ENUMERATION(
76 "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason",
77 reason, NUM_HANDSHAKE_FAILURE_REASONS);
78 }
79
80 // Note: these values must be kept in sync with the corresponding values in:
81 // tools/metrics/histograms/histograms.xml
82 enum HandshakeState {
83 STATE_STARTED = 0,
84 STATE_ENCRYPTION_ESTABLISHED = 1,
85 STATE_HANDSHAKE_CONFIRMED = 2,
86 STATE_FAILED = 3,
87 NUM_HANDSHAKE_STATES = 4
88 };
89
RecordHandshakeState(HandshakeState state)90 void RecordHandshakeState(HandshakeState state) {
91 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
92 NUM_HANDSHAKE_STATES);
93 }
94
95 } // namespace
96
StreamRequest()97 QuicClientSession::StreamRequest::StreamRequest() : stream_(NULL) {}
98
~StreamRequest()99 QuicClientSession::StreamRequest::~StreamRequest() {
100 CancelRequest();
101 }
102
StartRequest(const base::WeakPtr<QuicClientSession> & session,QuicReliableClientStream ** stream,const CompletionCallback & callback)103 int QuicClientSession::StreamRequest::StartRequest(
104 const base::WeakPtr<QuicClientSession>& session,
105 QuicReliableClientStream** stream,
106 const CompletionCallback& callback) {
107 session_ = session;
108 stream_ = stream;
109 int rv = session_->TryCreateStream(this, stream_);
110 if (rv == ERR_IO_PENDING) {
111 callback_ = callback;
112 }
113
114 return rv;
115 }
116
CancelRequest()117 void QuicClientSession::StreamRequest::CancelRequest() {
118 if (session_)
119 session_->CancelRequest(this);
120 session_.reset();
121 callback_.Reset();
122 }
123
OnRequestCompleteSuccess(QuicReliableClientStream * stream)124 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
125 QuicReliableClientStream* stream) {
126 session_.reset();
127 *stream_ = stream;
128 ResetAndReturn(&callback_).Run(OK);
129 }
130
OnRequestCompleteFailure(int rv)131 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
132 session_.reset();
133 ResetAndReturn(&callback_).Run(rv);
134 }
135
QuicClientSession(QuicConnection * connection,scoped_ptr<DatagramClientSocket> socket,QuicStreamFactory * stream_factory,TransportSecurityState * transport_security_state,scoped_ptr<QuicServerInfo> server_info,const QuicConfig & config,base::TaskRunner * task_runner,NetLog * net_log)136 QuicClientSession::QuicClientSession(
137 QuicConnection* connection,
138 scoped_ptr<DatagramClientSocket> socket,
139 QuicStreamFactory* stream_factory,
140 TransportSecurityState* transport_security_state,
141 scoped_ptr<QuicServerInfo> server_info,
142 const QuicConfig& config,
143 base::TaskRunner* task_runner,
144 NetLog* net_log)
145 : QuicClientSessionBase(connection, config),
146 require_confirmation_(false),
147 stream_factory_(stream_factory),
148 socket_(socket.Pass()),
149 read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
150 transport_security_state_(transport_security_state),
151 server_info_(server_info.Pass()),
152 read_pending_(false),
153 num_total_streams_(0),
154 task_runner_(task_runner),
155 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
156 logger_(new QuicConnectionLogger(net_log_)),
157 num_packets_read_(0),
158 going_away_(false),
159 weak_factory_(this) {
160 connection->set_debug_visitor(logger_);
161 }
162
InitializeSession(const QuicServerId & server_id,QuicCryptoClientConfig * crypto_config,QuicCryptoClientStreamFactory * crypto_client_stream_factory)163 void QuicClientSession::InitializeSession(
164 const QuicServerId& server_id,
165 QuicCryptoClientConfig* crypto_config,
166 QuicCryptoClientStreamFactory* crypto_client_stream_factory) {
167 server_host_port_ = server_id.host_port_pair();
168 crypto_stream_.reset(
169 crypto_client_stream_factory ?
170 crypto_client_stream_factory->CreateQuicCryptoClientStream(
171 server_id, this, crypto_config) :
172 new QuicCryptoClientStream(server_id, this,
173 new ProofVerifyContextChromium(net_log_),
174 crypto_config));
175 QuicClientSessionBase::InitializeSession();
176 // TODO(rch): pass in full host port proxy pair
177 net_log_.BeginEvent(
178 NetLog::TYPE_QUIC_SESSION,
179 NetLog::StringCallback("host", &server_id.host()));
180 }
181
~QuicClientSession()182 QuicClientSession::~QuicClientSession() {
183 if (!streams()->empty())
184 RecordUnexpectedOpenStreams(DESTRUCTOR);
185 if (!observers_.empty())
186 RecordUnexpectedObservers(DESTRUCTOR);
187 if (!going_away_)
188 RecordUnexpectedNotGoingAway(DESTRUCTOR);
189
190 while (!streams()->empty() ||
191 !observers_.empty() ||
192 !stream_requests_.empty()) {
193 // The session must be closed before it is destroyed.
194 DCHECK(streams()->empty());
195 CloseAllStreams(ERR_UNEXPECTED);
196 DCHECK(observers_.empty());
197 CloseAllObservers(ERR_UNEXPECTED);
198
199 connection()->set_debug_visitor(NULL);
200 net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
201
202 while (!stream_requests_.empty()) {
203 StreamRequest* request = stream_requests_.front();
204 stream_requests_.pop_front();
205 request->OnRequestCompleteFailure(ERR_ABORTED);
206 }
207 }
208
209 if (connection()->connected()) {
210 // Ensure that the connection is closed by the time the session is
211 // destroyed.
212 connection()->CloseConnection(QUIC_INTERNAL_ERROR, false);
213 }
214
215 if (IsEncryptionEstablished())
216 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
217 if (IsCryptoHandshakeConfirmed())
218 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
219 else
220 RecordHandshakeState(STATE_FAILED);
221
222 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
223 UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
224 crypto_stream_->num_sent_client_hellos());
225 if (!IsCryptoHandshakeConfirmed())
226 return;
227
228 // Sending one client_hello means we had zero handshake-round-trips.
229 int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
230
231 // Don't bother with these histogram during tests, which mock out
232 // num_sent_client_hellos().
233 if (round_trip_handshakes < 0 || !stream_factory_)
234 return;
235
236 bool port_selected = stream_factory_->enable_port_selection();
237 SSLInfo ssl_info;
238 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
239 if (port_selected) {
240 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
241 round_trip_handshakes, 0, 3, 4);
242 } else {
243 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
244 round_trip_handshakes, 0, 3, 4);
245 if (require_confirmation_) {
246 UMA_HISTOGRAM_CUSTOM_COUNTS(
247 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
248 round_trip_handshakes, 0, 3, 4);
249 }
250 }
251 } else {
252 if (port_selected) {
253 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
254 round_trip_handshakes, 0, 3, 4);
255 } else {
256 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
257 round_trip_handshakes, 0, 3, 4);
258 if (require_confirmation_) {
259 UMA_HISTOGRAM_CUSTOM_COUNTS(
260 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
261 round_trip_handshakes, 0, 3, 4);
262 }
263 }
264 }
265 const QuicConnectionStats stats = connection()->GetStats();
266 if (stats.max_sequence_reordering == 0)
267 return;
268 const uint64 kMaxReordering = 100;
269 uint64 reordering = kMaxReordering;
270 if (stats.min_rtt_us > 0 ) {
271 reordering =
272 GG_UINT64_C(100) * stats.max_time_reordering_us / stats.min_rtt_us;
273 }
274 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime",
275 reordering, 0, kMaxReordering, 50);
276 if (stats.min_rtt_us > 100 * 1000) {
277 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
278 reordering, 0, kMaxReordering, 50);
279 }
280 UMA_HISTOGRAM_COUNTS("Net.QuicSession.MaxReordering",
281 stats.max_sequence_reordering);
282 }
283
OnStreamFrames(const std::vector<QuicStreamFrame> & frames)284 void QuicClientSession::OnStreamFrames(
285 const std::vector<QuicStreamFrame>& frames) {
286 // Record total number of stream frames.
287 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", frames.size());
288
289 // Record number of frames per stream in packet.
290 typedef std::map<QuicStreamId, size_t> FrameCounter;
291 FrameCounter frames_per_stream;
292 for (size_t i = 0; i < frames.size(); ++i) {
293 frames_per_stream[frames[i].stream_id]++;
294 }
295 for (FrameCounter::const_iterator it = frames_per_stream.begin();
296 it != frames_per_stream.end(); ++it) {
297 UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket",
298 it->second);
299 }
300
301 return QuicSession::OnStreamFrames(frames);
302 }
303
AddObserver(Observer * observer)304 void QuicClientSession::AddObserver(Observer* observer) {
305 if (going_away_) {
306 RecordUnexpectedObservers(ADD_OBSERVER);
307 observer->OnSessionClosed(ERR_UNEXPECTED);
308 return;
309 }
310
311 DCHECK(!ContainsKey(observers_, observer));
312 observers_.insert(observer);
313 }
314
RemoveObserver(Observer * observer)315 void QuicClientSession::RemoveObserver(Observer* observer) {
316 DCHECK(ContainsKey(observers_, observer));
317 observers_.erase(observer);
318 }
319
TryCreateStream(StreamRequest * request,QuicReliableClientStream ** stream)320 int QuicClientSession::TryCreateStream(StreamRequest* request,
321 QuicReliableClientStream** stream) {
322 if (!crypto_stream_->encryption_established()) {
323 DLOG(DFATAL) << "Encryption not established.";
324 return ERR_CONNECTION_CLOSED;
325 }
326
327 if (goaway_received()) {
328 DVLOG(1) << "Going away.";
329 return ERR_CONNECTION_CLOSED;
330 }
331
332 if (!connection()->connected()) {
333 DVLOG(1) << "Already closed.";
334 return ERR_CONNECTION_CLOSED;
335 }
336
337 if (going_away_) {
338 RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
339 return ERR_CONNECTION_CLOSED;
340 }
341
342 if (GetNumOpenStreams() < get_max_open_streams()) {
343 *stream = CreateOutgoingReliableStreamImpl();
344 return OK;
345 }
346
347 stream_requests_.push_back(request);
348 return ERR_IO_PENDING;
349 }
350
CancelRequest(StreamRequest * request)351 void QuicClientSession::CancelRequest(StreamRequest* request) {
352 // Remove |request| from the queue while preserving the order of the
353 // other elements.
354 StreamRequestQueue::iterator it =
355 std::find(stream_requests_.begin(), stream_requests_.end(), request);
356 if (it != stream_requests_.end()) {
357 it = stream_requests_.erase(it);
358 }
359 }
360
CreateOutgoingDataStream()361 QuicReliableClientStream* QuicClientSession::CreateOutgoingDataStream() {
362 if (!crypto_stream_->encryption_established()) {
363 DVLOG(1) << "Encryption not active so no outgoing stream created.";
364 return NULL;
365 }
366 if (GetNumOpenStreams() >= get_max_open_streams()) {
367 DVLOG(1) << "Failed to create a new outgoing stream. "
368 << "Already " << GetNumOpenStreams() << " open.";
369 return NULL;
370 }
371 if (goaway_received()) {
372 DVLOG(1) << "Failed to create a new outgoing stream. "
373 << "Already received goaway.";
374 return NULL;
375 }
376 if (going_away_) {
377 RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
378 return NULL;
379 }
380 return CreateOutgoingReliableStreamImpl();
381 }
382
383 QuicReliableClientStream*
CreateOutgoingReliableStreamImpl()384 QuicClientSession::CreateOutgoingReliableStreamImpl() {
385 DCHECK(connection()->connected());
386 QuicReliableClientStream* stream =
387 new QuicReliableClientStream(GetNextStreamId(), this, net_log_);
388 ActivateStream(stream);
389 ++num_total_streams_;
390 UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams", GetNumOpenStreams());
391 return stream;
392 }
393
GetCryptoStream()394 QuicCryptoClientStream* QuicClientSession::GetCryptoStream() {
395 return crypto_stream_.get();
396 };
397
398 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
399 // we learn about SSL info (sync vs async vs cached).
GetSSLInfo(SSLInfo * ssl_info) const400 bool QuicClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
401 ssl_info->Reset();
402 if (!cert_verify_result_) {
403 return false;
404 }
405
406 ssl_info->cert_status = cert_verify_result_->cert_status;
407 ssl_info->cert = cert_verify_result_->verified_cert;
408
409 // TODO(wtc): Define QUIC "cipher suites".
410 // Report the TLS cipher suite that most closely resembles the crypto
411 // parameters of the QUIC connection.
412 QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
413 int cipher_suite;
414 int security_bits;
415 switch (aead) {
416 case kAESG:
417 cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
418 security_bits = 128;
419 break;
420 case kCC12:
421 cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
422 security_bits = 256;
423 break;
424 default:
425 NOTREACHED();
426 return false;
427 }
428 int ssl_connection_status = 0;
429 ssl_connection_status |=
430 (cipher_suite & SSL_CONNECTION_CIPHERSUITE_MASK) <<
431 SSL_CONNECTION_CIPHERSUITE_SHIFT;
432 ssl_connection_status |=
433 (SSL_CONNECTION_VERSION_QUIC & SSL_CONNECTION_VERSION_MASK) <<
434 SSL_CONNECTION_VERSION_SHIFT;
435
436 ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
437 ssl_info->is_issued_by_known_root =
438 cert_verify_result_->is_issued_by_known_root;
439
440 ssl_info->connection_status = ssl_connection_status;
441 ssl_info->client_cert_sent = false;
442 ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent();
443 ssl_info->security_bits = security_bits;
444 ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
445 ssl_info->pinning_failure_log = pinning_failure_log_;
446 return true;
447 }
448
CryptoConnect(bool require_confirmation,const CompletionCallback & callback)449 int QuicClientSession::CryptoConnect(bool require_confirmation,
450 const CompletionCallback& callback) {
451 require_confirmation_ = require_confirmation;
452 handshake_start_ = base::TimeTicks::Now();
453 RecordHandshakeState(STATE_STARTED);
454 DCHECK(flow_controller());
455 if (!crypto_stream_->CryptoConnect()) {
456 // TODO(wtc): change crypto_stream_.CryptoConnect() to return a
457 // QuicErrorCode and map it to a net error code.
458 return ERR_CONNECTION_FAILED;
459 }
460
461 if (IsCryptoHandshakeConfirmed())
462 return OK;
463
464 // Unless we require handshake confirmation, activate the session if
465 // we have established initial encryption.
466 if (!require_confirmation_ && IsEncryptionEstablished()) {
467 // To mitigate the effects of hanging 0-RTT connections, set up a timer to
468 // cancel any requests, if the handshake takes too long.
469 task_runner_->PostDelayedTask(
470 FROM_HERE,
471 base::Bind(&QuicClientSession::OnConnectTimeout,
472 weak_factory_.GetWeakPtr()),
473 base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs));
474 return OK;
475
476 }
477
478 callback_ = callback;
479 return ERR_IO_PENDING;
480 }
481
ResumeCryptoConnect(const CompletionCallback & callback)482 int QuicClientSession::ResumeCryptoConnect(const CompletionCallback& callback) {
483
484 if (IsCryptoHandshakeConfirmed())
485 return OK;
486
487 if (!connection()->connected())
488 return ERR_QUIC_HANDSHAKE_FAILED;
489
490 callback_ = callback;
491 return ERR_IO_PENDING;
492 }
493
GetNumSentClientHellos() const494 int QuicClientSession::GetNumSentClientHellos() const {
495 return crypto_stream_->num_sent_client_hellos();
496 }
497
CanPool(const std::string & hostname) const498 bool QuicClientSession::CanPool(const std::string& hostname) const {
499 DCHECK(connection()->connected());
500 SSLInfo ssl_info;
501 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
502 // We can always pool with insecure QUIC sessions.
503 return true;
504 }
505
506 return SpdySession::CanPool(transport_security_state_, ssl_info,
507 server_host_port_.host(), hostname);
508 }
509
CreateIncomingDataStream(QuicStreamId id)510 QuicDataStream* QuicClientSession::CreateIncomingDataStream(
511 QuicStreamId id) {
512 DLOG(ERROR) << "Server push not supported";
513 return NULL;
514 }
515
CloseStream(QuicStreamId stream_id)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());
522 }
523 QuicSession::CloseStream(stream_id);
524 OnClosedStream();
525 }
526
SendRstStream(QuicStreamId id,QuicRstStreamErrorCode error,QuicStreamOffset bytes_written)527 void QuicClientSession::SendRstStream(QuicStreamId id,
528 QuicRstStreamErrorCode error,
529 QuicStreamOffset bytes_written) {
530 QuicSession::SendRstStream(id, error, bytes_written);
531 OnClosedStream();
532 }
533
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());
544 }
545
546 if (GetNumOpenStreams() == 0) {
547 stream_factory_->OnIdleSession(this);
548 }
549 }
550
OnCryptoHandshakeEvent(CryptoHandshakeEvent event)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);
559 }
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();
568 }
569 }
570 QuicSession::OnCryptoHandshakeEvent(event);
571 }
572
OnCryptoHandshakeMessageSent(const CryptoHandshakeMessage & message)573 void QuicClientSession::OnCryptoHandshakeMessageSent(
574 const CryptoHandshakeMessage& message) {
575 logger_->OnCryptoHandshakeMessageSent(message);
576 }
577
OnCryptoHandshakeMessageReceived(const CryptoHandshakeMessage & message)578 void QuicClientSession::OnCryptoHandshakeMessageReceived(
579 const CryptoHandshakeMessage& message) {
580 logger_->OnCryptoHandshakeMessageReceived(message);
581 }
582
OnConnectionClosed(QuicErrorCode error,bool from_peer)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);
593 }
594
595 if (error == QUIC_CONNECTION_TIMED_OUT) {
596 UMA_HISTOGRAM_COUNTS(
597 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
598 GetNumOpenStreams());
599 if (IsCryptoHandshakeConfirmed()) {
600 if (GetNumOpenStreams() > 0) {
601 UMA_HISTOGRAM_BOOLEAN(
602 "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
603 connection()->sent_packet_manager().HasUnackedPackets());
604 UMA_HISTOGRAM_COUNTS(
605 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
606 connection()->sent_packet_manager().consecutive_rto_count());
607 UMA_HISTOGRAM_COUNTS(
608 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
609 connection()->sent_packet_manager().consecutive_tlp_count());
610 }
611 } else {
612 UMA_HISTOGRAM_COUNTS(
613 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
614 GetNumOpenStreams());
615 UMA_HISTOGRAM_COUNTS(
616 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
617 num_total_streams_);
618 }
619 }
620
621 if (!IsCryptoHandshakeConfirmed()) {
622 if (error == QUIC_PUBLIC_RESET) {
623 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
624 } else if (connection()->GetStats().packets_received == 0) {
625 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
626 UMA_HISTOGRAM_SPARSE_SLOWLY(
627 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
628 error);
629 } else {
630 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
631 UMA_HISTOGRAM_SPARSE_SLOWLY(
632 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
633 error);
634 }
635 }
636
637 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
638 connection()->version());
639 NotifyFactoryOfSessionGoingAway();
640 if (!callback_.is_null()) {
641 base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
642 }
643 socket_->Close();
644 QuicSession::OnConnectionClosed(error, from_peer);
645 DCHECK(streams()->empty());
646 CloseAllStreams(ERR_UNEXPECTED);
647 CloseAllObservers(ERR_UNEXPECTED);
648 NotifyFactoryOfSessionClosedLater();
649 }
650
OnSuccessfulVersionNegotiation(const QuicVersion & version)651 void QuicClientSession::OnSuccessfulVersionNegotiation(
652 const QuicVersion& version) {
653 logger_->OnSuccessfulVersionNegotiation(version);
654 QuicSession::OnSuccessfulVersionNegotiation(version);
655 }
656
OnProofValid(const QuicCryptoClientConfig::CachedState & cached)657 void QuicClientSession::OnProofValid(
658 const QuicCryptoClientConfig::CachedState& cached) {
659 DCHECK(cached.proof_valid());
660
661 if (!server_info_ || !server_info_->IsReadyToPersist()) {
662 return;
663 }
664
665 QuicServerInfo::State* state = server_info_->mutable_state();
666
667 state->server_config = cached.server_config();
668 state->source_address_token = cached.source_address_token();
669 state->server_config_sig = cached.signature();
670 state->certs = cached.certs();
671
672 server_info_->Persist();
673 }
674
OnProofVerifyDetailsAvailable(const ProofVerifyDetails & verify_details)675 void QuicClientSession::OnProofVerifyDetailsAvailable(
676 const ProofVerifyDetails& verify_details) {
677 const ProofVerifyDetailsChromium* verify_details_chromium =
678 reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
679 CertVerifyResult* result_copy = new CertVerifyResult;
680 result_copy->CopyFrom(verify_details_chromium->cert_verify_result);
681 cert_verify_result_.reset(result_copy);
682 pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
683 logger_->OnCertificateVerified(*cert_verify_result_);
684 }
685
StartReading()686 void QuicClientSession::StartReading() {
687 if (read_pending_) {
688 return;
689 }
690 read_pending_ = true;
691 int rv = socket_->Read(read_buffer_.get(),
692 read_buffer_->size(),
693 base::Bind(&QuicClientSession::OnReadComplete,
694 weak_factory_.GetWeakPtr()));
695 if (rv == ERR_IO_PENDING) {
696 num_packets_read_ = 0;
697 return;
698 }
699
700 if (++num_packets_read_ > 32) {
701 num_packets_read_ = 0;
702 // Data was read, process it.
703 // Schedule the work through the message loop to 1) prevent infinite
704 // recursion and 2) avoid blocking the thread for too long.
705 base::MessageLoop::current()->PostTask(
706 FROM_HERE,
707 base::Bind(&QuicClientSession::OnReadComplete,
708 weak_factory_.GetWeakPtr(), rv));
709 } else {
710 OnReadComplete(rv);
711 }
712 }
713
CloseSessionOnError(int error)714 void QuicClientSession::CloseSessionOnError(int error) {
715 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
716 CloseSessionOnErrorInner(error, QUIC_INTERNAL_ERROR);
717 NotifyFactoryOfSessionClosed();
718 }
719
CloseSessionOnErrorInner(int net_error,QuicErrorCode quic_error)720 void QuicClientSession::CloseSessionOnErrorInner(int net_error,
721 QuicErrorCode quic_error) {
722 if (!callback_.is_null()) {
723 base::ResetAndReturn(&callback_).Run(net_error);
724 }
725 CloseAllStreams(net_error);
726 CloseAllObservers(net_error);
727 net_log_.AddEvent(
728 NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
729 NetLog::IntegerCallback("net_error", net_error));
730
731 if (connection()->connected())
732 connection()->CloseConnection(quic_error, false);
733 DCHECK(!connection()->connected());
734 }
735
CloseAllStreams(int net_error)736 void QuicClientSession::CloseAllStreams(int net_error) {
737 while (!streams()->empty()) {
738 ReliableQuicStream* stream = streams()->begin()->second;
739 QuicStreamId id = stream->id();
740 static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
741 CloseStream(id);
742 }
743 }
744
CloseAllObservers(int net_error)745 void QuicClientSession::CloseAllObservers(int net_error) {
746 while (!observers_.empty()) {
747 Observer* observer = *observers_.begin();
748 observers_.erase(observer);
749 observer->OnSessionClosed(net_error);
750 }
751 }
752
GetInfoAsValue(const std::set<HostPortPair> & aliases)753 base::Value* QuicClientSession::GetInfoAsValue(
754 const std::set<HostPortPair>& aliases) {
755 base::DictionaryValue* dict = new base::DictionaryValue();
756 dict->SetString("version", QuicVersionToString(connection()->version()));
757 dict->SetInteger("open_streams", GetNumOpenStreams());
758 base::ListValue* stream_list = new base::ListValue();
759 for (base::hash_map<QuicStreamId, QuicDataStream*>::const_iterator it
760 = streams()->begin();
761 it != streams()->end();
762 ++it) {
763 stream_list->Append(new base::StringValue(
764 base::Uint64ToString(it->second->id())));
765 }
766 dict->Set("active_streams", stream_list);
767
768 dict->SetInteger("total_streams", num_total_streams_);
769 dict->SetString("peer_address", peer_address().ToString());
770 dict->SetString("connection_id", base::Uint64ToString(connection_id()));
771 dict->SetBoolean("connected", connection()->connected());
772 const QuicConnectionStats& stats = connection()->GetStats();
773 dict->SetInteger("packets_sent", stats.packets_sent);
774 dict->SetInteger("packets_received", stats.packets_received);
775 dict->SetInteger("packets_lost", stats.packets_lost);
776 SSLInfo ssl_info;
777 dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
778
779 base::ListValue* alias_list = new base::ListValue();
780 for (std::set<HostPortPair>::const_iterator it = aliases.begin();
781 it != aliases.end(); it++) {
782 alias_list->Append(new base::StringValue(it->ToString()));
783 }
784 dict->Set("aliases", alias_list);
785
786 return dict;
787 }
788
GetWeakPtr()789 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
790 return weak_factory_.GetWeakPtr();
791 }
792
OnReadComplete(int result)793 void QuicClientSession::OnReadComplete(int result) {
794 read_pending_ = false;
795 if (result == 0)
796 result = ERR_CONNECTION_CLOSED;
797
798 if (result < 0) {
799 DVLOG(1) << "Closing session on read error: " << result;
800 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
801 NotifyFactoryOfSessionGoingAway();
802 CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
803 NotifyFactoryOfSessionClosedLater();
804 return;
805 }
806
807 QuicEncryptedPacket packet(read_buffer_->data(), result);
808 IPEndPoint local_address;
809 IPEndPoint peer_address;
810 socket_->GetLocalAddress(&local_address);
811 socket_->GetPeerAddress(&peer_address);
812 // ProcessUdpPacket might result in |this| being deleted, so we
813 // use a weak pointer to be safe.
814 connection()->ProcessUdpPacket(local_address, peer_address, packet);
815 if (!connection()->connected()) {
816 NotifyFactoryOfSessionClosedLater();
817 return;
818 }
819 StartReading();
820 }
821
NotifyFactoryOfSessionGoingAway()822 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
823 going_away_ = true;
824 if (stream_factory_)
825 stream_factory_->OnSessionGoingAway(this);
826 }
827
NotifyFactoryOfSessionClosedLater()828 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
829 if (!streams()->empty())
830 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
831
832 if (!going_away_)
833 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
834
835 going_away_ = true;
836 DCHECK_EQ(0u, GetNumOpenStreams());
837 DCHECK(!connection()->connected());
838 base::MessageLoop::current()->PostTask(
839 FROM_HERE,
840 base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
841 weak_factory_.GetWeakPtr()));
842 }
843
NotifyFactoryOfSessionClosed()844 void QuicClientSession::NotifyFactoryOfSessionClosed() {
845 if (!streams()->empty())
846 RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
847
848 if (!going_away_)
849 RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
850
851 going_away_ = true;
852 DCHECK_EQ(0u, GetNumOpenStreams());
853 // Will delete |this|.
854 if (stream_factory_)
855 stream_factory_->OnSessionClosed(this);
856 }
857
OnConnectTimeout()858 void QuicClientSession::OnConnectTimeout() {
859 DCHECK(callback_.is_null());
860 DCHECK(IsEncryptionEstablished());
861
862 if (IsCryptoHandshakeConfirmed())
863 return;
864
865 // TODO(rch): re-enable this code once beta is cut.
866 // if (stream_factory_)
867 // stream_factory_->OnSessionConnectTimeout(this);
868 // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
869 // DCHECK_EQ(0u, GetNumOpenStreams());
870 }
871
872 } // namespace net
873