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/logging.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/proof_verifier_chromium.h" 24 #include "net/quic/crypto/quic_random.h" 25 #include "net/quic/port_suggester.h" 26 #include "net/quic/quic_client_session.h" 27 #include "net/quic/quic_clock.h" 28 #include "net/quic/quic_connection.h" 29 #include "net/quic/quic_connection_helper.h" 30 #include "net/quic/quic_crypto_client_stream_factory.h" 31 #include "net/quic/quic_default_packet_writer.h" 32 #include "net/quic/quic_http_stream.h" 33 #include "net/quic/quic_protocol.h" 34 #include "net/socket/client_socket_factory.h" 35 36 using std::string; 37 using std::vector; 38 39 namespace net { 40 41 // Responsible for creating a new QUIC session to the specified server, and 42 // for notifying any associated requests when complete. 43 class QuicStreamFactory::Job { 44 public: 45 Job(QuicStreamFactory* factory, 46 HostResolver* host_resolver, 47 const HostPortProxyPair& host_port_proxy_pair, 48 bool is_https, 49 CertVerifier* cert_verifier, 50 const BoundNetLog& net_log); 51 52 ~Job(); 53 54 int Run(const CompletionCallback& callback); 55 56 int DoLoop(int rv); 57 int DoResolveHost(); 58 int DoResolveHostComplete(int rv); 59 int DoConnect(); 60 int DoConnectComplete(int rv); 61 62 void OnIOComplete(int rv); 63 64 CompletionCallback callback() { 65 return callback_; 66 } 67 68 const HostPortProxyPair& host_port_proxy_pair() const { 69 return host_port_proxy_pair_; 70 } 71 72 private: 73 enum IoState { 74 STATE_NONE, 75 STATE_RESOLVE_HOST, 76 STATE_RESOLVE_HOST_COMPLETE, 77 STATE_CONNECT, 78 STATE_CONNECT_COMPLETE, 79 }; 80 IoState io_state_; 81 82 QuicStreamFactory* factory_; 83 SingleRequestHostResolver host_resolver_; 84 const HostPortProxyPair host_port_proxy_pair_; 85 bool is_https_; 86 CertVerifier* cert_verifier_; 87 const BoundNetLog net_log_; 88 QuicClientSession* session_; 89 CompletionCallback callback_; 90 AddressList address_list_; 91 DISALLOW_COPY_AND_ASSIGN(Job); 92 }; 93 94 QuicStreamFactory::Job::Job( 95 QuicStreamFactory* factory, 96 HostResolver* host_resolver, 97 const HostPortProxyPair& host_port_proxy_pair, 98 bool is_https, 99 CertVerifier* cert_verifier, 100 const BoundNetLog& net_log) 101 : factory_(factory), 102 host_resolver_(host_resolver), 103 host_port_proxy_pair_(host_port_proxy_pair), 104 is_https_(is_https), 105 cert_verifier_(cert_verifier), 106 net_log_(net_log), 107 session_(NULL) { 108 } 109 110 QuicStreamFactory::Job::~Job() { 111 } 112 113 int QuicStreamFactory::Job::Run(const CompletionCallback& callback) { 114 io_state_ = STATE_RESOLVE_HOST; 115 int rv = DoLoop(OK); 116 if (rv == ERR_IO_PENDING) 117 callback_ = callback; 118 119 return rv > 0 ? OK : rv; 120 } 121 122 int QuicStreamFactory::Job::DoLoop(int rv) { 123 do { 124 IoState state = io_state_; 125 io_state_ = STATE_NONE; 126 switch (state) { 127 case STATE_RESOLVE_HOST: 128 CHECK_EQ(OK, rv); 129 rv = DoResolveHost(); 130 break; 131 case STATE_RESOLVE_HOST_COMPLETE: 132 rv = DoResolveHostComplete(rv); 133 break; 134 case STATE_CONNECT: 135 CHECK_EQ(OK, rv); 136 rv = DoConnect(); 137 break; 138 case STATE_CONNECT_COMPLETE: 139 rv = DoConnectComplete(rv); 140 break; 141 default: 142 NOTREACHED() << "io_state_: " << io_state_; 143 break; 144 } 145 } while (io_state_ != STATE_NONE && rv != ERR_IO_PENDING); 146 return rv; 147 } 148 149 void QuicStreamFactory::Job::OnIOComplete(int rv) { 150 rv = DoLoop(rv); 151 152 if (rv != ERR_IO_PENDING && !callback_.is_null()) { 153 callback_.Run(rv); 154 } 155 } 156 157 int QuicStreamFactory::Job::DoResolveHost() { 158 io_state_ = STATE_RESOLVE_HOST_COMPLETE; 159 return host_resolver_.Resolve( 160 HostResolver::RequestInfo(host_port_proxy_pair_.first), 161 DEFAULT_PRIORITY, 162 &address_list_, 163 base::Bind(&QuicStreamFactory::Job::OnIOComplete, base::Unretained(this)), 164 net_log_); 165 } 166 167 int QuicStreamFactory::Job::DoResolveHostComplete(int rv) { 168 if (rv != OK) 169 return rv; 170 171 DCHECK(!factory_->HasActiveSession(host_port_proxy_pair_)); 172 io_state_ = STATE_CONNECT; 173 return OK; 174 } 175 176 QuicStreamRequest::QuicStreamRequest(QuicStreamFactory* factory) 177 : factory_(factory) {} 178 179 QuicStreamRequest::~QuicStreamRequest() { 180 if (factory_ && !callback_.is_null()) 181 factory_->CancelRequest(this); 182 } 183 184 int QuicStreamRequest::Request( 185 const HostPortProxyPair& host_port_proxy_pair, 186 bool is_https, 187 CertVerifier* cert_verifier, 188 const BoundNetLog& net_log, 189 const CompletionCallback& callback) { 190 DCHECK(!stream_); 191 DCHECK(callback_.is_null()); 192 int rv = factory_->Create(host_port_proxy_pair, is_https, cert_verifier, 193 net_log, this); 194 if (rv == ERR_IO_PENDING) { 195 host_port_proxy_pair_ = host_port_proxy_pair; 196 is_https_ = is_https; 197 cert_verifier_ = cert_verifier; 198 net_log_ = net_log; 199 callback_ = callback; 200 } else { 201 factory_ = NULL; 202 } 203 if (rv == OK) 204 DCHECK(stream_); 205 return rv; 206 } 207 208 void QuicStreamRequest::set_stream(scoped_ptr<QuicHttpStream> stream) { 209 DCHECK(stream); 210 stream_ = stream.Pass(); 211 } 212 213 void QuicStreamRequest::OnRequestComplete(int rv) { 214 factory_ = NULL; 215 callback_.Run(rv); 216 } 217 218 scoped_ptr<QuicHttpStream> QuicStreamRequest::ReleaseStream() { 219 DCHECK(stream_); 220 return stream_.Pass(); 221 } 222 223 int QuicStreamFactory::Job::DoConnect() { 224 io_state_ = STATE_CONNECT_COMPLETE; 225 226 int rv = factory_->CreateSession(host_port_proxy_pair_, is_https_, 227 cert_verifier_, address_list_, net_log_, &session_); 228 if (rv != OK) { 229 DCHECK(rv != ERR_IO_PENDING); 230 DCHECK(!session_); 231 return rv; 232 } 233 234 session_->StartReading(); 235 rv = session_->CryptoConnect( 236 factory_->require_confirmation() || is_https_, 237 base::Bind(&QuicStreamFactory::Job::OnIOComplete, 238 base::Unretained(this))); 239 return rv; 240 } 241 242 int QuicStreamFactory::Job::DoConnectComplete(int rv) { 243 if (rv != OK) 244 return rv; 245 246 DCHECK(!factory_->HasActiveSession(host_port_proxy_pair_)); 247 factory_->ActivateSession(host_port_proxy_pair_, session_); 248 249 return OK; 250 } 251 252 QuicStreamFactory::QuicStreamFactory( 253 HostResolver* host_resolver, 254 ClientSocketFactory* client_socket_factory, 255 base::WeakPtr<HttpServerProperties> http_server_properties, 256 QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory, 257 QuicRandom* random_generator, 258 QuicClock* clock, 259 size_t max_packet_length) 260 : require_confirmation_(true), 261 host_resolver_(host_resolver), 262 client_socket_factory_(client_socket_factory), 263 http_server_properties_(http_server_properties), 264 quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory), 265 random_generator_(random_generator), 266 clock_(clock), 267 max_packet_length_(max_packet_length), 268 weak_factory_(this), 269 port_seed_(random_generator_->RandUint64()) { 270 config_.SetDefaults(); 271 config_.set_idle_connection_state_lifetime( 272 QuicTime::Delta::FromSeconds(30), 273 QuicTime::Delta::FromSeconds(30)); 274 275 cannoncial_suffixes_.push_back(string(".c.youtube.com")); 276 cannoncial_suffixes_.push_back(string(".googlevideo.com")); 277 } 278 279 QuicStreamFactory::~QuicStreamFactory() { 280 CloseAllSessions(ERR_ABORTED); 281 STLDeleteElements(&all_sessions_); 282 STLDeleteValues(&active_jobs_); 283 STLDeleteValues(&all_crypto_configs_); 284 } 285 286 int QuicStreamFactory::Create(const HostPortProxyPair& host_port_proxy_pair, 287 bool is_https, 288 CertVerifier* cert_verifier, 289 const BoundNetLog& net_log, 290 QuicStreamRequest* request) { 291 if (HasActiveSession(host_port_proxy_pair)) { 292 request->set_stream(CreateIfSessionExists(host_port_proxy_pair, net_log)); 293 return OK; 294 } 295 296 if (HasActiveJob(host_port_proxy_pair)) { 297 Job* job = active_jobs_[host_port_proxy_pair]; 298 active_requests_[request] = job; 299 job_requests_map_[job].insert(request); 300 return ERR_IO_PENDING; 301 } 302 303 scoped_ptr<Job> job(new Job(this, host_resolver_, host_port_proxy_pair, 304 is_https, cert_verifier, net_log)); 305 int rv = job->Run(base::Bind(&QuicStreamFactory::OnJobComplete, 306 base::Unretained(this), job.get())); 307 308 if (rv == ERR_IO_PENDING) { 309 active_requests_[request] = job.get(); 310 job_requests_map_[job.get()].insert(request); 311 active_jobs_[host_port_proxy_pair] = job.release(); 312 } 313 if (rv == OK) { 314 DCHECK(HasActiveSession(host_port_proxy_pair)); 315 request->set_stream(CreateIfSessionExists(host_port_proxy_pair, net_log)); 316 } 317 return rv; 318 } 319 320 void QuicStreamFactory::OnJobComplete(Job* job, int rv) { 321 if (rv == OK) { 322 require_confirmation_ = false; 323 324 // Create all the streams, but do not notify them yet. 325 for (RequestSet::iterator it = job_requests_map_[job].begin(); 326 it != job_requests_map_[job].end() ; ++it) { 327 DCHECK(HasActiveSession(job->host_port_proxy_pair())); 328 (*it)->set_stream(CreateIfSessionExists(job->host_port_proxy_pair(), 329 (*it)->net_log())); 330 } 331 } 332 while (!job_requests_map_[job].empty()) { 333 RequestSet::iterator it = job_requests_map_[job].begin(); 334 QuicStreamRequest* request = *it; 335 job_requests_map_[job].erase(it); 336 active_requests_.erase(request); 337 // Even though we're invoking callbacks here, we don't need to worry 338 // about |this| being deleted, because the factory is owned by the 339 // profile which can not be deleted via callbacks. 340 request->OnRequestComplete(rv); 341 } 342 active_jobs_.erase(job->host_port_proxy_pair()); 343 job_requests_map_.erase(job); 344 delete job; 345 return; 346 } 347 348 // Returns a newly created QuicHttpStream owned by the caller, if a 349 // matching session already exists. Returns NULL otherwise. 350 scoped_ptr<QuicHttpStream> QuicStreamFactory::CreateIfSessionExists( 351 const HostPortProxyPair& host_port_proxy_pair, 352 const BoundNetLog& net_log) { 353 if (!HasActiveSession(host_port_proxy_pair)) { 354 DVLOG(1) << "No active session"; 355 return scoped_ptr<QuicHttpStream>(); 356 } 357 358 QuicClientSession* session = active_sessions_[host_port_proxy_pair]; 359 DCHECK(session); 360 return scoped_ptr<QuicHttpStream>( 361 new QuicHttpStream(session->GetWeakPtr())); 362 } 363 364 void QuicStreamFactory::OnIdleSession(QuicClientSession* session) { 365 } 366 367 void QuicStreamFactory::OnSessionGoingAway(QuicClientSession* session) { 368 const AliasSet& aliases = session_aliases_[session]; 369 for (AliasSet::const_iterator it = aliases.begin(); it != aliases.end(); 370 ++it) { 371 DCHECK(active_sessions_.count(*it)); 372 DCHECK_EQ(session, active_sessions_[*it]); 373 active_sessions_.erase(*it); 374 if (!session->IsCryptoHandshakeConfirmed() && http_server_properties_) { 375 // TODO(rch): In the special case where the session has received no 376 // packets from the peer, we should consider blacklisting this 377 // differently so that we still race TCP but we don't consider the 378 // session connected until the handshake has been confirmed. 379 http_server_properties_->SetBrokenAlternateProtocol(it->first); 380 } 381 } 382 session_aliases_.erase(session); 383 } 384 385 void QuicStreamFactory::OnSessionClosed(QuicClientSession* session) { 386 DCHECK_EQ(0u, session->GetNumOpenStreams()); 387 OnSessionGoingAway(session); 388 all_sessions_.erase(session); 389 delete session; 390 } 391 392 void QuicStreamFactory::CancelRequest(QuicStreamRequest* request) { 393 DCHECK(ContainsKey(active_requests_, request)); 394 Job* job = active_requests_[request]; 395 job_requests_map_[job].erase(request); 396 active_requests_.erase(request); 397 } 398 399 void QuicStreamFactory::CloseAllSessions(int error) { 400 while (!active_sessions_.empty()) { 401 size_t initial_size = active_sessions_.size(); 402 active_sessions_.begin()->second->CloseSessionOnError(error); 403 DCHECK_NE(initial_size, active_sessions_.size()); 404 } 405 while (!all_sessions_.empty()) { 406 size_t initial_size = all_sessions_.size(); 407 (*all_sessions_.begin())->CloseSessionOnError(error); 408 DCHECK_NE(initial_size, all_sessions_.size()); 409 } 410 DCHECK(all_sessions_.empty()); 411 } 412 413 base::Value* QuicStreamFactory::QuicStreamFactoryInfoToValue() const { 414 base::ListValue* list = new base::ListValue(); 415 416 for (SessionMap::const_iterator it = active_sessions_.begin(); 417 it != active_sessions_.end(); ++it) { 418 const HostPortProxyPair& pair = it->first; 419 const QuicClientSession* session = it->second; 420 421 list->Append(session->GetInfoAsValue(pair.first)); 422 } 423 return list; 424 } 425 426 void QuicStreamFactory::OnIPAddressChanged() { 427 CloseAllSessions(ERR_NETWORK_CHANGED); 428 require_confirmation_ = true; 429 } 430 431 void QuicStreamFactory::OnCertAdded(const X509Certificate* cert) { 432 CloseAllSessions(ERR_CERT_DATABASE_CHANGED); 433 } 434 435 void QuicStreamFactory::OnCACertChanged(const X509Certificate* cert) { 436 // We should flush the sessions if we removed trust from a 437 // cert, because a previously trusted server may have become 438 // untrusted. 439 // 440 // We should not flush the sessions if we added trust to a cert. 441 // 442 // Since the OnCACertChanged method doesn't tell us what 443 // kind of change it is, we have to flush the socket 444 // pools to be safe. 445 CloseAllSessions(ERR_CERT_DATABASE_CHANGED); 446 } 447 448 bool QuicStreamFactory::HasActiveSession( 449 const HostPortProxyPair& host_port_proxy_pair) { 450 return ContainsKey(active_sessions_, host_port_proxy_pair); 451 } 452 453 int QuicStreamFactory::CreateSession( 454 const HostPortProxyPair& host_port_proxy_pair, 455 bool is_https, 456 CertVerifier* cert_verifier, 457 const AddressList& address_list, 458 const BoundNetLog& net_log, 459 QuicClientSession** session) { 460 QuicGuid guid = random_generator_->RandUint64(); 461 IPEndPoint addr = *address_list.begin(); 462 scoped_refptr<PortSuggester> port_suggester = 463 new PortSuggester(host_port_proxy_pair.first, port_seed_); 464 DatagramSocket::BindType bind_type = DatagramSocket::RANDOM_BIND; 465 #if defined(OS_WIN) 466 // TODO(jar)bug=329255 Provide better implementation to avoid pop-up warning. 467 bind_type = DatagramSocket::DEFAULT_BIND; 468 #endif 469 scoped_ptr<DatagramClientSocket> socket( 470 client_socket_factory_->CreateDatagramClientSocket( 471 bind_type, 472 base::Bind(&PortSuggester::SuggestPort, port_suggester), 473 net_log.net_log(), net_log.source())); 474 int rv = socket->Connect(addr); 475 if (rv != OK) 476 return rv; 477 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested", 478 port_suggester->call_count()); 479 480 #if defined(OS_WIN) 481 // TODO(jar)bug=329255 Provide better implementation to avoid pop-up warning. 482 DCHECK_EQ(0u, port_suggester->call_count()); 483 #else 484 DCHECK_LE(1u, port_suggester->call_count()); 485 #endif 486 487 // We should adaptively set this buffer size, but for now, we'll use a size 488 // that is more than large enough for a full receive window, and yet 489 // does not consume "too much" memory. If we see bursty packet loss, we may 490 // revisit this setting and test for its impact. 491 const int32 kSocketBufferSize(TcpReceiver::kReceiveWindowTCP); 492 socket->SetReceiveBufferSize(kSocketBufferSize); 493 // Set a buffer large enough to contain the initial CWND's worth of packet 494 // to work around the problem with CHLO packets being sent out with the 495 // wrong encryption level, when the send buffer is full. 496 socket->SetSendBufferSize(kMaxPacketSize * 20); // Support 20 packets. 497 498 scoped_ptr<QuicDefaultPacketWriter> writer( 499 new QuicDefaultPacketWriter(socket.get())); 500 501 if (!helper_.get()) { 502 helper_.reset(new QuicConnectionHelper( 503 base::MessageLoop::current()->message_loop_proxy().get(), 504 clock_.get(), random_generator_)); 505 } 506 507 QuicConnection* connection = new QuicConnection(guid, addr, helper_.get(), 508 writer.get(), false, 509 QuicSupportedVersions()); 510 writer->SetConnection(connection); 511 connection->options()->max_packet_length = max_packet_length_; 512 513 QuicCryptoClientConfig* crypto_config = 514 GetOrCreateCryptoConfig(host_port_proxy_pair); 515 DCHECK(crypto_config); 516 517 *session = new QuicClientSession( 518 connection, socket.Pass(), writer.Pass(), this, 519 quic_crypto_client_stream_factory_, host_port_proxy_pair.first.host(), 520 config_, crypto_config, net_log.net_log()); 521 all_sessions_.insert(*session); // owning pointer 522 if (is_https) { 523 crypto_config->SetProofVerifier( 524 new ProofVerifierChromium(cert_verifier, net_log)); 525 } 526 return OK; 527 } 528 529 bool QuicStreamFactory::HasActiveJob( 530 const HostPortProxyPair& host_port_proxy_pair) { 531 return ContainsKey(active_jobs_, host_port_proxy_pair); 532 } 533 534 void QuicStreamFactory::ActivateSession( 535 const HostPortProxyPair& host_port_proxy_pair, 536 QuicClientSession* session) { 537 DCHECK(!HasActiveSession(host_port_proxy_pair)); 538 active_sessions_[host_port_proxy_pair] = session; 539 session_aliases_[session].insert(host_port_proxy_pair); 540 } 541 542 QuicCryptoClientConfig* QuicStreamFactory::GetOrCreateCryptoConfig( 543 const HostPortProxyPair& host_port_proxy_pair) { 544 QuicCryptoClientConfig* crypto_config; 545 546 if (ContainsKey(all_crypto_configs_, host_port_proxy_pair)) { 547 crypto_config = all_crypto_configs_[host_port_proxy_pair]; 548 DCHECK(crypto_config); 549 } else { 550 // TODO(rtenneti): if two quic_sessions for the same host_port_proxy_pair 551 // share the same crypto_config, will it cause issues? 552 crypto_config = new QuicCryptoClientConfig(); 553 crypto_config->SetDefaults(); 554 all_crypto_configs_[host_port_proxy_pair] = crypto_config; 555 PopulateFromCanonicalConfig(host_port_proxy_pair, crypto_config); 556 } 557 return crypto_config; 558 } 559 560 void QuicStreamFactory::PopulateFromCanonicalConfig( 561 const HostPortProxyPair& host_port_proxy_pair, 562 QuicCryptoClientConfig* crypto_config) { 563 const string server_hostname = host_port_proxy_pair.first.host(); 564 565 unsigned i = 0; 566 for (; i < cannoncial_suffixes_.size(); ++i) { 567 if (EndsWith(server_hostname, cannoncial_suffixes_[i], false)) { 568 break; 569 } 570 } 571 if (i == cannoncial_suffixes_.size()) 572 return; 573 574 HostPortPair canonical_host_port(cannoncial_suffixes_[i], 575 host_port_proxy_pair.first.port()); 576 if (!ContainsKey(canonical_hostname_to_origin_map_, canonical_host_port)) { 577 // This is the first host we've seen which matches the suffix, so make it 578 // canonical. 579 canonical_hostname_to_origin_map_[canonical_host_port] = 580 host_port_proxy_pair; 581 return; 582 } 583 584 const HostPortProxyPair& canonical_host_port_proxy_pair = 585 canonical_hostname_to_origin_map_[canonical_host_port]; 586 QuicCryptoClientConfig* canonical_crypto_config = 587 all_crypto_configs_[canonical_host_port_proxy_pair]; 588 DCHECK(canonical_crypto_config); 589 590 // Copy the CachedState for the canonical server from canonical_crypto_config 591 // as the initial CachedState for the server_hostname in crypto_config. 592 crypto_config->InitializeFrom(server_hostname, 593 canonical_host_port_proxy_pair.first.host(), 594 canonical_crypto_config); 595 // Update canonical version to point at the "most recent" crypto_config. 596 canonical_hostname_to_origin_map_[canonical_host_port] = host_port_proxy_pair; 597 } 598 599 } // namespace net 600