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