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