Upstream version 10.39.225.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_server_id.h"
22 #include "net/quic/quic_stream_factory.h"
23 #include "net/spdy/spdy_session.h"
24 #include "net/ssl/channel_id_service.h"
25 #include "net/ssl/ssl_connection_status_flags.h"
26 #include "net/ssl/ssl_info.h"
27 #include "net/udp/datagram_client_socket.h"
28
29 namespace net {
30
31 namespace {
32
33 // The length of time to wait for a 0-RTT handshake to complete
34 // before allowing the requests to possibly proceed over TCP.
35 const int k0RttHandshakeTimeoutMs = 300;
36
37 // Histograms for tracking down the crashes from http://crbug.com/354669
38 // Note: these values must be kept in sync with the corresponding values in:
39 // tools/metrics/histograms/histograms.xml
40 enum Location {
41   DESTRUCTOR = 0,
42   ADD_OBSERVER = 1,
43   TRY_CREATE_STREAM = 2,
44   CREATE_OUTGOING_RELIABLE_STREAM = 3,
45   NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER = 4,
46   NOTIFY_FACTORY_OF_SESSION_CLOSED = 5,
47   NUM_LOCATIONS = 6,
48 };
49
50 void RecordUnexpectedOpenStreams(Location location) {
51   UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
52                             NUM_LOCATIONS);
53 }
54
55 void RecordUnexpectedObservers(Location location) {
56   UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
57                             NUM_LOCATIONS);
58 }
59
60 void RecordUnexpectedNotGoingAway(Location location) {
61   UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
62                             NUM_LOCATIONS);
63 }
64
65 // Histogram for recording the different reasons that a QUIC session is unable
66 // to complete the handshake.
67 enum HandshakeFailureReason {
68   HANDSHAKE_FAILURE_UNKNOWN = 0,
69   HANDSHAKE_FAILURE_BLACK_HOLE = 1,
70   HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
71   NUM_HANDSHAKE_FAILURE_REASONS = 3,
72 };
73
74 void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
75   UMA_HISTOGRAM_ENUMERATION(
76       "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason",
77       reason, NUM_HANDSHAKE_FAILURE_REASONS);
78 }
79
80 // Note: these values must be kept in sync with the corresponding values in:
81 // tools/metrics/histograms/histograms.xml
82 enum HandshakeState {
83   STATE_STARTED = 0,
84   STATE_ENCRYPTION_ESTABLISHED = 1,
85   STATE_HANDSHAKE_CONFIRMED = 2,
86   STATE_FAILED = 3,
87   NUM_HANDSHAKE_STATES = 4
88 };
89
90 void RecordHandshakeState(HandshakeState state) {
91   UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
92                             NUM_HANDSHAKE_STATES);
93 }
94
95 }  // namespace
96
97 QuicClientSession::StreamRequest::StreamRequest() : stream_(NULL) {}
98
99 QuicClientSession::StreamRequest::~StreamRequest() {
100   CancelRequest();
101 }
102
103 int QuicClientSession::StreamRequest::StartRequest(
104     const base::WeakPtr<QuicClientSession>& session,
105     QuicReliableClientStream** stream,
106     const CompletionCallback& callback) {
107   session_ = session;
108   stream_ = stream;
109   int rv = session_->TryCreateStream(this, stream_);
110   if (rv == ERR_IO_PENDING) {
111     callback_ = callback;
112   }
113
114   return rv;
115 }
116
117 void QuicClientSession::StreamRequest::CancelRequest() {
118   if (session_)
119     session_->CancelRequest(this);
120   session_.reset();
121   callback_.Reset();
122 }
123
124 void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
125     QuicReliableClientStream* stream) {
126   session_.reset();
127   *stream_ = stream;
128   ResetAndReturn(&callback_).Run(OK);
129 }
130
131 void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
132   session_.reset();
133   ResetAndReturn(&callback_).Run(rv);
134 }
135
136 QuicClientSession::QuicClientSession(
137     QuicConnection* connection,
138     scoped_ptr<DatagramClientSocket> socket,
139     QuicStreamFactory* stream_factory,
140     TransportSecurityState* transport_security_state,
141     scoped_ptr<QuicServerInfo> server_info,
142     const QuicConfig& config,
143     base::TaskRunner* task_runner,
144     NetLog* net_log)
145     : QuicClientSessionBase(connection, config),
146       require_confirmation_(false),
147       stream_factory_(stream_factory),
148       socket_(socket.Pass()),
149       read_buffer_(new IOBufferWithSize(kMaxPacketSize)),
150       transport_security_state_(transport_security_state),
151       server_info_(server_info.Pass()),
152       read_pending_(false),
153       num_total_streams_(0),
154       task_runner_(task_runner),
155       net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
156       logger_(new QuicConnectionLogger(net_log_)),
157       num_packets_read_(0),
158       going_away_(false),
159       weak_factory_(this) {
160   connection->set_debug_visitor(logger_);
161 }
162
163 void QuicClientSession::InitializeSession(
164     const QuicServerId& server_id,
165     QuicCryptoClientConfig* crypto_config,
166     QuicCryptoClientStreamFactory* crypto_client_stream_factory) {
167   server_host_port_ = server_id.host_port_pair();
168   crypto_stream_.reset(
169       crypto_client_stream_factory ?
170           crypto_client_stream_factory->CreateQuicCryptoClientStream(
171               server_id, this, crypto_config) :
172           new QuicCryptoClientStream(server_id, this,
173                                      new ProofVerifyContextChromium(net_log_),
174                                      crypto_config));
175   QuicClientSessionBase::InitializeSession();
176   // TODO(rch): pass in full host port proxy pair
177   net_log_.BeginEvent(
178       NetLog::TYPE_QUIC_SESSION,
179       NetLog::StringCallback("host", &server_id.host()));
180 }
181
182 QuicClientSession::~QuicClientSession() {
183   if (!streams()->empty())
184     RecordUnexpectedOpenStreams(DESTRUCTOR);
185   if (!observers_.empty())
186     RecordUnexpectedObservers(DESTRUCTOR);
187   if (!going_away_)
188     RecordUnexpectedNotGoingAway(DESTRUCTOR);
189
190   while (!streams()->empty() ||
191          !observers_.empty() ||
192          !stream_requests_.empty()) {
193     // The session must be closed before it is destroyed.
194     DCHECK(streams()->empty());
195     CloseAllStreams(ERR_UNEXPECTED);
196     DCHECK(observers_.empty());
197     CloseAllObservers(ERR_UNEXPECTED);
198
199     connection()->set_debug_visitor(NULL);
200     net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
201
202     while (!stream_requests_.empty()) {
203       StreamRequest* request = stream_requests_.front();
204       stream_requests_.pop_front();
205       request->OnRequestCompleteFailure(ERR_ABORTED);
206     }
207   }
208
209   if (connection()->connected()) {
210     // Ensure that the connection is closed by the time the session is
211     // destroyed.
212     connection()->CloseConnection(QUIC_INTERNAL_ERROR, false);
213   }
214
215   if (IsEncryptionEstablished())
216     RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
217   if (IsCryptoHandshakeConfirmed())
218     RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
219   else
220     RecordHandshakeState(STATE_FAILED);
221
222   UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
223   UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
224                        crypto_stream_->num_sent_client_hellos());
225   if (!IsCryptoHandshakeConfirmed())
226     return;
227
228   // Sending one client_hello means we had zero handshake-round-trips.
229   int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
230
231   // Don't bother with these histogram during tests, which mock out
232   // num_sent_client_hellos().
233   if (round_trip_handshakes < 0 || !stream_factory_)
234     return;
235
236   bool port_selected = stream_factory_->enable_port_selection();
237   SSLInfo ssl_info;
238   if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
239     if (port_selected) {
240       UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTP",
241                                   round_trip_handshakes, 0, 3, 4);
242     } else {
243       UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTP",
244                                   round_trip_handshakes, 0, 3, 4);
245       if (require_confirmation_) {
246         UMA_HISTOGRAM_CUSTOM_COUNTS(
247             "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTP",
248             round_trip_handshakes, 0, 3, 4);
249       }
250     }
251   } else {
252     if (port_selected) {
253       UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectSelectPortForHTTPS",
254                                   round_trip_handshakes, 0, 3, 4);
255     } else {
256       UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
257                                   round_trip_handshakes, 0, 3, 4);
258       if (require_confirmation_) {
259         UMA_HISTOGRAM_CUSTOM_COUNTS(
260             "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
261             round_trip_handshakes, 0, 3, 4);
262       }
263     }
264   }
265   const QuicConnectionStats stats = connection()->GetStats();
266   if (stats.max_sequence_reordering == 0)
267     return;
268   const uint64 kMaxReordering = 100;
269   uint64 reordering = kMaxReordering;
270   if (stats.min_rtt_us > 0 ) {
271     reordering =
272         GG_UINT64_C(100) * stats.max_time_reordering_us / stats.min_rtt_us;
273   }
274   UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime",
275                                 reordering, 0, kMaxReordering, 50);
276   if (stats.min_rtt_us > 100 * 1000) {
277     UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
278                                 reordering, 0, kMaxReordering, 50);
279   }
280   UMA_HISTOGRAM_COUNTS("Net.QuicSession.MaxReordering",
281                        stats.max_sequence_reordering);
282 }
283
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.get()) {
502     // We can always pool with insecure QUIC sessions.
503     return true;
504   }
505
506   return SpdySession::CanPool(transport_security_state_, ssl_info,
507                               server_host_port_.host(), hostname);
508 }
509
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       if (GetNumOpenStreams() > 0) {
601         UMA_HISTOGRAM_BOOLEAN(
602             "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
603             connection()->sent_packet_manager().HasUnackedPackets());
604         UMA_HISTOGRAM_COUNTS(
605             "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
606             connection()->sent_packet_manager().consecutive_rto_count());
607         UMA_HISTOGRAM_COUNTS(
608             "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
609             connection()->sent_packet_manager().consecutive_tlp_count());
610       }
611     } else {
612       UMA_HISTOGRAM_COUNTS(
613           "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
614           GetNumOpenStreams());
615       UMA_HISTOGRAM_COUNTS(
616           "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
617           num_total_streams_);
618     }
619   }
620
621   if (!IsCryptoHandshakeConfirmed()) {
622     if (error == QUIC_PUBLIC_RESET) {
623       RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
624     } else if (connection()->GetStats().packets_received == 0) {
625       RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
626       UMA_HISTOGRAM_SPARSE_SLOWLY(
627           "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
628           error);
629     } else {
630       RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
631       UMA_HISTOGRAM_SPARSE_SLOWLY(
632           "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
633           error);
634     }
635   }
636
637   UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
638                               connection()->version());
639   NotifyFactoryOfSessionGoingAway();
640   if (!callback_.is_null()) {
641     base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
642   }
643   socket_->Close();
644   QuicSession::OnConnectionClosed(error, from_peer);
645   DCHECK(streams()->empty());
646   CloseAllStreams(ERR_UNEXPECTED);
647   CloseAllObservers(ERR_UNEXPECTED);
648   NotifyFactoryOfSessionClosedLater();
649 }
650
651 void QuicClientSession::OnSuccessfulVersionNegotiation(
652     const QuicVersion& version) {
653   logger_->OnSuccessfulVersionNegotiation(version);
654   QuicSession::OnSuccessfulVersionNegotiation(version);
655 }
656
657 void QuicClientSession::OnProofValid(
658     const QuicCryptoClientConfig::CachedState& cached) {
659   DCHECK(cached.proof_valid());
660
661   if (!server_info_ || !server_info_->IsReadyToPersist()) {
662     return;
663   }
664
665   QuicServerInfo::State* state = server_info_->mutable_state();
666
667   state->server_config = cached.server_config();
668   state->source_address_token = cached.source_address_token();
669   state->server_config_sig = cached.signature();
670   state->certs = cached.certs();
671
672   server_info_->Persist();
673 }
674
675 void QuicClientSession::OnProofVerifyDetailsAvailable(
676     const ProofVerifyDetails& verify_details) {
677   const ProofVerifyDetailsChromium* verify_details_chromium =
678       reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
679   CertVerifyResult* result_copy = new CertVerifyResult;
680   result_copy->CopyFrom(verify_details_chromium->cert_verify_result);
681   cert_verify_result_.reset(result_copy);
682   pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
683   logger_->OnCertificateVerified(*cert_verify_result_);
684 }
685
686 void QuicClientSession::StartReading() {
687   if (read_pending_) {
688     return;
689   }
690   read_pending_ = true;
691   int rv = socket_->Read(read_buffer_.get(),
692                          read_buffer_->size(),
693                          base::Bind(&QuicClientSession::OnReadComplete,
694                                     weak_factory_.GetWeakPtr()));
695   if (rv == ERR_IO_PENDING) {
696     num_packets_read_ = 0;
697     return;
698   }
699
700   if (++num_packets_read_ > 32) {
701     num_packets_read_ = 0;
702     // Data was read, process it.
703     // Schedule the work through the message loop to 1) prevent infinite
704     // recursion and 2) avoid blocking the thread for too long.
705     base::MessageLoop::current()->PostTask(
706         FROM_HERE,
707         base::Bind(&QuicClientSession::OnReadComplete,
708                    weak_factory_.GetWeakPtr(), rv));
709   } else {
710     OnReadComplete(rv);
711   }
712 }
713
714 void QuicClientSession::CloseSessionOnError(int error) {
715   UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
716   CloseSessionOnErrorInner(error, QUIC_INTERNAL_ERROR);
717   NotifyFactoryOfSessionClosed();
718 }
719
720 void QuicClientSession::CloseSessionOnErrorInner(int net_error,
721                                                  QuicErrorCode quic_error) {
722   if (!callback_.is_null()) {
723     base::ResetAndReturn(&callback_).Run(net_error);
724   }
725   CloseAllStreams(net_error);
726   CloseAllObservers(net_error);
727   net_log_.AddEvent(
728       NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
729       NetLog::IntegerCallback("net_error", net_error));
730
731   if (connection()->connected())
732     connection()->CloseConnection(quic_error, false);
733   DCHECK(!connection()->connected());
734 }
735
736 void QuicClientSession::CloseAllStreams(int net_error) {
737   while (!streams()->empty()) {
738     ReliableQuicStream* stream = streams()->begin()->second;
739     QuicStreamId id = stream->id();
740     static_cast<QuicReliableClientStream*>(stream)->OnError(net_error);
741     CloseStream(id);
742   }
743 }
744
745 void QuicClientSession::CloseAllObservers(int net_error) {
746   while (!observers_.empty()) {
747     Observer* observer = *observers_.begin();
748     observers_.erase(observer);
749     observer->OnSessionClosed(net_error);
750   }
751 }
752
753 base::Value* QuicClientSession::GetInfoAsValue(
754     const std::set<HostPortPair>& aliases) {
755   base::DictionaryValue* dict = new base::DictionaryValue();
756   dict->SetString("version", QuicVersionToString(connection()->version()));
757   dict->SetInteger("open_streams", GetNumOpenStreams());
758   base::ListValue* stream_list = new base::ListValue();
759   for (base::hash_map<QuicStreamId, QuicDataStream*>::const_iterator it
760            = streams()->begin();
761        it != streams()->end();
762        ++it) {
763     stream_list->Append(new base::StringValue(
764         base::Uint64ToString(it->second->id())));
765   }
766   dict->Set("active_streams", stream_list);
767
768   dict->SetInteger("total_streams", num_total_streams_);
769   dict->SetString("peer_address", peer_address().ToString());
770   dict->SetString("connection_id", base::Uint64ToString(connection_id()));
771   dict->SetBoolean("connected", connection()->connected());
772   const QuicConnectionStats& stats = connection()->GetStats();
773   dict->SetInteger("packets_sent", stats.packets_sent);
774   dict->SetInteger("packets_received", stats.packets_received);
775   dict->SetInteger("packets_lost", stats.packets_lost);
776   SSLInfo ssl_info;
777   dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
778
779   base::ListValue* alias_list = new base::ListValue();
780   for (std::set<HostPortPair>::const_iterator it = aliases.begin();
781        it != aliases.end(); it++) {
782     alias_list->Append(new base::StringValue(it->ToString()));
783   }
784   dict->Set("aliases", alias_list);
785
786   return dict;
787 }
788
789 base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
790   return weak_factory_.GetWeakPtr();
791 }
792
793 void QuicClientSession::OnReadComplete(int result) {
794   read_pending_ = false;
795   if (result == 0)
796     result = ERR_CONNECTION_CLOSED;
797
798   if (result < 0) {
799     DVLOG(1) << "Closing session on read error: " << result;
800     UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
801     NotifyFactoryOfSessionGoingAway();
802     CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
803     NotifyFactoryOfSessionClosedLater();
804     return;
805   }
806
807   QuicEncryptedPacket packet(read_buffer_->data(), result);
808   IPEndPoint local_address;
809   IPEndPoint peer_address;
810   socket_->GetLocalAddress(&local_address);
811   socket_->GetPeerAddress(&peer_address);
812   // ProcessUdpPacket might result in |this| being deleted, so we
813   // use a weak pointer to be safe.
814   connection()->ProcessUdpPacket(local_address, peer_address, packet);
815   if (!connection()->connected()) {
816     NotifyFactoryOfSessionClosedLater();
817     return;
818   }
819   StartReading();
820 }
821
822 void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
823   going_away_ = true;
824   if (stream_factory_)
825     stream_factory_->OnSessionGoingAway(this);
826 }
827
828 void QuicClientSession::NotifyFactoryOfSessionClosedLater() {
829   if (!streams()->empty())
830     RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
831
832   if (!going_away_)
833     RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
834
835   going_away_ = true;
836   DCHECK_EQ(0u, GetNumOpenStreams());
837   DCHECK(!connection()->connected());
838   base::MessageLoop::current()->PostTask(
839       FROM_HERE,
840       base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
841                  weak_factory_.GetWeakPtr()));
842 }
843
844 void QuicClientSession::NotifyFactoryOfSessionClosed() {
845   if (!streams()->empty())
846     RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
847
848   if (!going_away_)
849     RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
850
851   going_away_ = true;
852   DCHECK_EQ(0u, GetNumOpenStreams());
853   // Will delete |this|.
854   if (stream_factory_)
855     stream_factory_->OnSessionClosed(this);
856 }
857
858 void QuicClientSession::OnConnectTimeout() {
859   DCHECK(callback_.is_null());
860   DCHECK(IsEncryptionEstablished());
861
862   if (IsCryptoHandshakeConfirmed())
863     return;
864
865   // TODO(rch): re-enable this code once beta is cut.
866   //  if (stream_factory_)
867   //    stream_factory_->OnSessionConnectTimeout(this);
868   //  CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
869   //  DCHECK_EQ(0u, GetNumOpenStreams());
870 }
871
872 }  // namespace net