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