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