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