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