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
29namespace net {
30
31namespace {
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.
35const 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
40enum 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
50void RecordUnexpectedOpenStreams(Location location) {
51  UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
52                            NUM_LOCATIONS);
53}
54
55void RecordUnexpectedObservers(Location location) {
56  UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
57                            NUM_LOCATIONS);
58}
59
60void 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.
67enum 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
74void 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
82enum 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
90void RecordHandshakeState(HandshakeState state) {
91  UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
92                            NUM_HANDSHAKE_STATES);
93}
94
95}  // namespace
96
97QuicClientSession::StreamRequest::StreamRequest() : stream_(NULL) {}
98
99QuicClientSession::StreamRequest::~StreamRequest() {
100  CancelRequest();
101}
102
103int 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
117void QuicClientSession::StreamRequest::CancelRequest() {
118  if (session_)
119    session_->CancelRequest(this);
120  session_.reset();
121  callback_.Reset();
122}
123
124void QuicClientSession::StreamRequest::OnRequestCompleteSuccess(
125    QuicReliableClientStream* stream) {
126  session_.reset();
127  *stream_ = stream;
128  ResetAndReturn(&callback_).Run(OK);
129}
130
131void QuicClientSession::StreamRequest::OnRequestCompleteFailure(int rv) {
132  session_.reset();
133  ResetAndReturn(&callback_).Run(rv);
134}
135
136QuicClientSession::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
163void 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
182QuicClientSession::~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
284void 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
304void 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
315void QuicClientSession::RemoveObserver(Observer* observer) {
316  DCHECK(ContainsKey(observers_, observer));
317  observers_.erase(observer);
318}
319
320int 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
351void 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
361QuicReliableClientStream* 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
383QuicReliableClientStream*
384QuicClientSession::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
394QuicCryptoClientStream* 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).
400bool 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
449int 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
482int 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
494int QuicClientSession::GetNumSentClientHellos() const {
495  return crypto_stream_->num_sent_client_hellos();
496}
497
498bool 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
510QuicDataStream* QuicClientSession::CreateIncomingDataStream(
511    QuicStreamId id) {
512  DLOG(ERROR) << "Server push not supported";
513  return NULL;
514}
515
516void 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
527void QuicClientSession::SendRstStream(QuicStreamId id,
528                                      QuicRstStreamErrorCode error,
529                                      QuicStreamOffset bytes_written) {
530  QuicSession::SendRstStream(id, error, bytes_written);
531  OnClosedStream();
532}
533
534void 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
551void 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
573void QuicClientSession::OnCryptoHandshakeMessageSent(
574    const CryptoHandshakeMessage& message) {
575  logger_->OnCryptoHandshakeMessageSent(message);
576}
577
578void QuicClientSession::OnCryptoHandshakeMessageReceived(
579    const CryptoHandshakeMessage& message) {
580  logger_->OnCryptoHandshakeMessageReceived(message);
581}
582
583void 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
651void QuicClientSession::OnSuccessfulVersionNegotiation(
652    const QuicVersion& version) {
653  logger_->OnSuccessfulVersionNegotiation(version);
654  QuicSession::OnSuccessfulVersionNegotiation(version);
655}
656
657void 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
675void 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
686void 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
714void QuicClientSession::CloseSessionOnError(int error) {
715  UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
716  CloseSessionOnErrorInner(error, QUIC_INTERNAL_ERROR);
717  NotifyFactoryOfSessionClosed();
718}
719
720void 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
736void 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
745void 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
753base::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
789base::WeakPtr<QuicClientSession> QuicClientSession::GetWeakPtr() {
790  return weak_factory_.GetWeakPtr();
791}
792
793void 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
822void QuicClientSession::NotifyFactoryOfSessionGoingAway() {
823  going_away_ = true;
824  if (stream_factory_)
825    stream_factory_->OnSessionGoingAway(this);
826}
827
828void 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
844void 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
858void 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
873