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_stream_factory.h" 6 7#include <set> 8 9#include "base/cpu.h" 10#include "base/message_loop/message_loop.h" 11#include "base/message_loop/message_loop_proxy.h" 12#include "base/metrics/histogram.h" 13#include "base/rand_util.h" 14#include "base/stl_util.h" 15#include "base/strings/string_util.h" 16#include "base/values.h" 17#include "net/base/net_errors.h" 18#include "net/cert/cert_verifier.h" 19#include "net/dns/host_resolver.h" 20#include "net/dns/single_request_host_resolver.h" 21#include "net/http/http_server_properties.h" 22#include "net/quic/congestion_control/tcp_receiver.h" 23#include "net/quic/crypto/channel_id_chromium.h" 24#include "net/quic/crypto/proof_verifier_chromium.h" 25#include "net/quic/crypto/quic_random.h" 26#include "net/quic/crypto/quic_server_info.h" 27#include "net/quic/port_suggester.h" 28#include "net/quic/quic_client_session.h" 29#include "net/quic/quic_clock.h" 30#include "net/quic/quic_connection.h" 31#include "net/quic/quic_connection_helper.h" 32#include "net/quic/quic_crypto_client_stream_factory.h" 33#include "net/quic/quic_default_packet_writer.h" 34#include "net/quic/quic_http_stream.h" 35#include "net/quic/quic_protocol.h" 36#include "net/quic/quic_server_id.h" 37#include "net/socket/client_socket_factory.h" 38 39#if defined(OS_WIN) 40#include "base/win/windows_version.h" 41#endif 42 43using std::string; 44using std::vector; 45 46namespace net { 47 48namespace { 49 50enum CreateSessionFailure { 51 CREATION_ERROR_CONNECTING_SOCKET, 52 CREATION_ERROR_SETTING_RECEIVE_BUFFER, 53 CREATION_ERROR_SETTING_SEND_BUFFER, 54 CREATION_ERROR_MAX 55}; 56 57// When a connection is idle for 30 seconds it will be closed. 58const int kIdleConnectionTimeoutSeconds = 30; 59 60// The initial receive window size for both streams and sessions. 61const int32 kInitialReceiveWindowSize = 10 * 1024 * 1024; // 10MB 62 63// The suggested initial congestion windows for a server to use. 64// TODO: This should be tested and optimized, and even better, suggest a window 65// that corresponds to historical bandwidth and min-RTT. 66// Larger initial congestion windows can, if we don't overshoot, reduce latency 67// by avoiding the RTT needed for slow start to double (and re-double) from a 68// default of 10. 69// We match SPDY's use of 32 when secure (since we'd compete with SPDY). 70const int32 kServerSecureInitialCongestionWindow = 32; 71// Be conservative, and just use double a typical TCP ICWND for HTTP. 72const int32 kServerInecureInitialCongestionWindow = 20; 73 74const char kDummyHostname[] = "quic.global.props"; 75const uint16 kDummyPort = 0; 76 77void HistogramCreateSessionFailure(enum CreateSessionFailure error) { 78 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error, 79 CREATION_ERROR_MAX); 80} 81 82bool IsEcdsaSupported() { 83#if defined(OS_WIN) 84 if (base::win::GetVersion() < base::win::VERSION_VISTA) 85 return false; 86#endif 87 88 return true; 89} 90 91QuicConfig InitializeQuicConfig(bool enable_time_based_loss_detection, 92 const QuicTagVector& connection_options) { 93 QuicConfig config; 94 config.SetDefaults(); 95 if (enable_time_based_loss_detection) 96 config.SetLossDetectionToSend(kTIME); 97 config.set_idle_connection_state_lifetime( 98 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds), 99 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds)); 100 config.SetConnectionOptionsToSend(connection_options); 101 return config; 102} 103 104class DefaultPacketWriterFactory : public QuicConnection::PacketWriterFactory { 105 public: 106 explicit DefaultPacketWriterFactory(DatagramClientSocket* socket) 107 : socket_(socket) {} 108 virtual ~DefaultPacketWriterFactory() {} 109 110 virtual QuicPacketWriter* Create(QuicConnection* connection) const OVERRIDE; 111 112 private: 113 DatagramClientSocket* socket_; 114}; 115 116QuicPacketWriter* DefaultPacketWriterFactory::Create( 117 QuicConnection* connection) const { 118 scoped_ptr<QuicDefaultPacketWriter> writer( 119 new QuicDefaultPacketWriter(socket_)); 120 writer->SetConnection(connection); 121 return writer.release(); 122} 123 124} // namespace 125 126QuicStreamFactory::IpAliasKey::IpAliasKey() {} 127 128QuicStreamFactory::IpAliasKey::IpAliasKey(IPEndPoint ip_endpoint, 129 bool is_https) 130 : ip_endpoint(ip_endpoint), 131 is_https(is_https) {} 132 133QuicStreamFactory::IpAliasKey::~IpAliasKey() {} 134 135bool QuicStreamFactory::IpAliasKey::operator<( 136 const QuicStreamFactory::IpAliasKey& other) const { 137 if (!(ip_endpoint == other.ip_endpoint)) { 138 return ip_endpoint < other.ip_endpoint; 139 } 140 return is_https < other.is_https; 141} 142 143bool QuicStreamFactory::IpAliasKey::operator==( 144 const QuicStreamFactory::IpAliasKey& other) const { 145 return is_https == other.is_https && 146 ip_endpoint == other.ip_endpoint; 147}; 148 149// Responsible for creating a new QUIC session to the specified server, and 150// for notifying any associated requests when complete. 151class QuicStreamFactory::Job { 152 public: 153 Job(QuicStreamFactory* factory, 154 HostResolver* host_resolver, 155 const HostPortPair& host_port_pair, 156 bool is_https, 157 bool was_alternate_protocol_recently_broken, 158 PrivacyMode privacy_mode, 159 base::StringPiece method, 160 QuicServerInfo* server_info, 161 const BoundNetLog& net_log); 162 163 // Creates a new job to handle the resumption of for connecting an 164 // existing session. 165 Job(QuicStreamFactory* factory, 166 HostResolver* host_resolver, 167 QuicClientSession* session, 168 QuicServerId server_id); 169 170 ~Job(); 171 172 int Run(const CompletionCallback& callback); 173 174 int DoLoop(int rv); 175 int DoResolveHost(); 176 int DoResolveHostComplete(int rv); 177 int DoLoadServerInfo(); 178 int DoLoadServerInfoComplete(int rv); 179 int DoConnect(); 180 int DoResumeConnect(); 181 int DoConnectComplete(int rv); 182 183 void OnIOComplete(int rv); 184 185 CompletionCallback callback() { 186 return callback_; 187 } 188 189 const QuicServerId server_id() const { 190 return server_id_; 191 } 192 193 private: 194 enum IoState { 195 STATE_NONE, 196 STATE_RESOLVE_HOST, 197 STATE_RESOLVE_HOST_COMPLETE, 198 STATE_LOAD_SERVER_INFO, 199 STATE_LOAD_SERVER_INFO_COMPLETE, 200 STATE_CONNECT, 201 STATE_RESUME_CONNECT, 202 STATE_CONNECT_COMPLETE, 203 }; 204 IoState io_state_; 205 206 QuicStreamFactory* factory_; 207 SingleRequestHostResolver host_resolver_; 208 QuicServerId server_id_; 209 bool is_post_; 210 bool was_alternate_protocol_recently_broken_; 211 scoped_ptr<QuicServerInfo> server_info_; 212 const BoundNetLog net_log_; 213 QuicClientSession* session_; 214 CompletionCallback callback_; 215 AddressList address_list_; 216 base::TimeTicks disk_cache_load_start_time_; 217 base::TimeTicks dns_resolution_start_time_; 218 base::WeakPtrFactory<Job> weak_factory_; 219 DISALLOW_COPY_AND_ASSIGN(Job); 220}; 221 222QuicStreamFactory::Job::Job(QuicStreamFactory* factory, 223 HostResolver* host_resolver, 224 const HostPortPair& host_port_pair, 225 bool is_https, 226 bool was_alternate_protocol_recently_broken, 227 PrivacyMode privacy_mode, 228 base::StringPiece method, 229 QuicServerInfo* server_info, 230 const BoundNetLog& net_log) 231 : io_state_(STATE_RESOLVE_HOST), 232 factory_(factory), 233 host_resolver_(host_resolver), 234 server_id_(host_port_pair, is_https, privacy_mode), 235 is_post_(method == "POST"), 236 was_alternate_protocol_recently_broken_( 237 was_alternate_protocol_recently_broken), 238 server_info_(server_info), 239 net_log_(net_log), 240 session_(NULL), 241 weak_factory_(this) {} 242 243QuicStreamFactory::Job::Job(QuicStreamFactory* factory, 244 HostResolver* host_resolver, 245 QuicClientSession* session, 246 QuicServerId server_id) 247 : io_state_(STATE_RESUME_CONNECT), 248 factory_(factory), 249 host_resolver_(host_resolver), // unused 250 server_id_(server_id), 251 is_post_(false), // unused 252 was_alternate_protocol_recently_broken_(false), // unused 253 net_log_(session->net_log()), // unused 254 session_(session), 255 weak_factory_(this) {} 256 257QuicStreamFactory::Job::~Job() { 258} 259 260int QuicStreamFactory::Job::Run(const CompletionCallback& callback) { 261 int rv = DoLoop(OK); 262 if (rv == ERR_IO_PENDING) 263 callback_ = callback; 264 265 return rv > 0 ? OK : rv; 266} 267 268int QuicStreamFactory::Job::DoLoop(int rv) { 269 do { 270 IoState state = io_state_; 271 io_state_ = STATE_NONE; 272 switch (state) { 273 case STATE_RESOLVE_HOST: 274 CHECK_EQ(OK, rv); 275 rv = DoResolveHost(); 276 break; 277 case STATE_RESOLVE_HOST_COMPLETE: 278 rv = DoResolveHostComplete(rv); 279 break; 280 case STATE_LOAD_SERVER_INFO: 281 CHECK_EQ(OK, rv); 282 rv = DoLoadServerInfo(); 283 break; 284 case STATE_LOAD_SERVER_INFO_COMPLETE: 285 rv = DoLoadServerInfoComplete(rv); 286 break; 287 case STATE_CONNECT: 288 CHECK_EQ(OK, rv); 289 rv = DoConnect(); 290 break; 291 case STATE_RESUME_CONNECT: 292 CHECK_EQ(OK, rv); 293 rv = DoResumeConnect(); 294 break; 295 case STATE_CONNECT_COMPLETE: 296 rv = DoConnectComplete(rv); 297 break; 298 default: 299 NOTREACHED() << "io_state_: " << io_state_; 300 break; 301 } 302 } while (io_state_ != STATE_NONE && rv != ERR_IO_PENDING); 303 return rv; 304} 305 306void QuicStreamFactory::Job::OnIOComplete(int rv) { 307 rv = DoLoop(rv); 308 309 if (rv != ERR_IO_PENDING && !callback_.is_null()) { 310 callback_.Run(rv); 311 } 312} 313 314int QuicStreamFactory::Job::DoResolveHost() { 315 // Start loading the data now, and wait for it after we resolve the host. 316 if (server_info_) { 317 disk_cache_load_start_time_ = base::TimeTicks::Now(); 318 server_info_->Start(); 319 } 320 321 io_state_ = STATE_RESOLVE_HOST_COMPLETE; 322 dns_resolution_start_time_ = base::TimeTicks::Now(); 323 return host_resolver_.Resolve( 324 HostResolver::RequestInfo(server_id_.host_port_pair()), 325 DEFAULT_PRIORITY, 326 &address_list_, 327 base::Bind(&QuicStreamFactory::Job::OnIOComplete, 328 weak_factory_.GetWeakPtr()), 329 net_log_); 330} 331 332int QuicStreamFactory::Job::DoResolveHostComplete(int rv) { 333 UMA_HISTOGRAM_TIMES("Net.QuicSession.HostResolutionTime", 334 base::TimeTicks::Now() - dns_resolution_start_time_); 335 if (rv != OK) 336 return rv; 337 338 DCHECK(!factory_->HasActiveSession(server_id_)); 339 340 // Inform the factory of this resolution, which will set up 341 // a session alias, if possible. 342 if (factory_->OnResolution(server_id_, address_list_)) { 343 return OK; 344 } 345 346 io_state_ = STATE_LOAD_SERVER_INFO; 347 return OK; 348} 349 350int QuicStreamFactory::Job::DoLoadServerInfo() { 351 io_state_ = STATE_LOAD_SERVER_INFO_COMPLETE; 352 353 if (!server_info_) 354 return OK; 355 356 return server_info_->WaitForDataReady( 357 base::Bind(&QuicStreamFactory::Job::OnIOComplete, 358 weak_factory_.GetWeakPtr())); 359} 360 361int QuicStreamFactory::Job::DoLoadServerInfoComplete(int rv) { 362 if (server_info_) { 363 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheReadTime", 364 base::TimeTicks::Now() - disk_cache_load_start_time_); 365 } 366 367 if (rv != OK) { 368 server_info_.reset(); 369 } 370 371 io_state_ = STATE_CONNECT; 372 return OK; 373} 374 375int QuicStreamFactory::Job::DoConnect() { 376 io_state_ = STATE_CONNECT_COMPLETE; 377 378 int rv = factory_->CreateSession(server_id_, server_info_.Pass(), 379 address_list_, net_log_, &session_); 380 if (rv != OK) { 381 DCHECK(rv != ERR_IO_PENDING); 382 DCHECK(!session_); 383 return rv; 384 } 385 386 if (!session_->connection()->connected()) { 387 return ERR_CONNECTION_CLOSED; 388 } 389 390 session_->StartReading(); 391 if (!session_->connection()->connected()) { 392 return ERR_QUIC_PROTOCOL_ERROR; 393 } 394 bool require_confirmation = 395 factory_->require_confirmation() || is_post_ || 396 was_alternate_protocol_recently_broken_; 397 rv = session_->CryptoConnect( 398 require_confirmation, 399 base::Bind(&QuicStreamFactory::Job::OnIOComplete, 400 base::Unretained(this))); 401 return rv; 402} 403 404int QuicStreamFactory::Job::DoResumeConnect() { 405 io_state_ = STATE_CONNECT_COMPLETE; 406 407 int rv = session_->ResumeCryptoConnect( 408 base::Bind(&QuicStreamFactory::Job::OnIOComplete, 409 base::Unretained(this))); 410 411 return rv; 412} 413 414int QuicStreamFactory::Job::DoConnectComplete(int rv) { 415 if (rv != OK) 416 return rv; 417 418 DCHECK(!factory_->HasActiveSession(server_id_)); 419 // There may well now be an active session for this IP. If so, use the 420 // existing session instead. 421 AddressList address(session_->connection()->peer_address()); 422 if (factory_->OnResolution(server_id_, address)) { 423 session_->connection()->SendConnectionClose(QUIC_CONNECTION_IP_POOLED); 424 session_ = NULL; 425 return OK; 426 } 427 428 factory_->ActivateSession(server_id_, session_); 429 430 return OK; 431} 432 433QuicStreamRequest::QuicStreamRequest(QuicStreamFactory* factory) 434 : factory_(factory) {} 435 436QuicStreamRequest::~QuicStreamRequest() { 437 if (factory_ && !callback_.is_null()) 438 factory_->CancelRequest(this); 439} 440 441int QuicStreamRequest::Request(const HostPortPair& host_port_pair, 442 bool is_https, 443 PrivacyMode privacy_mode, 444 base::StringPiece method, 445 const BoundNetLog& net_log, 446 const CompletionCallback& callback) { 447 DCHECK(!stream_); 448 DCHECK(callback_.is_null()); 449 DCHECK(factory_); 450 int rv = factory_->Create(host_port_pair, is_https, privacy_mode, method, 451 net_log, this); 452 if (rv == ERR_IO_PENDING) { 453 host_port_pair_ = host_port_pair; 454 is_https_ = is_https; 455 net_log_ = net_log; 456 callback_ = callback; 457 } else { 458 factory_ = NULL; 459 } 460 if (rv == OK) 461 DCHECK(stream_); 462 return rv; 463} 464 465void QuicStreamRequest::set_stream(scoped_ptr<QuicHttpStream> stream) { 466 DCHECK(stream); 467 stream_ = stream.Pass(); 468} 469 470void QuicStreamRequest::OnRequestComplete(int rv) { 471 factory_ = NULL; 472 callback_.Run(rv); 473} 474 475scoped_ptr<QuicHttpStream> QuicStreamRequest::ReleaseStream() { 476 DCHECK(stream_); 477 return stream_.Pass(); 478} 479 480QuicStreamFactory::QuicStreamFactory( 481 HostResolver* host_resolver, 482 ClientSocketFactory* client_socket_factory, 483 base::WeakPtr<HttpServerProperties> http_server_properties, 484 CertVerifier* cert_verifier, 485 ChannelIDService* channel_id_service, 486 TransportSecurityState* transport_security_state, 487 QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory, 488 QuicRandom* random_generator, 489 QuicClock* clock, 490 size_t max_packet_length, 491 const std::string& user_agent_id, 492 const QuicVersionVector& supported_versions, 493 bool enable_port_selection, 494 bool enable_time_based_loss_detection, 495 bool always_require_handshake_confirmation, 496 bool disable_connection_pooling, 497 const QuicTagVector& connection_options) 498 : require_confirmation_(true), 499 host_resolver_(host_resolver), 500 client_socket_factory_(client_socket_factory), 501 http_server_properties_(http_server_properties), 502 transport_security_state_(transport_security_state), 503 quic_server_info_factory_(NULL), 504 quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory), 505 random_generator_(random_generator), 506 clock_(clock), 507 max_packet_length_(max_packet_length), 508 config_(InitializeQuicConfig(enable_time_based_loss_detection, 509 connection_options)), 510 supported_versions_(supported_versions), 511 enable_port_selection_(enable_port_selection), 512 always_require_handshake_confirmation_( 513 always_require_handshake_confirmation), 514 disable_connection_pooling_(disable_connection_pooling), 515 port_seed_(random_generator_->RandUint64()), 516 check_persisted_supports_quic_(true), 517 weak_factory_(this) { 518 DCHECK(transport_security_state_); 519 crypto_config_.SetDefaults(); 520 crypto_config_.set_user_agent_id(user_agent_id); 521 crypto_config_.AddCanonicalSuffix(".c.youtube.com"); 522 crypto_config_.AddCanonicalSuffix(".googlevideo.com"); 523 crypto_config_.SetProofVerifier( 524 new ProofVerifierChromium(cert_verifier, transport_security_state)); 525 crypto_config_.SetChannelIDSource( 526 new ChannelIDSourceChromium(channel_id_service)); 527 base::CPU cpu; 528 if (cpu.has_aesni() && cpu.has_avx()) 529 crypto_config_.PreferAesGcm(); 530 if (!IsEcdsaSupported()) 531 crypto_config_.DisableEcdsa(); 532} 533 534QuicStreamFactory::~QuicStreamFactory() { 535 CloseAllSessions(ERR_ABORTED); 536 while (!all_sessions_.empty()) { 537 delete all_sessions_.begin()->first; 538 all_sessions_.erase(all_sessions_.begin()); 539 } 540 STLDeleteValues(&active_jobs_); 541} 542 543void QuicStreamFactory::set_require_confirmation(bool require_confirmation) { 544 require_confirmation_ = require_confirmation; 545 if (http_server_properties_ && (!(local_address_ == IPEndPoint()))) { 546 // TODO(rtenneti): Delete host_port_pair and persist data in globals. 547 HostPortPair host_port_pair(kDummyHostname, kDummyPort); 548 http_server_properties_->SetSupportsQuic( 549 host_port_pair, !require_confirmation, 550 local_address_.ToStringWithoutPort()); 551 } 552} 553 554int QuicStreamFactory::Create(const HostPortPair& host_port_pair, 555 bool is_https, 556 PrivacyMode privacy_mode, 557 base::StringPiece method, 558 const BoundNetLog& net_log, 559 QuicStreamRequest* request) { 560 QuicServerId server_id(host_port_pair, is_https, privacy_mode); 561 if (HasActiveSession(server_id)) { 562 request->set_stream(CreateIfSessionExists(server_id, net_log)); 563 return OK; 564 } 565 566 if (HasActiveJob(server_id)) { 567 Job* job = active_jobs_[server_id]; 568 active_requests_[request] = job; 569 job_requests_map_[job].insert(request); 570 return ERR_IO_PENDING; 571 } 572 573 QuicServerInfo* quic_server_info = NULL; 574 if (quic_server_info_factory_) { 575 QuicCryptoClientConfig::CachedState* cached = 576 crypto_config_.LookupOrCreate(server_id); 577 DCHECK(cached); 578 if (cached->IsEmpty()) { 579 quic_server_info = quic_server_info_factory_->GetForServer(server_id); 580 } 581 } 582 bool was_alternate_protocol_recently_broken = 583 http_server_properties_ && 584 http_server_properties_->WasAlternateProtocolRecentlyBroken( 585 server_id.host_port_pair()); 586 scoped_ptr<Job> job(new Job(this, host_resolver_, host_port_pair, is_https, 587 was_alternate_protocol_recently_broken, 588 privacy_mode, method, quic_server_info, net_log)); 589 int rv = job->Run(base::Bind(&QuicStreamFactory::OnJobComplete, 590 base::Unretained(this), job.get())); 591 592 if (rv == ERR_IO_PENDING) { 593 active_requests_[request] = job.get(); 594 job_requests_map_[job.get()].insert(request); 595 active_jobs_[server_id] = job.release(); 596 } 597 if (rv == OK) { 598 DCHECK(HasActiveSession(server_id)); 599 request->set_stream(CreateIfSessionExists(server_id, net_log)); 600 } 601 return rv; 602} 603 604bool QuicStreamFactory::OnResolution( 605 const QuicServerId& server_id, 606 const AddressList& address_list) { 607 DCHECK(!HasActiveSession(server_id)); 608 if (disable_connection_pooling_) { 609 return false; 610 } 611 for (size_t i = 0; i < address_list.size(); ++i) { 612 const IPEndPoint& address = address_list[i]; 613 const IpAliasKey ip_alias_key(address, server_id.is_https()); 614 if (!ContainsKey(ip_aliases_, ip_alias_key)) 615 continue; 616 617 const SessionSet& sessions = ip_aliases_[ip_alias_key]; 618 for (SessionSet::const_iterator i = sessions.begin(); 619 i != sessions.end(); ++i) { 620 QuicClientSession* session = *i; 621 if (!session->CanPool(server_id.host())) 622 continue; 623 active_sessions_[server_id] = session; 624 session_aliases_[session].insert(server_id); 625 return true; 626 } 627 } 628 return false; 629} 630 631void QuicStreamFactory::OnJobComplete(Job* job, int rv) { 632 if (rv == OK) { 633 if (!always_require_handshake_confirmation_) 634 set_require_confirmation(false); 635 636 // Create all the streams, but do not notify them yet. 637 for (RequestSet::iterator it = job_requests_map_[job].begin(); 638 it != job_requests_map_[job].end() ; ++it) { 639 DCHECK(HasActiveSession(job->server_id())); 640 (*it)->set_stream(CreateIfSessionExists(job->server_id(), 641 (*it)->net_log())); 642 } 643 } 644 while (!job_requests_map_[job].empty()) { 645 RequestSet::iterator it = job_requests_map_[job].begin(); 646 QuicStreamRequest* request = *it; 647 job_requests_map_[job].erase(it); 648 active_requests_.erase(request); 649 // Even though we're invoking callbacks here, we don't need to worry 650 // about |this| being deleted, because the factory is owned by the 651 // profile which can not be deleted via callbacks. 652 request->OnRequestComplete(rv); 653 } 654 active_jobs_.erase(job->server_id()); 655 job_requests_map_.erase(job); 656 delete job; 657 return; 658} 659 660// Returns a newly created QuicHttpStream owned by the caller, if a 661// matching session already exists. Returns NULL otherwise. 662scoped_ptr<QuicHttpStream> QuicStreamFactory::CreateIfSessionExists( 663 const QuicServerId& server_id, 664 const BoundNetLog& net_log) { 665 if (!HasActiveSession(server_id)) { 666 DVLOG(1) << "No active session"; 667 return scoped_ptr<QuicHttpStream>(); 668 } 669 670 QuicClientSession* session = active_sessions_[server_id]; 671 DCHECK(session); 672 return scoped_ptr<QuicHttpStream>( 673 new QuicHttpStream(session->GetWeakPtr())); 674} 675 676void QuicStreamFactory::OnIdleSession(QuicClientSession* session) { 677} 678 679void QuicStreamFactory::OnSessionGoingAway(QuicClientSession* session) { 680 const AliasSet& aliases = session_aliases_[session]; 681 for (AliasSet::const_iterator it = aliases.begin(); it != aliases.end(); 682 ++it) { 683 DCHECK(active_sessions_.count(*it)); 684 DCHECK_EQ(session, active_sessions_[*it]); 685 // Track sessions which have recently gone away so that we can disable 686 // port suggestions. 687 if (session->goaway_received()) { 688 gone_away_aliases_.insert(*it); 689 } 690 691 active_sessions_.erase(*it); 692 ProcessGoingAwaySession(session, *it, true); 693 } 694 ProcessGoingAwaySession(session, all_sessions_[session], false); 695 if (!aliases.empty()) { 696 const IpAliasKey ip_alias_key(session->connection()->peer_address(), 697 aliases.begin()->is_https()); 698 ip_aliases_[ip_alias_key].erase(session); 699 if (ip_aliases_[ip_alias_key].empty()) { 700 ip_aliases_.erase(ip_alias_key); 701 } 702 } 703 session_aliases_.erase(session); 704} 705 706void QuicStreamFactory::OnSessionClosed(QuicClientSession* session) { 707 DCHECK_EQ(0u, session->GetNumOpenStreams()); 708 OnSessionGoingAway(session); 709 delete session; 710 all_sessions_.erase(session); 711} 712 713void QuicStreamFactory::OnSessionConnectTimeout( 714 QuicClientSession* session) { 715 const AliasSet& aliases = session_aliases_[session]; 716 for (AliasSet::const_iterator it = aliases.begin(); it != aliases.end(); 717 ++it) { 718 DCHECK(active_sessions_.count(*it)); 719 DCHECK_EQ(session, active_sessions_[*it]); 720 active_sessions_.erase(*it); 721 } 722 723 if (aliases.empty()) { 724 return; 725 } 726 727 const IpAliasKey ip_alias_key(session->connection()->peer_address(), 728 aliases.begin()->is_https()); 729 ip_aliases_[ip_alias_key].erase(session); 730 if (ip_aliases_[ip_alias_key].empty()) { 731 ip_aliases_.erase(ip_alias_key); 732 } 733 QuicServerId server_id = *aliases.begin(); 734 session_aliases_.erase(session); 735 Job* job = new Job(this, host_resolver_, session, server_id); 736 active_jobs_[server_id] = job; 737 int rv = job->Run(base::Bind(&QuicStreamFactory::OnJobComplete, 738 base::Unretained(this), job)); 739 DCHECK_EQ(ERR_IO_PENDING, rv); 740} 741 742void QuicStreamFactory::CancelRequest(QuicStreamRequest* request) { 743 DCHECK(ContainsKey(active_requests_, request)); 744 Job* job = active_requests_[request]; 745 job_requests_map_[job].erase(request); 746 active_requests_.erase(request); 747} 748 749void QuicStreamFactory::CloseAllSessions(int error) { 750 while (!active_sessions_.empty()) { 751 size_t initial_size = active_sessions_.size(); 752 active_sessions_.begin()->second->CloseSessionOnError(error); 753 DCHECK_NE(initial_size, active_sessions_.size()); 754 } 755 while (!all_sessions_.empty()) { 756 size_t initial_size = all_sessions_.size(); 757 all_sessions_.begin()->first->CloseSessionOnError(error); 758 DCHECK_NE(initial_size, all_sessions_.size()); 759 } 760 DCHECK(all_sessions_.empty()); 761} 762 763base::Value* QuicStreamFactory::QuicStreamFactoryInfoToValue() const { 764 base::ListValue* list = new base::ListValue(); 765 766 for (SessionMap::const_iterator it = active_sessions_.begin(); 767 it != active_sessions_.end(); ++it) { 768 const QuicServerId& server_id = it->first; 769 QuicClientSession* session = it->second; 770 const AliasSet& aliases = session_aliases_.find(session)->second; 771 // Only add a session to the list once. 772 if (server_id == *aliases.begin()) { 773 std::set<HostPortPair> hosts; 774 for (AliasSet::const_iterator alias_it = aliases.begin(); 775 alias_it != aliases.end(); ++alias_it) { 776 hosts.insert(alias_it->host_port_pair()); 777 } 778 list->Append(session->GetInfoAsValue(hosts)); 779 } 780 } 781 return list; 782} 783 784void QuicStreamFactory::ClearCachedStatesInCryptoConfig() { 785 crypto_config_.ClearCachedStates(); 786} 787 788void QuicStreamFactory::OnIPAddressChanged() { 789 CloseAllSessions(ERR_NETWORK_CHANGED); 790 set_require_confirmation(true); 791} 792 793void QuicStreamFactory::OnCertAdded(const X509Certificate* cert) { 794 CloseAllSessions(ERR_CERT_DATABASE_CHANGED); 795} 796 797void QuicStreamFactory::OnCACertChanged(const X509Certificate* cert) { 798 // We should flush the sessions if we removed trust from a 799 // cert, because a previously trusted server may have become 800 // untrusted. 801 // 802 // We should not flush the sessions if we added trust to a cert. 803 // 804 // Since the OnCACertChanged method doesn't tell us what 805 // kind of change it is, we have to flush the socket 806 // pools to be safe. 807 CloseAllSessions(ERR_CERT_DATABASE_CHANGED); 808} 809 810bool QuicStreamFactory::HasActiveSession( 811 const QuicServerId& server_id) const { 812 return ContainsKey(active_sessions_, server_id); 813} 814 815int QuicStreamFactory::CreateSession( 816 const QuicServerId& server_id, 817 scoped_ptr<QuicServerInfo> server_info, 818 const AddressList& address_list, 819 const BoundNetLog& net_log, 820 QuicClientSession** session) { 821 bool enable_port_selection = enable_port_selection_; 822 if (enable_port_selection && 823 ContainsKey(gone_away_aliases_, server_id)) { 824 // Disable port selection when the server is going away. 825 // There is no point in trying to return to the same server, if 826 // that server is no longer handling requests. 827 enable_port_selection = false; 828 gone_away_aliases_.erase(server_id); 829 } 830 831 QuicConnectionId connection_id = random_generator_->RandUint64(); 832 IPEndPoint addr = *address_list.begin(); 833 scoped_refptr<PortSuggester> port_suggester = 834 new PortSuggester(server_id.host_port_pair(), port_seed_); 835 DatagramSocket::BindType bind_type = enable_port_selection ? 836 DatagramSocket::RANDOM_BIND : // Use our callback. 837 DatagramSocket::DEFAULT_BIND; // Use OS to randomize. 838 scoped_ptr<DatagramClientSocket> socket( 839 client_socket_factory_->CreateDatagramClientSocket( 840 bind_type, 841 base::Bind(&PortSuggester::SuggestPort, port_suggester), 842 net_log.net_log(), net_log.source())); 843 int rv = socket->Connect(addr); 844 if (rv != OK) { 845 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET); 846 return rv; 847 } 848 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested", 849 port_suggester->call_count()); 850 if (enable_port_selection) { 851 DCHECK_LE(1u, port_suggester->call_count()); 852 } else { 853 DCHECK_EQ(0u, port_suggester->call_count()); 854 } 855 856 // We should adaptively set this buffer size, but for now, we'll use a size 857 // that is more than large enough for a full receive window, and yet 858 // does not consume "too much" memory. If we see bursty packet loss, we may 859 // revisit this setting and test for its impact. 860 const int32 kSocketBufferSize(TcpReceiver::kReceiveWindowTCP); 861 rv = socket->SetReceiveBufferSize(kSocketBufferSize); 862 if (rv != OK) { 863 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER); 864 return rv; 865 } 866 // Set a buffer large enough to contain the initial CWND's worth of packet 867 // to work around the problem with CHLO packets being sent out with the 868 // wrong encryption level, when the send buffer is full. 869 rv = socket->SetSendBufferSize(kMaxPacketSize * 20); 870 if (rv != OK) { 871 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER); 872 return rv; 873 } 874 875 socket->GetLocalAddress(&local_address_); 876 if (check_persisted_supports_quic_ && http_server_properties_) { 877 check_persisted_supports_quic_ = false; 878 // TODO(rtenneti): Delete host_port_pair and persist data in globals. 879 HostPortPair host_port_pair(kDummyHostname, kDummyPort); 880 SupportsQuic supports_quic(true, local_address_.ToStringWithoutPort()); 881 if (http_server_properties_->GetSupportsQuic( 882 host_port_pair).Equals(supports_quic)) { 883 require_confirmation_ = false; 884 } 885 } 886 887 DefaultPacketWriterFactory packet_writer_factory(socket.get()); 888 889 if (!helper_.get()) { 890 helper_.reset(new QuicConnectionHelper( 891 base::MessageLoop::current()->message_loop_proxy().get(), 892 clock_.get(), random_generator_)); 893 } 894 895 QuicConnection* connection = new QuicConnection(connection_id, 896 addr, 897 helper_.get(), 898 packet_writer_factory, 899 true /* owns_writer */, 900 false /* is_server */, 901 supported_versions_); 902 connection->set_max_packet_length(max_packet_length_); 903 904 InitializeCachedStateInCryptoConfig(server_id, server_info); 905 906 QuicConfig config = config_; 907 config.SetInitialCongestionWindowToSend( 908 server_id.is_https() ? kServerSecureInitialCongestionWindow 909 : kServerInecureInitialCongestionWindow); 910 config.SetInitialFlowControlWindowToSend(kInitialReceiveWindowSize); 911 config.SetInitialStreamFlowControlWindowToSend(kInitialReceiveWindowSize); 912 config.SetInitialSessionFlowControlWindowToSend(kInitialReceiveWindowSize); 913 if (http_server_properties_) { 914 const HttpServerProperties::NetworkStats* stats = 915 http_server_properties_->GetServerNetworkStats( 916 server_id.host_port_pair()); 917 if (stats != NULL) { 918 config.SetInitialRoundTripTimeUsToSend(stats->srtt.InMicroseconds()); 919 } 920 } 921 922 *session = new QuicClientSession( 923 connection, socket.Pass(), this, transport_security_state_, 924 server_info.Pass(), config, 925 base::MessageLoop::current()->message_loop_proxy().get(), 926 net_log.net_log()); 927 all_sessions_[*session] = server_id; // owning pointer 928 (*session)->InitializeSession(server_id, &crypto_config_, 929 quic_crypto_client_stream_factory_); 930 bool closed_during_initialize = 931 !ContainsKey(all_sessions_, *session) || 932 !(*session)->connection()->connected(); 933 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedDuringInitializeSession", 934 closed_during_initialize); 935 if (closed_during_initialize) { 936 DLOG(DFATAL) << "Session closed during initialize"; 937 *session = NULL; 938 return ERR_CONNECTION_CLOSED; 939 } 940 return OK; 941} 942 943bool QuicStreamFactory::HasActiveJob(const QuicServerId& key) const { 944 return ContainsKey(active_jobs_, key); 945} 946 947void QuicStreamFactory::ActivateSession( 948 const QuicServerId& server_id, 949 QuicClientSession* session) { 950 DCHECK(!HasActiveSession(server_id)); 951 UMA_HISTOGRAM_COUNTS("Net.QuicActiveSessions", active_sessions_.size()); 952 active_sessions_[server_id] = session; 953 session_aliases_[session].insert(server_id); 954 const IpAliasKey ip_alias_key(session->connection()->peer_address(), 955 server_id.is_https()); 956 DCHECK(!ContainsKey(ip_aliases_[ip_alias_key], session)); 957 ip_aliases_[ip_alias_key].insert(session); 958} 959 960void QuicStreamFactory::InitializeCachedStateInCryptoConfig( 961 const QuicServerId& server_id, 962 const scoped_ptr<QuicServerInfo>& server_info) { 963 if (!server_info) 964 return; 965 966 QuicCryptoClientConfig::CachedState* cached = 967 crypto_config_.LookupOrCreate(server_id); 968 if (!cached->IsEmpty()) 969 return; 970 971 if (!cached->Initialize(server_info->state().server_config, 972 server_info->state().source_address_token, 973 server_info->state().certs, 974 server_info->state().server_config_sig, 975 clock_->WallNow())) 976 return; 977 978 if (!server_id.is_https()) { 979 // Don't check the certificates for insecure QUIC. 980 cached->SetProofValid(); 981 } 982} 983 984void QuicStreamFactory::ProcessGoingAwaySession( 985 QuicClientSession* session, 986 const QuicServerId& server_id, 987 bool session_was_active) { 988 if (!http_server_properties_) 989 return; 990 991 const QuicConnectionStats& stats = session->connection()->GetStats(); 992 if (session->IsCryptoHandshakeConfirmed()) { 993 HttpServerProperties::NetworkStats network_stats; 994 network_stats.srtt = base::TimeDelta::FromMicroseconds(stats.srtt_us); 995 network_stats.bandwidth_estimate = stats.estimated_bandwidth; 996 http_server_properties_->SetServerNetworkStats(server_id.host_port_pair(), 997 network_stats); 998 return; 999 } 1000 1001 UMA_HISTOGRAM_COUNTS("Net.QuicHandshakeNotConfirmedNumPacketsReceived", 1002 stats.packets_received); 1003 1004 if (!session_was_active) 1005 return; 1006 1007 const HostPortPair& server = server_id.host_port_pair(); 1008 // Don't try to change the alternate-protocol state, if the 1009 // alternate-protocol state is unknown. 1010 if (!http_server_properties_->HasAlternateProtocol(server)) 1011 return; 1012 1013 // TODO(rch): In the special case where the session has received no 1014 // packets from the peer, we should consider blacklisting this 1015 // differently so that we still race TCP but we don't consider the 1016 // session connected until the handshake has been confirmed. 1017 HistogramBrokenAlternateProtocolLocation( 1018 BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY); 1019 AlternateProtocolInfo alternate = 1020 http_server_properties_->GetAlternateProtocol(server); 1021 DCHECK_EQ(QUIC, alternate.protocol); 1022 1023 // Since the session was active, there's no longer an 1024 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the 1025 // TCP job also fails. So to avoid not using QUIC when we otherwise could, 1026 // we mark it as broken, and then immediately re-enable it. This leaves 1027 // QUIC as "recently broken" which means that 0-RTT will be disabled but 1028 // we'll still race. 1029 http_server_properties_->SetBrokenAlternateProtocol(server); 1030 http_server_properties_->ClearAlternateProtocol(server); 1031 http_server_properties_->SetAlternateProtocol( 1032 server, alternate.port, alternate.protocol, 1); 1033 DCHECK_EQ(QUIC, 1034 http_server_properties_->GetAlternateProtocol(server).protocol); 1035 DCHECK(http_server_properties_->WasAlternateProtocolRecentlyBroken( 1036 server)); 1037} 1038 1039} // namespace net 1040