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
43 using std::string;
44 using std::vector;
45
46 namespace net {
47
48 namespace {
49
50 enum 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.
58 const int kIdleConnectionTimeoutSeconds = 30;
59
60 // The initial receive window size for both streams and sessions.
61 const 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).
70 const int32 kServerSecureInitialCongestionWindow = 32;
71 // Be conservative, and just use double a typical TCP ICWND for HTTP.
72 const int32 kServerInecureInitialCongestionWindow = 20;
73
74 const char kDummyHostname[] = "quic.global.props";
75 const uint16 kDummyPort = 0;
76
HistogramCreateSessionFailure(enum CreateSessionFailure error)77 void HistogramCreateSessionFailure(enum CreateSessionFailure error) {
78 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error,
79 CREATION_ERROR_MAX);
80 }
81
IsEcdsaSupported()82 bool 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
InitializeQuicConfig(bool enable_time_based_loss_detection,const QuicTagVector & connection_options)91 QuicConfig 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
104 class DefaultPacketWriterFactory : public QuicConnection::PacketWriterFactory {
105 public:
DefaultPacketWriterFactory(DatagramClientSocket * socket)106 explicit DefaultPacketWriterFactory(DatagramClientSocket* socket)
107 : socket_(socket) {}
~DefaultPacketWriterFactory()108 virtual ~DefaultPacketWriterFactory() {}
109
110 virtual QuicPacketWriter* Create(QuicConnection* connection) const OVERRIDE;
111
112 private:
113 DatagramClientSocket* socket_;
114 };
115
Create(QuicConnection * connection) const116 QuicPacketWriter* 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
IpAliasKey()126 QuicStreamFactory::IpAliasKey::IpAliasKey() {}
127
IpAliasKey(IPEndPoint ip_endpoint,bool is_https)128 QuicStreamFactory::IpAliasKey::IpAliasKey(IPEndPoint ip_endpoint,
129 bool is_https)
130 : ip_endpoint(ip_endpoint),
131 is_https(is_https) {}
132
~IpAliasKey()133 QuicStreamFactory::IpAliasKey::~IpAliasKey() {}
134
operator <(const QuicStreamFactory::IpAliasKey & other) const135 bool 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
operator ==(const QuicStreamFactory::IpAliasKey & other) const143 bool 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.
151 class 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
callback()185 CompletionCallback callback() {
186 return callback_;
187 }
188
server_id() const189 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
Job(QuicStreamFactory * factory,HostResolver * host_resolver,const HostPortPair & host_port_pair,bool is_https,bool was_alternate_protocol_recently_broken,PrivacyMode privacy_mode,base::StringPiece method,QuicServerInfo * server_info,const BoundNetLog & net_log)222 QuicStreamFactory::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
Job(QuicStreamFactory * factory,HostResolver * host_resolver,QuicClientSession * session,QuicServerId server_id)243 QuicStreamFactory::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
~Job()257 QuicStreamFactory::Job::~Job() {
258 }
259
Run(const CompletionCallback & callback)260 int 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
DoLoop(int rv)268 int 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
OnIOComplete(int rv)306 void 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
DoResolveHost()314 int 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
DoResolveHostComplete(int rv)332 int 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
DoLoadServerInfo()350 int 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
DoLoadServerInfoComplete(int rv)361 int 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
DoConnect()375 int 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
DoResumeConnect()404 int 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
DoConnectComplete(int rv)414 int 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
QuicStreamRequest(QuicStreamFactory * factory)433 QuicStreamRequest::QuicStreamRequest(QuicStreamFactory* factory)
434 : factory_(factory) {}
435
~QuicStreamRequest()436 QuicStreamRequest::~QuicStreamRequest() {
437 if (factory_ && !callback_.is_null())
438 factory_->CancelRequest(this);
439 }
440
Request(const HostPortPair & host_port_pair,bool is_https,PrivacyMode privacy_mode,base::StringPiece method,const BoundNetLog & net_log,const CompletionCallback & callback)441 int 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
set_stream(scoped_ptr<QuicHttpStream> stream)465 void QuicStreamRequest::set_stream(scoped_ptr<QuicHttpStream> stream) {
466 DCHECK(stream);
467 stream_ = stream.Pass();
468 }
469
OnRequestComplete(int rv)470 void QuicStreamRequest::OnRequestComplete(int rv) {
471 factory_ = NULL;
472 callback_.Run(rv);
473 }
474
ReleaseStream()475 scoped_ptr<QuicHttpStream> QuicStreamRequest::ReleaseStream() {
476 DCHECK(stream_);
477 return stream_.Pass();
478 }
479
QuicStreamFactory(HostResolver * host_resolver,ClientSocketFactory * client_socket_factory,base::WeakPtr<HttpServerProperties> http_server_properties,CertVerifier * cert_verifier,ChannelIDService * channel_id_service,TransportSecurityState * transport_security_state,QuicCryptoClientStreamFactory * quic_crypto_client_stream_factory,QuicRandom * random_generator,QuicClock * clock,size_t max_packet_length,const std::string & user_agent_id,const QuicVersionVector & supported_versions,bool enable_port_selection,bool enable_time_based_loss_detection,bool always_require_handshake_confirmation,bool disable_connection_pooling,const QuicTagVector & connection_options)480 QuicStreamFactory::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
~QuicStreamFactory()534 QuicStreamFactory::~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
set_require_confirmation(bool require_confirmation)543 void 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
Create(const HostPortPair & host_port_pair,bool is_https,PrivacyMode privacy_mode,base::StringPiece method,const BoundNetLog & net_log,QuicStreamRequest * request)554 int 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
OnResolution(const QuicServerId & server_id,const AddressList & address_list)604 bool 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
OnJobComplete(Job * job,int rv)631 void 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.
CreateIfSessionExists(const QuicServerId & server_id,const BoundNetLog & net_log)662 scoped_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
OnIdleSession(QuicClientSession * session)676 void QuicStreamFactory::OnIdleSession(QuicClientSession* session) {
677 }
678
OnSessionGoingAway(QuicClientSession * session)679 void 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
OnSessionClosed(QuicClientSession * session)706 void QuicStreamFactory::OnSessionClosed(QuicClientSession* session) {
707 DCHECK_EQ(0u, session->GetNumOpenStreams());
708 OnSessionGoingAway(session);
709 delete session;
710 all_sessions_.erase(session);
711 }
712
OnSessionConnectTimeout(QuicClientSession * session)713 void 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
CancelRequest(QuicStreamRequest * request)742 void 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
CloseAllSessions(int error)749 void 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
QuicStreamFactoryInfoToValue() const763 base::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
ClearCachedStatesInCryptoConfig()784 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
785 crypto_config_.ClearCachedStates();
786 }
787
OnIPAddressChanged()788 void QuicStreamFactory::OnIPAddressChanged() {
789 CloseAllSessions(ERR_NETWORK_CHANGED);
790 set_require_confirmation(true);
791 }
792
OnCertAdded(const X509Certificate * cert)793 void QuicStreamFactory::OnCertAdded(const X509Certificate* cert) {
794 CloseAllSessions(ERR_CERT_DATABASE_CHANGED);
795 }
796
OnCACertChanged(const X509Certificate * cert)797 void 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
HasActiveSession(const QuicServerId & server_id) const810 bool QuicStreamFactory::HasActiveSession(
811 const QuicServerId& server_id) const {
812 return ContainsKey(active_sessions_, server_id);
813 }
814
CreateSession(const QuicServerId & server_id,scoped_ptr<QuicServerInfo> server_info,const AddressList & address_list,const BoundNetLog & net_log,QuicClientSession ** session)815 int 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
HasActiveJob(const QuicServerId & key) const943 bool QuicStreamFactory::HasActiveJob(const QuicServerId& key) const {
944 return ContainsKey(active_jobs_, key);
945 }
946
ActivateSession(const QuicServerId & server_id,QuicClientSession * session)947 void 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
InitializeCachedStateInCryptoConfig(const QuicServerId & server_id,const scoped_ptr<QuicServerInfo> & server_info)960 void 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
ProcessGoingAwaySession(QuicClientSession * session,const QuicServerId & server_id,bool session_was_active)984 void 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