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/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
    873