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