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.
5 #include "net/quic/quic_stream_factory.h"
11 #include "base/location.h"
12 #include "base/metrics/field_trial.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/metrics/sparse_histogram.h"
15 #include "base/rand_util.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/thread_task_runner_handle.h"
21 #include "base/values.h"
22 #include "net/base/net_errors.h"
23 #include "net/cert/cert_verifier.h"
24 #include "net/dns/host_resolver.h"
25 #include "net/dns/single_request_host_resolver.h"
26 #include "net/http/http_server_properties.h"
27 #include "net/quic/crypto/channel_id_chromium.h"
28 #include "net/quic/crypto/proof_verifier_chromium.h"
29 #include "net/quic/crypto/quic_random.h"
30 #include "net/quic/crypto/quic_server_info.h"
31 #include "net/quic/port_suggester.h"
32 #include "net/quic/quic_client_session.h"
33 #include "net/quic/quic_clock.h"
34 #include "net/quic/quic_connection.h"
35 #include "net/quic/quic_connection_helper.h"
36 #include "net/quic/quic_crypto_client_stream_factory.h"
37 #include "net/quic/quic_default_packet_writer.h"
38 #include "net/quic/quic_flags.h"
39 #include "net/quic/quic_http_stream.h"
40 #include "net/quic/quic_protocol.h"
41 #include "net/quic/quic_server_id.h"
42 #include "net/socket/client_socket_factory.h"
43 #include "net/udp/udp_client_socket.h"
46 #include "base/win/windows_version.h"
53 enum CreateSessionFailure
{
54 CREATION_ERROR_CONNECTING_SOCKET
,
55 CREATION_ERROR_SETTING_RECEIVE_BUFFER
,
56 CREATION_ERROR_SETTING_SEND_BUFFER
,
60 // When a connection is idle for 30 seconds it will be closed.
61 const int kIdleConnectionTimeoutSeconds
= 30;
63 // The maximum receive window sizes for QUIC sessions and streams.
64 const int32 kQuicSessionMaxRecvWindowSize
= 15 * 1024 * 1024; // 15 MB
65 const int32 kQuicStreamMaxRecvWindowSize
= 6 * 1024 * 1024; // 6 MB
67 // Set the maximum number of undecryptable packets the connection will store.
68 const int32 kMaxUndecryptablePackets
= 100;
70 void HistogramCreateSessionFailure(enum CreateSessionFailure error
) {
71 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error
,
75 bool IsEcdsaSupported() {
77 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
84 QuicConfig
InitializeQuicConfig(const QuicTagVector
& connection_options
) {
86 config
.SetIdleConnectionStateLifetime(
87 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
),
88 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
));
89 config
.SetConnectionOptionsToSend(connection_options
);
93 class DefaultPacketWriterFactory
: public QuicConnection::PacketWriterFactory
{
95 explicit DefaultPacketWriterFactory(DatagramClientSocket
* socket
)
97 ~DefaultPacketWriterFactory() override
{}
99 QuicPacketWriter
* Create(QuicConnection
* connection
) const override
;
102 DatagramClientSocket
* socket_
;
105 QuicPacketWriter
* DefaultPacketWriterFactory::Create(
106 QuicConnection
* connection
) const {
107 scoped_ptr
<QuicDefaultPacketWriter
> writer(
108 new QuicDefaultPacketWriter(socket_
));
109 writer
->SetConnection(connection
);
110 return writer
.release();
115 QuicStreamFactory::IpAliasKey::IpAliasKey() {}
117 QuicStreamFactory::IpAliasKey::IpAliasKey(IPEndPoint ip_endpoint
,
119 : ip_endpoint(ip_endpoint
),
120 is_https(is_https
) {}
122 QuicStreamFactory::IpAliasKey::~IpAliasKey() {}
124 bool QuicStreamFactory::IpAliasKey::operator<(
125 const QuicStreamFactory::IpAliasKey
& other
) const {
126 if (!(ip_endpoint
== other
.ip_endpoint
)) {
127 return ip_endpoint
< other
.ip_endpoint
;
129 return is_https
< other
.is_https
;
132 bool QuicStreamFactory::IpAliasKey::operator==(
133 const QuicStreamFactory::IpAliasKey
& other
) const {
134 return is_https
== other
.is_https
&&
135 ip_endpoint
== other
.ip_endpoint
;
138 // Responsible for creating a new QUIC session to the specified server, and
139 // for notifying any associated requests when complete.
140 class QuicStreamFactory::Job
{
142 Job(QuicStreamFactory
* factory
,
143 HostResolver
* host_resolver
,
144 const HostPortPair
& host_port_pair
,
145 bool server_and_origin_have_same_host
,
147 bool was_alternative_service_recently_broken
,
148 PrivacyMode privacy_mode
,
149 int cert_verify_flags
,
151 QuicServerInfo
* server_info
,
152 const BoundNetLog
& net_log
);
154 // Creates a new job to handle the resumption of for connecting an
156 Job(QuicStreamFactory
* factory
,
157 HostResolver
* host_resolver
,
158 QuicClientSession
* session
,
159 QuicServerId server_id
);
163 int Run(const CompletionCallback
& callback
);
167 int DoResolveHostComplete(int rv
);
168 int DoLoadServerInfo();
169 int DoLoadServerInfoComplete(int rv
);
171 int DoResumeConnect();
172 int DoConnectComplete(int rv
);
174 void OnIOComplete(int rv
);
176 void RunAuxilaryJob();
180 void CancelWaitForDataReadyCallback();
182 const QuicServerId
server_id() const { return server_id_
; }
184 base::WeakPtr
<Job
> GetWeakPtr() { return weak_factory_
.GetWeakPtr(); }
190 STATE_RESOLVE_HOST_COMPLETE
,
191 STATE_LOAD_SERVER_INFO
,
192 STATE_LOAD_SERVER_INFO_COMPLETE
,
194 STATE_RESUME_CONNECT
,
195 STATE_CONNECT_COMPLETE
,
199 QuicStreamFactory
* factory_
;
200 SingleRequestHostResolver host_resolver_
;
201 QuicServerId server_id_
;
202 int cert_verify_flags_
;
203 // True if and only if server and origin have the same hostname.
204 bool server_and_origin_have_same_host_
;
206 bool was_alternative_service_recently_broken_
;
207 scoped_ptr
<QuicServerInfo
> server_info_
;
208 bool started_another_job_
;
209 const BoundNetLog net_log_
;
210 QuicClientSession
* session_
;
211 CompletionCallback callback_
;
212 AddressList address_list_
;
213 base::TimeTicks dns_resolution_start_time_
;
214 base::TimeTicks dns_resolution_end_time_
;
215 base::WeakPtrFactory
<Job
> weak_factory_
;
216 DISALLOW_COPY_AND_ASSIGN(Job
);
219 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
220 HostResolver
* host_resolver
,
221 const HostPortPair
& host_port_pair
,
222 bool server_and_origin_have_same_host
,
224 bool was_alternative_service_recently_broken
,
225 PrivacyMode privacy_mode
,
226 int cert_verify_flags
,
228 QuicServerInfo
* server_info
,
229 const BoundNetLog
& net_log
)
230 : io_state_(STATE_RESOLVE_HOST
),
232 host_resolver_(host_resolver
),
233 server_id_(host_port_pair
, is_https
, privacy_mode
),
234 cert_verify_flags_(cert_verify_flags
),
235 server_and_origin_have_same_host_(server_and_origin_have_same_host
),
237 was_alternative_service_recently_broken_(
238 was_alternative_service_recently_broken
),
239 server_info_(server_info
),
240 started_another_job_(false),
243 weak_factory_(this) {
246 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
247 HostResolver
* host_resolver
,
248 QuicClientSession
* session
,
249 QuicServerId server_id
)
250 : io_state_(STATE_RESUME_CONNECT
),
252 host_resolver_(host_resolver
), // unused
253 server_id_(server_id
),
254 cert_verify_flags_(0), // unused
255 server_and_origin_have_same_host_(false), // unused
256 is_post_(false), // unused
257 was_alternative_service_recently_broken_(false), // unused
258 started_another_job_(false), // unused
259 net_log_(session
->net_log()), // unused
261 weak_factory_(this) {
264 QuicStreamFactory::Job::~Job() {
265 // If disk cache has a pending WaitForDataReadyCallback, cancel that callback.
267 server_info_
->ResetWaitForDataReadyCallback();
270 int QuicStreamFactory::Job::Run(const CompletionCallback
& callback
) {
272 if (rv
== ERR_IO_PENDING
)
273 callback_
= callback
;
275 return rv
> 0 ? OK
: rv
;
278 int QuicStreamFactory::Job::DoLoop(int rv
) {
280 IoState state
= io_state_
;
281 io_state_
= STATE_NONE
;
283 case STATE_RESOLVE_HOST
:
285 rv
= DoResolveHost();
287 case STATE_RESOLVE_HOST_COMPLETE
:
288 rv
= DoResolveHostComplete(rv
);
290 case STATE_LOAD_SERVER_INFO
:
292 rv
= DoLoadServerInfo();
294 case STATE_LOAD_SERVER_INFO_COMPLETE
:
295 rv
= DoLoadServerInfoComplete(rv
);
301 case STATE_RESUME_CONNECT
:
303 rv
= DoResumeConnect();
305 case STATE_CONNECT_COMPLETE
:
306 rv
= DoConnectComplete(rv
);
309 NOTREACHED() << "io_state_: " << io_state_
;
312 } while (io_state_
!= STATE_NONE
&& rv
!= ERR_IO_PENDING
);
316 void QuicStreamFactory::Job::OnIOComplete(int rv
) {
318 if (rv
!= ERR_IO_PENDING
&& !callback_
.is_null()) {
323 void QuicStreamFactory::Job::RunAuxilaryJob() {
324 int rv
= Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
325 base::Unretained(factory_
), this));
326 if (rv
!= ERR_IO_PENDING
)
327 factory_
->OnJobComplete(this, rv
);
330 void QuicStreamFactory::Job::Cancel() {
333 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_CANCELLED
);
336 void QuicStreamFactory::Job::CancelWaitForDataReadyCallback() {
337 // If we are waiting for WaitForDataReadyCallback, then cancel the callback.
338 if (io_state_
!= STATE_LOAD_SERVER_INFO_COMPLETE
)
340 server_info_
->CancelWaitForDataReadyCallback();
344 int QuicStreamFactory::Job::DoResolveHost() {
345 // Start loading the data now, and wait for it after we resolve the host.
347 server_info_
->Start();
350 io_state_
= STATE_RESOLVE_HOST_COMPLETE
;
351 dns_resolution_start_time_
= base::TimeTicks::Now();
352 return host_resolver_
.Resolve(
353 HostResolver::RequestInfo(server_id_
.host_port_pair()), DEFAULT_PRIORITY
,
355 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()),
359 int QuicStreamFactory::Job::DoResolveHostComplete(int rv
) {
360 dns_resolution_end_time_
= base::TimeTicks::Now();
361 UMA_HISTOGRAM_TIMES("Net.QuicSession.HostResolutionTime",
362 dns_resolution_end_time_
- dns_resolution_start_time_
);
366 DCHECK(!factory_
->HasActiveSession(server_id_
));
368 // Inform the factory of this resolution, which will set up
369 // a session alias, if possible.
370 if (factory_
->OnResolution(server_id_
, address_list_
)) {
375 io_state_
= STATE_LOAD_SERVER_INFO
;
377 io_state_
= STATE_CONNECT
;
381 int QuicStreamFactory::Job::DoLoadServerInfo() {
382 io_state_
= STATE_LOAD_SERVER_INFO_COMPLETE
;
384 DCHECK(server_info_
);
386 // To mitigate the effects of disk cache taking too long to load QUIC server
387 // information, set up a timer to cancel WaitForDataReady's callback.
388 if (factory_
->load_server_info_timeout_srtt_multiplier_
> 0) {
389 int64 load_server_info_timeout_ms
=
390 (factory_
->load_server_info_timeout_srtt_multiplier_
*
391 factory_
->GetServerNetworkStatsSmoothedRttInMicroseconds(server_id_
)) /
393 if (load_server_info_timeout_ms
> 0) {
394 factory_
->task_runner_
->PostDelayedTask(
396 base::Bind(&QuicStreamFactory::Job::CancelWaitForDataReadyCallback
,
398 base::TimeDelta::FromMilliseconds(load_server_info_timeout_ms
));
402 int rv
= server_info_
->WaitForDataReady(
403 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
404 if (rv
== ERR_IO_PENDING
&& factory_
->enable_connection_racing()) {
405 // If we are waiting to load server config from the disk cache, then start
407 started_another_job_
= true;
408 factory_
->CreateAuxilaryJob(server_id_
, cert_verify_flags_
,
409 server_and_origin_have_same_host_
, is_post_
,
415 int QuicStreamFactory::Job::DoLoadServerInfoComplete(int rv
) {
416 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheWaitForDataReadyTime",
417 base::TimeTicks::Now() - dns_resolution_end_time_
);
420 server_info_
.reset();
422 if (started_another_job_
&&
423 (!server_info_
|| server_info_
->state().server_config
.empty() ||
424 !factory_
->CryptoConfigCacheIsEmpty(server_id_
))) {
425 // If we have started another job and if we didn't load the server config
426 // from the disk cache or if we have received a new server config from the
427 // server, then cancel the current job.
428 io_state_
= STATE_NONE
;
429 return ERR_CONNECTION_CLOSED
;
432 io_state_
= STATE_CONNECT
;
436 int QuicStreamFactory::Job::DoConnect() {
437 io_state_
= STATE_CONNECT_COMPLETE
;
439 int rv
= factory_
->CreateSession(
440 server_id_
, cert_verify_flags_
, server_info_
.Pass(), address_list_
,
441 dns_resolution_end_time_
, net_log_
, &session_
);
443 DCHECK(rv
!= ERR_IO_PENDING
);
448 if (!session_
->connection()->connected()) {
449 return ERR_CONNECTION_CLOSED
;
452 session_
->StartReading();
453 if (!session_
->connection()->connected()) {
454 return ERR_QUIC_PROTOCOL_ERROR
;
456 bool require_confirmation
= factory_
->require_confirmation() ||
457 !server_and_origin_have_same_host_
|| is_post_
||
458 was_alternative_service_recently_broken_
;
460 rv
= session_
->CryptoConnect(
461 require_confirmation
,
462 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
466 int QuicStreamFactory::Job::DoResumeConnect() {
467 io_state_
= STATE_CONNECT_COMPLETE
;
469 int rv
= session_
->ResumeCryptoConnect(
470 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
475 int QuicStreamFactory::Job::DoConnectComplete(int rv
) {
479 DCHECK(!factory_
->HasActiveSession(server_id_
));
480 // There may well now be an active session for this IP. If so, use the
481 // existing session instead.
482 AddressList
address(session_
->connection()->peer_address());
483 if (factory_
->OnResolution(server_id_
, address
)) {
484 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_IP_POOLED
);
489 factory_
->ActivateSession(server_id_
, session_
);
494 QuicStreamRequest::QuicStreamRequest(QuicStreamFactory
* factory
)
495 : factory_(factory
) {}
497 QuicStreamRequest::~QuicStreamRequest() {
498 if (factory_
&& !callback_
.is_null())
499 factory_
->CancelRequest(this);
502 int QuicStreamRequest::Request(const HostPortPair
& host_port_pair
,
504 PrivacyMode privacy_mode
,
505 int cert_verify_flags
,
506 base::StringPiece origin_host
,
507 base::StringPiece method
,
508 const BoundNetLog
& net_log
,
509 const CompletionCallback
& callback
) {
511 DCHECK(callback_
.is_null());
513 origin_host_
= origin_host
.as_string();
514 privacy_mode_
= privacy_mode
;
516 factory_
->Create(host_port_pair
, is_https
, privacy_mode
,
517 cert_verify_flags
, origin_host
, method
, net_log
, this);
518 if (rv
== ERR_IO_PENDING
) {
519 host_port_pair_
= host_port_pair
;
521 callback_
= callback
;
530 void QuicStreamRequest::set_stream(scoped_ptr
<QuicHttpStream
> stream
) {
532 stream_
= stream
.Pass();
535 void QuicStreamRequest::OnRequestComplete(int rv
) {
540 scoped_ptr
<QuicHttpStream
> QuicStreamRequest::ReleaseStream() {
542 return stream_
.Pass();
545 QuicStreamFactory::QuicStreamFactory(
546 HostResolver
* host_resolver
,
547 ClientSocketFactory
* client_socket_factory
,
548 base::WeakPtr
<HttpServerProperties
> http_server_properties
,
549 CertVerifier
* cert_verifier
,
550 ChannelIDService
* channel_id_service
,
551 TransportSecurityState
* transport_security_state
,
552 QuicCryptoClientStreamFactory
* quic_crypto_client_stream_factory
,
553 QuicRandom
* random_generator
,
555 size_t max_packet_length
,
556 const std::string
& user_agent_id
,
557 const QuicVersionVector
& supported_versions
,
558 bool enable_port_selection
,
559 bool always_require_handshake_confirmation
,
560 bool disable_connection_pooling
,
561 float load_server_info_timeout_srtt_multiplier
,
562 bool enable_connection_racing
,
563 bool enable_non_blocking_io
,
564 bool disable_disk_cache
,
566 int max_number_of_lossy_connections
,
567 float packet_loss_threshold
,
568 int socket_receive_buffer_size
,
569 const QuicTagVector
& connection_options
)
570 : require_confirmation_(true),
571 host_resolver_(host_resolver
),
572 client_socket_factory_(client_socket_factory
),
573 http_server_properties_(http_server_properties
),
574 transport_security_state_(transport_security_state
),
575 quic_server_info_factory_(nullptr),
576 quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory
),
577 random_generator_(random_generator
),
579 max_packet_length_(max_packet_length
),
580 config_(InitializeQuicConfig(connection_options
)),
581 supported_versions_(supported_versions
),
582 enable_port_selection_(enable_port_selection
),
583 always_require_handshake_confirmation_(
584 always_require_handshake_confirmation
),
585 disable_connection_pooling_(disable_connection_pooling
),
586 load_server_info_timeout_srtt_multiplier_(
587 load_server_info_timeout_srtt_multiplier
),
588 enable_connection_racing_(enable_connection_racing
),
589 enable_non_blocking_io_(enable_non_blocking_io
),
590 disable_disk_cache_(disable_disk_cache
),
591 prefer_aes_(prefer_aes
),
592 max_number_of_lossy_connections_(max_number_of_lossy_connections
),
593 packet_loss_threshold_(packet_loss_threshold
),
594 socket_receive_buffer_size_(socket_receive_buffer_size
),
595 port_seed_(random_generator_
->RandUint64()),
596 check_persisted_supports_quic_(true),
597 task_runner_(nullptr),
598 weak_factory_(this) {
599 DCHECK(transport_security_state_
);
600 crypto_config_
.set_user_agent_id(user_agent_id
);
601 crypto_config_
.AddCanonicalSuffix(".c.youtube.com");
602 crypto_config_
.AddCanonicalSuffix(".googlevideo.com");
603 crypto_config_
.AddCanonicalSuffix(".googleusercontent.com");
604 crypto_config_
.SetProofVerifier(
605 new ProofVerifierChromium(cert_verifier
, transport_security_state
));
606 // TODO(rtenneti): http://crbug.com/487355. Temporary fix for b/20760730 until
607 // channel_id_service is supported in cronet.
608 if (channel_id_service
) {
609 crypto_config_
.SetChannelIDSource(
610 new ChannelIDSourceChromium(channel_id_service
));
613 bool has_aes_hardware_support
= cpu
.has_aesni() && cpu
.has_avx();
614 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.PreferAesGcm",
615 has_aes_hardware_support
);
616 if (has_aes_hardware_support
|| prefer_aes_
)
617 crypto_config_
.PreferAesGcm();
618 if (!IsEcdsaSupported())
619 crypto_config_
.DisableEcdsa();
622 QuicStreamFactory::~QuicStreamFactory() {
623 CloseAllSessions(ERR_ABORTED
);
624 while (!all_sessions_
.empty()) {
625 delete all_sessions_
.begin()->first
;
626 all_sessions_
.erase(all_sessions_
.begin());
628 while (!active_jobs_
.empty()) {
629 const QuicServerId server_id
= active_jobs_
.begin()->first
;
630 STLDeleteElements(&(active_jobs_
[server_id
]));
631 active_jobs_
.erase(server_id
);
635 void QuicStreamFactory::set_require_confirmation(bool require_confirmation
) {
636 require_confirmation_
= require_confirmation
;
637 if (http_server_properties_
&& (!(local_address_
== IPEndPoint()))) {
638 http_server_properties_
->SetSupportsQuic(!require_confirmation
,
639 local_address_
.address());
643 int QuicStreamFactory::Create(const HostPortPair
& host_port_pair
,
645 PrivacyMode privacy_mode
,
646 int cert_verify_flags
,
647 base::StringPiece origin_host
,
648 base::StringPiece method
,
649 const BoundNetLog
& net_log
,
650 QuicStreamRequest
* request
) {
651 QuicServerId
server_id(host_port_pair
, is_https
, privacy_mode
);
652 SessionMap::iterator it
= active_sessions_
.find(server_id
);
653 if (it
!= active_sessions_
.end()) {
654 QuicClientSession
* session
= it
->second
;
655 if (!session
->CanPool(origin_host
.as_string(), privacy_mode
))
656 return ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN
;
657 request
->set_stream(CreateFromSession(session
));
661 if (HasActiveJob(server_id
)) {
662 active_requests_
[request
] = server_id
;
663 job_requests_map_
[server_id
].insert(request
);
664 return ERR_IO_PENDING
;
667 // TODO(rtenneti): |task_runner_| is used by the Job. Initialize task_runner_
668 // in the constructor after WebRequestActionWithThreadsTest.* tests are fixed.
670 task_runner_
= base::ThreadTaskRunnerHandle::Get().get();
672 QuicServerInfo
* quic_server_info
= nullptr;
673 if (quic_server_info_factory_
) {
674 bool load_from_disk_cache
= !disable_disk_cache_
;
675 if (http_server_properties_
) {
676 const AlternativeServiceMap
& alternative_service_map
=
677 http_server_properties_
->alternative_service_map();
678 AlternativeServiceMap::const_iterator it
=
679 alternative_service_map
.Peek(server_id
.host_port_pair());
680 if (it
== alternative_service_map
.end() ||
681 it
->second
.alternative_service
.protocol
!= QUIC
) {
682 // If there is no entry for QUIC, consider that as a new server and
683 // don't wait for Cache thread to load the data for that server.
684 load_from_disk_cache
= false;
687 if (load_from_disk_cache
&& CryptoConfigCacheIsEmpty(server_id
)) {
688 quic_server_info
= quic_server_info_factory_
->GetForServer(server_id
);
692 bool server_and_origin_have_same_host
= host_port_pair
.host() == origin_host
;
693 scoped_ptr
<Job
> job(new Job(this, host_resolver_
, host_port_pair
,
694 server_and_origin_have_same_host
, is_https
,
695 WasQuicRecentlyBroken(server_id
), privacy_mode
,
696 cert_verify_flags
, method
== "POST" /* is_post */,
697 quic_server_info
, net_log
));
698 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
699 base::Unretained(this), job
.get()));
700 if (rv
== ERR_IO_PENDING
) {
701 active_requests_
[request
] = server_id
;
702 job_requests_map_
[server_id
].insert(request
);
703 active_jobs_
[server_id
].insert(job
.release());
707 it
= active_sessions_
.find(server_id
);
708 DCHECK(it
!= active_sessions_
.end());
709 QuicClientSession
* session
= it
->second
;
710 if (!session
->CanPool(origin_host
.as_string(), privacy_mode
))
711 return ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN
;
712 request
->set_stream(CreateFromSession(session
));
717 void QuicStreamFactory::CreateAuxilaryJob(const QuicServerId server_id
,
718 int cert_verify_flags
,
719 bool server_and_origin_have_same_host
,
721 const BoundNetLog
& net_log
) {
723 new Job(this, host_resolver_
, server_id
.host_port_pair(),
724 server_and_origin_have_same_host
, server_id
.is_https(),
725 WasQuicRecentlyBroken(server_id
), server_id
.privacy_mode(),
726 cert_verify_flags
, is_post
, nullptr, net_log
);
727 active_jobs_
[server_id
].insert(aux_job
);
728 task_runner_
->PostTask(FROM_HERE
,
729 base::Bind(&QuicStreamFactory::Job::RunAuxilaryJob
,
730 aux_job
->GetWeakPtr()));
733 bool QuicStreamFactory::OnResolution(
734 const QuicServerId
& server_id
,
735 const AddressList
& address_list
) {
736 DCHECK(!HasActiveSession(server_id
));
737 if (disable_connection_pooling_
) {
740 for (const IPEndPoint
& address
: address_list
) {
741 const IpAliasKey
ip_alias_key(address
, server_id
.is_https());
742 if (!ContainsKey(ip_aliases_
, ip_alias_key
))
745 const SessionSet
& sessions
= ip_aliases_
[ip_alias_key
];
746 for (QuicClientSession
* session
: sessions
) {
747 if (!session
->CanPool(server_id
.host(), server_id
.privacy_mode()))
749 active_sessions_
[server_id
] = session
;
750 session_aliases_
[session
].insert(server_id
);
757 void QuicStreamFactory::OnJobComplete(Job
* job
, int rv
) {
758 QuicServerId server_id
= job
->server_id();
760 JobSet
* jobs
= &(active_jobs_
[server_id
]);
761 if (jobs
->size() > 1) {
762 // If there is another pending job, then we can delete this job and let
763 // the other job handle the request.
772 if (!always_require_handshake_confirmation_
)
773 set_require_confirmation(false);
775 // Create all the streams, but do not notify them yet.
776 SessionMap::iterator session_it
= active_sessions_
.find(server_id
);
777 for (RequestSet::iterator request_it
= job_requests_map_
[server_id
].begin();
778 request_it
!= job_requests_map_
[server_id
].end();) {
779 DCHECK(session_it
!= active_sessions_
.end());
780 QuicClientSession
* session
= session_it
->second
;
781 QuicStreamRequest
* request
= *request_it
;
782 if (!session
->CanPool(request
->origin_host(), request
->privacy_mode())) {
783 RequestSet::iterator old_request_it
= request_it
;
785 // Remove request from containers so that OnRequestComplete() is not
786 // called later again on the same request.
787 job_requests_map_
[server_id
].erase(old_request_it
);
788 active_requests_
.erase(request
);
789 // Notify request of certificate error.
790 request
->OnRequestComplete(ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN
);
793 request
->set_stream(CreateFromSession(session
));
798 while (!job_requests_map_
[server_id
].empty()) {
799 RequestSet::iterator it
= job_requests_map_
[server_id
].begin();
800 QuicStreamRequest
* request
= *it
;
801 job_requests_map_
[server_id
].erase(it
);
802 active_requests_
.erase(request
);
803 // Even though we're invoking callbacks here, we don't need to worry
804 // about |this| being deleted, because the factory is owned by the
805 // profile which can not be deleted via callbacks.
806 request
->OnRequestComplete(rv
);
809 for (Job
* other_job
: active_jobs_
[server_id
]) {
810 if (other_job
!= job
)
814 STLDeleteElements(&(active_jobs_
[server_id
]));
815 active_jobs_
.erase(server_id
);
816 job_requests_map_
.erase(server_id
);
819 scoped_ptr
<QuicHttpStream
> QuicStreamFactory::CreateFromSession(
820 QuicClientSession
* session
) {
821 return scoped_ptr
<QuicHttpStream
>(new QuicHttpStream(session
->GetWeakPtr()));
824 bool QuicStreamFactory::IsQuicDisabled(uint16 port
) {
825 return max_number_of_lossy_connections_
> 0 &&
826 number_of_lossy_connections_
[port
] >= max_number_of_lossy_connections_
;
829 bool QuicStreamFactory::OnHandshakeConfirmed(QuicClientSession
* session
,
830 float packet_loss_rate
) {
832 uint16 port
= session
->server_id().port();
833 if (packet_loss_rate
< packet_loss_threshold_
) {
834 number_of_lossy_connections_
[port
] = 0;
838 if (http_server_properties_
) {
839 // We mark it as recently broken, which means that 0-RTT will be disabled
840 // but we'll still race.
841 http_server_properties_
->MarkAlternativeServiceRecentlyBroken(
842 AlternativeService(QUIC
, session
->server_id().host(), port
));
845 bool was_quic_disabled
= IsQuicDisabled(port
);
846 ++number_of_lossy_connections_
[port
];
848 // Collect data for port 443 for packet loss events.
849 if (port
== 443 && max_number_of_lossy_connections_
> 0) {
850 UMA_HISTOGRAM_SPARSE_SLOWLY(
851 base::StringPrintf("Net.QuicStreamFactory.BadPacketLossEvents%d",
852 max_number_of_lossy_connections_
),
853 std::min(number_of_lossy_connections_
[port
],
854 max_number_of_lossy_connections_
));
857 bool is_quic_disabled
= IsQuicDisabled(port
);
858 if (is_quic_disabled
) {
859 // Close QUIC connection if Quic is disabled for this port.
860 session
->CloseSessionOnErrorAndNotifyFactoryLater(
861 ERR_ABORTED
, QUIC_BAD_PACKET_LOSS_RATE
);
863 // If this bad packet loss rate disabled the QUIC, then record it.
864 if (!was_quic_disabled
)
865 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicStreamFactory.QuicIsDisabled", port
);
867 return is_quic_disabled
;
870 void QuicStreamFactory::OnIdleSession(QuicClientSession
* session
) {
873 void QuicStreamFactory::OnSessionGoingAway(QuicClientSession
* session
) {
874 const AliasSet
& aliases
= session_aliases_
[session
];
875 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
877 DCHECK(active_sessions_
.count(*it
));
878 DCHECK_EQ(session
, active_sessions_
[*it
]);
879 // Track sessions which have recently gone away so that we can disable
881 if (session
->goaway_received()) {
882 gone_away_aliases_
.insert(*it
);
885 active_sessions_
.erase(*it
);
886 ProcessGoingAwaySession(session
, *it
, true);
888 ProcessGoingAwaySession(session
, all_sessions_
[session
], false);
889 if (!aliases
.empty()) {
890 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
891 aliases
.begin()->is_https());
892 ip_aliases_
[ip_alias_key
].erase(session
);
893 if (ip_aliases_
[ip_alias_key
].empty()) {
894 ip_aliases_
.erase(ip_alias_key
);
897 session_aliases_
.erase(session
);
900 void QuicStreamFactory::OnSessionClosed(QuicClientSession
* session
) {
901 DCHECK_EQ(0u, session
->GetNumOpenStreams());
902 OnSessionGoingAway(session
);
904 all_sessions_
.erase(session
);
907 void QuicStreamFactory::OnSessionConnectTimeout(
908 QuicClientSession
* session
) {
909 const AliasSet
& aliases
= session_aliases_
[session
];
910 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
912 DCHECK(active_sessions_
.count(*it
));
913 DCHECK_EQ(session
, active_sessions_
[*it
]);
914 active_sessions_
.erase(*it
);
917 if (aliases
.empty()) {
921 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
922 aliases
.begin()->is_https());
923 ip_aliases_
[ip_alias_key
].erase(session
);
924 if (ip_aliases_
[ip_alias_key
].empty()) {
925 ip_aliases_
.erase(ip_alias_key
);
927 QuicServerId server_id
= *aliases
.begin();
928 session_aliases_
.erase(session
);
929 Job
* job
= new Job(this, host_resolver_
, session
, server_id
);
930 active_jobs_
[server_id
].insert(job
);
931 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
932 base::Unretained(this), job
));
933 DCHECK_EQ(ERR_IO_PENDING
, rv
);
936 void QuicStreamFactory::CancelRequest(QuicStreamRequest
* request
) {
937 DCHECK(ContainsKey(active_requests_
, request
));
938 QuicServerId server_id
= active_requests_
[request
];
939 job_requests_map_
[server_id
].erase(request
);
940 active_requests_
.erase(request
);
943 void QuicStreamFactory::CloseAllSessions(int error
) {
944 while (!active_sessions_
.empty()) {
945 size_t initial_size
= active_sessions_
.size();
946 active_sessions_
.begin()->second
->CloseSessionOnError(error
,
947 QUIC_INTERNAL_ERROR
);
948 DCHECK_NE(initial_size
, active_sessions_
.size());
950 while (!all_sessions_
.empty()) {
951 size_t initial_size
= all_sessions_
.size();
952 all_sessions_
.begin()->first
->CloseSessionOnError(error
,
953 QUIC_INTERNAL_ERROR
);
954 DCHECK_NE(initial_size
, all_sessions_
.size());
956 DCHECK(all_sessions_
.empty());
959 scoped_ptr
<base::Value
> QuicStreamFactory::QuicStreamFactoryInfoToValue()
961 scoped_ptr
<base::ListValue
> list(new base::ListValue());
963 for (SessionMap::const_iterator it
= active_sessions_
.begin();
964 it
!= active_sessions_
.end(); ++it
) {
965 const QuicServerId
& server_id
= it
->first
;
966 QuicClientSession
* session
= it
->second
;
967 const AliasSet
& aliases
= session_aliases_
.find(session
)->second
;
968 // Only add a session to the list once.
969 if (server_id
== *aliases
.begin()) {
970 std::set
<HostPortPair
> hosts
;
971 for (AliasSet::const_iterator alias_it
= aliases
.begin();
972 alias_it
!= aliases
.end(); ++alias_it
) {
973 hosts
.insert(alias_it
->host_port_pair());
975 list
->Append(session
->GetInfoAsValue(hosts
));
981 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
982 crypto_config_
.ClearCachedStates();
985 void QuicStreamFactory::OnIPAddressChanged() {
986 CloseAllSessions(ERR_NETWORK_CHANGED
);
987 set_require_confirmation(true);
990 void QuicStreamFactory::OnCertAdded(const X509Certificate
* cert
) {
991 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
994 void QuicStreamFactory::OnCACertChanged(const X509Certificate
* cert
) {
995 // We should flush the sessions if we removed trust from a
996 // cert, because a previously trusted server may have become
999 // We should not flush the sessions if we added trust to a cert.
1001 // Since the OnCACertChanged method doesn't tell us what
1002 // kind of change it is, we have to flush the socket
1003 // pools to be safe.
1004 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
1007 bool QuicStreamFactory::HasActiveSession(
1008 const QuicServerId
& server_id
) const {
1009 return ContainsKey(active_sessions_
, server_id
);
1012 bool QuicStreamFactory::HasActiveJob(const QuicServerId
& key
) const {
1013 return ContainsKey(active_jobs_
, key
);
1016 int QuicStreamFactory::CreateSession(const QuicServerId
& server_id
,
1017 int cert_verify_flags
,
1018 scoped_ptr
<QuicServerInfo
> server_info
,
1019 const AddressList
& address_list
,
1020 base::TimeTicks dns_resolution_end_time
,
1021 const BoundNetLog
& net_log
,
1022 QuicClientSession
** session
) {
1023 bool enable_port_selection
= enable_port_selection_
;
1024 if (enable_port_selection
&&
1025 ContainsKey(gone_away_aliases_
, server_id
)) {
1026 // Disable port selection when the server is going away.
1027 // There is no point in trying to return to the same server, if
1028 // that server is no longer handling requests.
1029 enable_port_selection
= false;
1030 gone_away_aliases_
.erase(server_id
);
1033 QuicConnectionId connection_id
= random_generator_
->RandUint64();
1034 IPEndPoint addr
= *address_list
.begin();
1035 scoped_refptr
<PortSuggester
> port_suggester
=
1036 new PortSuggester(server_id
.host_port_pair(), port_seed_
);
1037 DatagramSocket::BindType bind_type
= enable_port_selection
?
1038 DatagramSocket::RANDOM_BIND
: // Use our callback.
1039 DatagramSocket::DEFAULT_BIND
; // Use OS to randomize.
1040 scoped_ptr
<DatagramClientSocket
> socket(
1041 client_socket_factory_
->CreateDatagramClientSocket(
1043 base::Bind(&PortSuggester::SuggestPort
, port_suggester
),
1044 net_log
.net_log(), net_log
.source()));
1046 if (enable_non_blocking_io_
&&
1047 client_socket_factory_
== ClientSocketFactory::GetDefaultFactory()) {
1049 static_cast<UDPClientSocket
*>(socket
.get())->UseNonBlockingIO();
1053 int rv
= socket
->Connect(addr
);
1056 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET
);
1059 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested",
1060 port_suggester
->call_count());
1061 if (enable_port_selection
) {
1062 DCHECK_LE(1u, port_suggester
->call_count());
1064 DCHECK_EQ(0u, port_suggester
->call_count());
1067 rv
= socket
->SetReceiveBufferSize(socket_receive_buffer_size_
);
1069 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER
);
1072 // Set a buffer large enough to contain the initial CWND's worth of packet
1073 // to work around the problem with CHLO packets being sent out with the
1074 // wrong encryption level, when the send buffer is full.
1075 rv
= socket
->SetSendBufferSize(kMaxPacketSize
* 20);
1077 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER
);
1081 socket
->GetLocalAddress(&local_address_
);
1082 if (check_persisted_supports_quic_
&& http_server_properties_
) {
1083 check_persisted_supports_quic_
= false;
1084 IPAddressNumber last_address
;
1085 if (http_server_properties_
->GetSupportsQuic(&last_address
) &&
1086 last_address
== local_address_
.address()) {
1087 require_confirmation_
= false;
1091 DefaultPacketWriterFactory
packet_writer_factory(socket
.get());
1093 if (!helper_
.get()) {
1095 new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(),
1096 clock_
.get(), random_generator_
));
1099 QuicConnection
* connection
= new QuicConnection(
1100 connection_id
, addr
, helper_
.get(), packet_writer_factory
,
1101 true /* owns_writer */, Perspective::IS_CLIENT
, server_id
.is_https(),
1102 supported_versions_
);
1103 connection
->set_max_packet_length(max_packet_length_
);
1105 InitializeCachedStateInCryptoConfig(server_id
, server_info
);
1107 QuicConfig config
= config_
;
1108 config
.SetSocketReceiveBufferToSend(socket_receive_buffer_size_
);
1109 config
.set_max_undecryptable_packets(kMaxUndecryptablePackets
);
1110 config
.SetInitialSessionFlowControlWindowToSend(
1111 kQuicSessionMaxRecvWindowSize
);
1112 config
.SetInitialStreamFlowControlWindowToSend(kQuicStreamMaxRecvWindowSize
);
1113 int64 srtt
= GetServerNetworkStatsSmoothedRttInMicroseconds(server_id
);
1115 config
.SetInitialRoundTripTimeUsToSend(static_cast<uint32
>(srtt
));
1116 config
.SetBytesForConnectionIdToSend(0);
1118 if (quic_server_info_factory_
&& !server_info
) {
1119 // Start the disk cache loading so that we can persist the newer QUIC server
1120 // information and/or inform the disk cache that we have reused
1122 server_info
.reset(quic_server_info_factory_
->GetForServer(server_id
));
1123 server_info
->Start();
1126 *session
= new QuicClientSession(
1127 connection
, socket
.Pass(), this, quic_crypto_client_stream_factory_
,
1128 transport_security_state_
, server_info
.Pass(), server_id
,
1129 cert_verify_flags
, config
, &crypto_config_
,
1130 network_connection_
.GetDescription(), dns_resolution_end_time
,
1131 base::ThreadTaskRunnerHandle::Get().get(), net_log
.net_log());
1133 all_sessions_
[*session
] = server_id
; // owning pointer
1135 (*session
)->Initialize();
1136 bool closed_during_initialize
=
1137 !ContainsKey(all_sessions_
, *session
) ||
1138 !(*session
)->connection()->connected();
1139 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedDuringInitializeSession",
1140 closed_during_initialize
);
1141 if (closed_during_initialize
) {
1142 DLOG(DFATAL
) << "Session closed during initialize";
1144 return ERR_CONNECTION_CLOSED
;
1149 void QuicStreamFactory::ActivateSession(
1150 const QuicServerId
& server_id
,
1151 QuicClientSession
* session
) {
1152 DCHECK(!HasActiveSession(server_id
));
1153 UMA_HISTOGRAM_COUNTS("Net.QuicActiveSessions", active_sessions_
.size());
1154 active_sessions_
[server_id
] = session
;
1155 session_aliases_
[session
].insert(server_id
);
1156 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
1157 server_id
.is_https());
1158 DCHECK(!ContainsKey(ip_aliases_
[ip_alias_key
], session
));
1159 ip_aliases_
[ip_alias_key
].insert(session
);
1162 int64
QuicStreamFactory::GetServerNetworkStatsSmoothedRttInMicroseconds(
1163 const QuicServerId
& server_id
) const {
1164 if (!http_server_properties_
)
1166 const ServerNetworkStats
* stats
=
1167 http_server_properties_
->GetServerNetworkStats(
1168 server_id
.host_port_pair());
1169 if (stats
== nullptr)
1171 return stats
->srtt
.InMicroseconds();
1174 bool QuicStreamFactory::WasQuicRecentlyBroken(
1175 const QuicServerId
& server_id
) const {
1176 if (!http_server_properties_
)
1178 const AlternativeService
alternative_service(QUIC
,
1179 server_id
.host_port_pair());
1180 return http_server_properties_
->WasAlternativeServiceRecentlyBroken(
1181 alternative_service
);
1184 bool QuicStreamFactory::CryptoConfigCacheIsEmpty(
1185 const QuicServerId
& server_id
) {
1186 QuicCryptoClientConfig::CachedState
* cached
=
1187 crypto_config_
.LookupOrCreate(server_id
);
1188 return cached
->IsEmpty();
1191 void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
1192 const QuicServerId
& server_id
,
1193 const scoped_ptr
<QuicServerInfo
>& server_info
) {
1194 // |server_info| will be NULL, if a non-empty server config already exists in
1195 // the memory cache. This is a minor optimization to avoid LookupOrCreate.
1199 QuicCryptoClientConfig::CachedState
* cached
=
1200 crypto_config_
.LookupOrCreate(server_id
);
1201 if (!cached
->IsEmpty())
1204 if (http_server_properties_
) {
1205 if (quic_supported_servers_at_startup_
.empty()) {
1206 for (const std::pair
<const HostPortPair
, AlternativeServiceInfo
>&
1207 key_value
: http_server_properties_
->alternative_service_map()) {
1208 if (key_value
.second
.alternative_service
.protocol
== QUIC
) {
1209 quic_supported_servers_at_startup_
.insert(key_value
.first
);
1214 // TODO(rtenneti): Delete the following histogram after collecting stats.
1215 // If the AlternativeServiceMap contained an entry for this host, check if
1216 // the disk cache contained an entry for it.
1217 if (ContainsKey(quic_supported_servers_at_startup_
,
1218 server_id
.host_port_pair())) {
1219 UMA_HISTOGRAM_BOOLEAN(
1220 "Net.QuicServerInfo.ExpectConfigMissingFromDiskCache",
1221 server_info
->state().server_config
.empty());
1225 if (!cached
->Initialize(server_info
->state().server_config
,
1226 server_info
->state().source_address_token
,
1227 server_info
->state().certs
,
1228 server_info
->state().server_config_sig
,
1232 if (!server_id
.is_https()) {
1233 // Don't check the certificates for insecure QUIC.
1234 cached
->SetProofValid();
1238 void QuicStreamFactory::ProcessGoingAwaySession(
1239 QuicClientSession
* session
,
1240 const QuicServerId
& server_id
,
1241 bool session_was_active
) {
1242 if (!http_server_properties_
)
1245 const QuicConnectionStats
& stats
= session
->connection()->GetStats();
1246 const AlternativeService
alternative_service(QUIC
,
1247 server_id
.host_port_pair());
1248 if (session
->IsCryptoHandshakeConfirmed()) {
1249 http_server_properties_
->ConfirmAlternativeService(alternative_service
);
1250 ServerNetworkStats network_stats
;
1251 network_stats
.srtt
= base::TimeDelta::FromMicroseconds(stats
.srtt_us
);
1252 network_stats
.bandwidth_estimate
= stats
.estimated_bandwidth
;
1253 http_server_properties_
->SetServerNetworkStats(server_id
.host_port_pair(),
1258 UMA_HISTOGRAM_COUNTS("Net.QuicHandshakeNotConfirmedNumPacketsReceived",
1259 stats
.packets_received
);
1261 if (!session_was_active
)
1264 // TODO(rch): In the special case where the session has received no
1265 // packets from the peer, we should consider blacklisting this
1266 // differently so that we still race TCP but we don't consider the
1267 // session connected until the handshake has been confirmed.
1268 HistogramBrokenAlternateProtocolLocation(
1269 BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY
);
1271 // Since the session was active, there's no longer an
1272 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the TCP
1273 // job also fails. So to avoid not using QUIC when we otherwise could, we mark
1274 // it as recently broken, which means that 0-RTT will be disabled but we'll
1276 http_server_properties_
->MarkAlternativeServiceRecentlyBroken(
1277 alternative_service
);