Upstream version 9.37.195.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/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
48 void RecordUnexpectedOpenStreams(Location location) {
49   UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
50                             NUM_LOCATIONS);
51 }
52
53 void RecordUnexpectedObservers(Location location) {
54   UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
55                             NUM_LOCATIONS);
56 }
57
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
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
88 void RecordHandshakeState(HandshakeState state) {
89   UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
90                             NUM_HANDSHAKE_STATES);
91 }
92
93 }  // namespace
94
95 QuicClientSession::StreamRequest::StreamRequest() : stream_(NULL) {}
96
97 QuicClientSession::StreamRequest::~StreamRequest() {
98   CancelRequest();
99 }
100
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
115 void QuicClientSession::StreamRequest::CancelRequest() {
116   if (session_)
117     session_->CancelRequest(this);
118   session_.reset();
119   callback_.Reset();
120 }
121
122 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
123     QuicReliableClientStream* stream) {
124   session_.reset();
125   *stream_ = stream;
126   ResetAndReturn(&callback_).Run(OK);
127 }
128
129 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
130   session_.reset();
131   ResetAndReturn(&callback_).Run(rv);
132 }
133
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
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
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
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
300 void QuicClientSession::RemoveObserver(Observer* observer) {
301   DCHECK(ContainsKey(observers_, observer));
302   observers_.erase(observer);
303 }
304
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
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
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*
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
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).
385 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
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
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
478 int QuicClientSession::GetNumSentClientHellos() const {
479   return crypto_stream_->num_sent_client_hellos();
480 }
481
482 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
503 QuicDataStream* QuicClientSession::CreateIncomingDataStream(
504     QuicStreamId id) {
505   DLOG(ERROR) << "Server push not supported";
506   return NULL;
507 }
508
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
520 void QuicClientSession::SendRstStream(QuicStreamId id,
521                                       QuicRstStreamErrorCode error,
522                                       QuicStreamOffset bytes_written) {
523   QuicSession::SendRstStream(id, error, bytes_written);
524   OnClosedStream();
525 }
526
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
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
566 void QuicClientSession::OnCryptoHandshakeMessageSent(
567     const CryptoHandshakeMessage& message) {
568   logger_.OnCryptoHandshakeMessageSent(message);
569 }
570
571 void QuicClientSession::OnCryptoHandshakeMessageReceived(
572     const CryptoHandshakeMessage& message) {
573   logger_.OnCryptoHandshakeMessageReceived(message);
574 }
575
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
632 void QuicClientSession::OnSuccessfulVersionNegotiation(
633     const QuicVersion& version) {
634   logger_.OnSuccessfulVersionNegotiation(version);
635   QuicSession::OnSuccessfulVersionNegotiation(version);
636 }
637
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
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
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
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
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
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
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
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
771 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
772   return weak_factory_.GetWeakPtr();
773 }
774
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
804 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
805   going_away_ = true;
806   if (stream_factory_)
807     stream_factory_->OnSessionGoingAway(this);
808 }
809
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
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
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