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/message_loop/message_loop.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/metrics/field_trial.h"
14 #include "base/metrics/histogram.h"
15 #include "base/metrics/sparse_histogram.h"
16 #include "base/rand_util.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/values.h"
21 #include "net/base/net_errors.h"
22 #include "net/cert/cert_verifier.h"
23 #include "net/dns/host_resolver.h"
24 #include "net/dns/single_request_host_resolver.h"
25 #include "net/http/http_server_properties.h"
26 #include "net/quic/crypto/channel_id_chromium.h"
27 #include "net/quic/crypto/proof_verifier_chromium.h"
28 #include "net/quic/crypto/quic_random.h"
29 #include "net/quic/crypto/quic_server_info.h"
30 #include "net/quic/port_suggester.h"
31 #include "net/quic/quic_client_session.h"
32 #include "net/quic/quic_clock.h"
33 #include "net/quic/quic_connection.h"
34 #include "net/quic/quic_connection_helper.h"
35 #include "net/quic/quic_crypto_client_stream_factory.h"
36 #include "net/quic/quic_default_packet_writer.h"
37 #include "net/quic/quic_flags.h"
38 #include "net/quic/quic_http_stream.h"
39 #include "net/quic/quic_protocol.h"
40 #include "net/quic/quic_server_id.h"
41 #include "net/socket/client_socket_factory.h"
42 #include "net/udp/udp_client_socket.h"
45 #include "base/win/windows_version.h"
52 enum CreateSessionFailure
{
53 CREATION_ERROR_CONNECTING_SOCKET
,
54 CREATION_ERROR_SETTING_RECEIVE_BUFFER
,
55 CREATION_ERROR_SETTING_SEND_BUFFER
,
59 // When a connection is idle for 30 seconds it will be closed.
60 const int kIdleConnectionTimeoutSeconds
= 30;
62 // The maximum receive window sizes for QUIC sessions and streams.
63 const int32 kQuicSessionMaxRecvWindowSize
= 15 * 1024 * 1024; // 15 MB
64 const int32 kQuicStreamMaxRecvWindowSize
= 6 * 1024 * 1024; // 6 MB
66 // Set the maximum number of undecryptable packets the connection will store.
67 const int32 kMaxUndecryptablePackets
= 100;
69 void HistogramCreateSessionFailure(enum CreateSessionFailure error
) {
70 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error
,
74 bool IsEcdsaSupported() {
76 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
83 QuicConfig
InitializeQuicConfig(const QuicTagVector
& connection_options
) {
85 config
.SetIdleConnectionStateLifetime(
86 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
),
87 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
));
88 config
.SetConnectionOptionsToSend(connection_options
);
92 class DefaultPacketWriterFactory
: public QuicConnection::PacketWriterFactory
{
94 explicit DefaultPacketWriterFactory(DatagramClientSocket
* socket
)
96 ~DefaultPacketWriterFactory() override
{}
98 QuicPacketWriter
* Create(QuicConnection
* connection
) const override
;
101 DatagramClientSocket
* socket_
;
104 QuicPacketWriter
* DefaultPacketWriterFactory::Create(
105 QuicConnection
* connection
) const {
106 scoped_ptr
<QuicDefaultPacketWriter
> writer(
107 new QuicDefaultPacketWriter(socket_
));
108 writer
->SetConnection(connection
);
109 return writer
.release();
114 QuicStreamFactory::IpAliasKey::IpAliasKey() {}
116 QuicStreamFactory::IpAliasKey::IpAliasKey(IPEndPoint ip_endpoint
,
118 : ip_endpoint(ip_endpoint
),
119 is_https(is_https
) {}
121 QuicStreamFactory::IpAliasKey::~IpAliasKey() {}
123 bool QuicStreamFactory::IpAliasKey::operator<(
124 const QuicStreamFactory::IpAliasKey
& other
) const {
125 if (!(ip_endpoint
== other
.ip_endpoint
)) {
126 return ip_endpoint
< other
.ip_endpoint
;
128 return is_https
< other
.is_https
;
131 bool QuicStreamFactory::IpAliasKey::operator==(
132 const QuicStreamFactory::IpAliasKey
& other
) const {
133 return is_https
== other
.is_https
&&
134 ip_endpoint
== other
.ip_endpoint
;
137 // Responsible for creating a new QUIC session to the specified server, and
138 // for notifying any associated requests when complete.
139 class QuicStreamFactory::Job
{
141 Job(QuicStreamFactory
* factory
,
142 HostResolver
* host_resolver
,
143 const HostPortPair
& host_port_pair
,
144 bool server_and_origin_have_same_host
,
146 bool was_alternative_service_recently_broken
,
147 PrivacyMode privacy_mode
,
149 QuicServerInfo
* server_info
,
150 const BoundNetLog
& net_log
);
152 // Creates a new job to handle the resumption of for connecting an
154 Job(QuicStreamFactory
* factory
,
155 HostResolver
* host_resolver
,
156 QuicClientSession
* session
,
157 QuicServerId server_id
);
161 int Run(const CompletionCallback
& callback
);
165 int DoResolveHostComplete(int rv
);
166 int DoLoadServerInfo();
167 int DoLoadServerInfoComplete(int rv
);
169 int DoResumeConnect();
170 int DoConnectComplete(int rv
);
172 void OnIOComplete(int rv
);
174 void RunAuxilaryJob();
178 void CancelWaitForDataReadyCallback();
180 const QuicServerId
server_id() const { return server_id_
; }
182 base::WeakPtr
<Job
> GetWeakPtr() { return weak_factory_
.GetWeakPtr(); }
188 STATE_RESOLVE_HOST_COMPLETE
,
189 STATE_LOAD_SERVER_INFO
,
190 STATE_LOAD_SERVER_INFO_COMPLETE
,
192 STATE_RESUME_CONNECT
,
193 STATE_CONNECT_COMPLETE
,
197 QuicStreamFactory
* factory_
;
198 SingleRequestHostResolver host_resolver_
;
199 QuicServerId server_id_
;
200 // True if and only if server and origin have the same hostname.
201 bool server_and_origin_have_same_host_
;
203 bool was_alternative_service_recently_broken_
;
204 scoped_ptr
<QuicServerInfo
> server_info_
;
205 bool started_another_job_
;
206 const BoundNetLog net_log_
;
207 QuicClientSession
* session_
;
208 CompletionCallback callback_
;
209 AddressList address_list_
;
210 base::TimeTicks dns_resolution_start_time_
;
211 base::TimeTicks dns_resolution_end_time_
;
212 base::WeakPtrFactory
<Job
> weak_factory_
;
213 DISALLOW_COPY_AND_ASSIGN(Job
);
216 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
217 HostResolver
* host_resolver
,
218 const HostPortPair
& host_port_pair
,
219 bool server_and_origin_have_same_host
,
221 bool was_alternative_service_recently_broken
,
222 PrivacyMode privacy_mode
,
224 QuicServerInfo
* server_info
,
225 const BoundNetLog
& net_log
)
226 : io_state_(STATE_RESOLVE_HOST
),
228 host_resolver_(host_resolver
),
229 server_id_(host_port_pair
, is_https
, privacy_mode
),
230 server_and_origin_have_same_host_(server_and_origin_have_same_host
),
232 was_alternative_service_recently_broken_(
233 was_alternative_service_recently_broken
),
234 server_info_(server_info
),
235 started_another_job_(false),
238 weak_factory_(this) {
241 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
242 HostResolver
* host_resolver
,
243 QuicClientSession
* session
,
244 QuicServerId server_id
)
245 : io_state_(STATE_RESUME_CONNECT
),
247 host_resolver_(host_resolver
), // unused
248 server_id_(server_id
),
249 server_and_origin_have_same_host_(false), // unused
250 is_post_(false), // unused
251 was_alternative_service_recently_broken_(false), // unused
252 started_another_job_(false), // unused
253 net_log_(session
->net_log()), // unused
255 weak_factory_(this) {
258 QuicStreamFactory::Job::~Job() {
259 // If disk cache has a pending WaitForDataReadyCallback, cancel that callback.
261 server_info_
->ResetWaitForDataReadyCallback();
264 int QuicStreamFactory::Job::Run(const CompletionCallback
& callback
) {
266 if (rv
== ERR_IO_PENDING
)
267 callback_
= callback
;
269 return rv
> 0 ? OK
: rv
;
272 int QuicStreamFactory::Job::DoLoop(int rv
) {
274 IoState state
= io_state_
;
275 io_state_
= STATE_NONE
;
277 case STATE_RESOLVE_HOST
:
279 rv
= DoResolveHost();
281 case STATE_RESOLVE_HOST_COMPLETE
:
282 rv
= DoResolveHostComplete(rv
);
284 case STATE_LOAD_SERVER_INFO
:
286 rv
= DoLoadServerInfo();
288 case STATE_LOAD_SERVER_INFO_COMPLETE
:
289 rv
= DoLoadServerInfoComplete(rv
);
295 case STATE_RESUME_CONNECT
:
297 rv
= DoResumeConnect();
299 case STATE_CONNECT_COMPLETE
:
300 rv
= DoConnectComplete(rv
);
303 NOTREACHED() << "io_state_: " << io_state_
;
306 } while (io_state_
!= STATE_NONE
&& rv
!= ERR_IO_PENDING
);
310 void QuicStreamFactory::Job::OnIOComplete(int rv
) {
312 if (rv
!= ERR_IO_PENDING
&& !callback_
.is_null()) {
317 void QuicStreamFactory::Job::RunAuxilaryJob() {
318 int rv
= Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
319 base::Unretained(factory_
), this));
320 if (rv
!= ERR_IO_PENDING
)
321 factory_
->OnJobComplete(this, rv
);
324 void QuicStreamFactory::Job::Cancel() {
327 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_CANCELLED
);
330 void QuicStreamFactory::Job::CancelWaitForDataReadyCallback() {
331 // If we are waiting for WaitForDataReadyCallback, then cancel the callback.
332 if (io_state_
!= STATE_LOAD_SERVER_INFO_COMPLETE
)
334 server_info_
->CancelWaitForDataReadyCallback();
338 int QuicStreamFactory::Job::DoResolveHost() {
339 // Start loading the data now, and wait for it after we resolve the host.
341 server_info_
->Start();
344 io_state_
= STATE_RESOLVE_HOST_COMPLETE
;
345 dns_resolution_start_time_
= base::TimeTicks::Now();
346 return host_resolver_
.Resolve(
347 HostResolver::RequestInfo(server_id_
.host_port_pair()), DEFAULT_PRIORITY
,
349 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()),
353 int QuicStreamFactory::Job::DoResolveHostComplete(int rv
) {
354 dns_resolution_end_time_
= base::TimeTicks::Now();
355 UMA_HISTOGRAM_TIMES("Net.QuicSession.HostResolutionTime",
356 dns_resolution_end_time_
- dns_resolution_start_time_
);
360 DCHECK(!factory_
->HasActiveSession(server_id_
));
362 // Inform the factory of this resolution, which will set up
363 // a session alias, if possible.
364 if (factory_
->OnResolution(server_id_
, address_list_
)) {
369 io_state_
= STATE_LOAD_SERVER_INFO
;
371 io_state_
= STATE_CONNECT
;
375 int QuicStreamFactory::Job::DoLoadServerInfo() {
376 io_state_
= STATE_LOAD_SERVER_INFO_COMPLETE
;
378 DCHECK(server_info_
);
380 // To mitigate the effects of disk cache taking too long to load QUIC server
381 // information, set up a timer to cancel WaitForDataReady's callback.
382 if (factory_
->load_server_info_timeout_srtt_multiplier_
> 0) {
383 int64 load_server_info_timeout_ms
=
384 (factory_
->load_server_info_timeout_srtt_multiplier_
*
385 factory_
->GetServerNetworkStatsSmoothedRttInMicroseconds(server_id_
)) /
387 if (load_server_info_timeout_ms
> 0) {
388 factory_
->task_runner_
->PostDelayedTask(
390 base::Bind(&QuicStreamFactory::Job::CancelWaitForDataReadyCallback
,
392 base::TimeDelta::FromMilliseconds(load_server_info_timeout_ms
));
396 int rv
= server_info_
->WaitForDataReady(
397 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
398 if (rv
== ERR_IO_PENDING
&& factory_
->enable_connection_racing()) {
399 // If we are waiting to load server config from the disk cache, then start
401 started_another_job_
= true;
402 factory_
->CreateAuxilaryJob(server_id_
, server_and_origin_have_same_host_
,
408 int QuicStreamFactory::Job::DoLoadServerInfoComplete(int rv
) {
409 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheWaitForDataReadyTime",
410 base::TimeTicks::Now() - dns_resolution_end_time_
);
413 server_info_
.reset();
415 if (started_another_job_
&&
416 (!server_info_
|| server_info_
->state().server_config
.empty() ||
417 !factory_
->CryptoConfigCacheIsEmpty(server_id_
))) {
418 // If we have started another job and if we didn't load the server config
419 // from the disk cache or if we have received a new server config from the
420 // server, then cancel the current job.
421 io_state_
= STATE_NONE
;
422 return ERR_CONNECTION_CLOSED
;
425 io_state_
= STATE_CONNECT
;
429 int QuicStreamFactory::Job::DoConnect() {
430 io_state_
= STATE_CONNECT_COMPLETE
;
433 factory_
->CreateSession(server_id_
, server_info_
.Pass(), address_list_
,
434 dns_resolution_end_time_
, net_log_
, &session_
);
436 DCHECK(rv
!= ERR_IO_PENDING
);
441 if (!session_
->connection()->connected()) {
442 return ERR_CONNECTION_CLOSED
;
445 session_
->StartReading();
446 if (!session_
->connection()->connected()) {
447 return ERR_QUIC_PROTOCOL_ERROR
;
449 bool require_confirmation
= factory_
->require_confirmation() ||
450 !server_and_origin_have_same_host_
|| is_post_
||
451 was_alternative_service_recently_broken_
;
453 rv
= session_
->CryptoConnect(
454 require_confirmation
,
455 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
459 int QuicStreamFactory::Job::DoResumeConnect() {
460 io_state_
= STATE_CONNECT_COMPLETE
;
462 int rv
= session_
->ResumeCryptoConnect(
463 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
468 int QuicStreamFactory::Job::DoConnectComplete(int rv
) {
472 DCHECK(!factory_
->HasActiveSession(server_id_
));
473 // There may well now be an active session for this IP. If so, use the
474 // existing session instead.
475 AddressList
address(session_
->connection()->peer_address());
476 if (factory_
->OnResolution(server_id_
, address
)) {
477 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_IP_POOLED
);
482 factory_
->ActivateSession(server_id_
, session_
);
487 QuicStreamRequest::QuicStreamRequest(QuicStreamFactory
* factory
)
488 : factory_(factory
) {}
490 QuicStreamRequest::~QuicStreamRequest() {
491 if (factory_
&& !callback_
.is_null())
492 factory_
->CancelRequest(this);
495 int QuicStreamRequest::Request(const HostPortPair
& host_port_pair
,
497 PrivacyMode privacy_mode
,
498 base::StringPiece origin_host
,
499 base::StringPiece method
,
500 const BoundNetLog
& net_log
,
501 const CompletionCallback
& callback
) {
503 DCHECK(callback_
.is_null());
505 origin_host_
= origin_host
.as_string();
506 privacy_mode_
= privacy_mode
;
507 int rv
= factory_
->Create(host_port_pair
, is_https
, privacy_mode
, origin_host
,
508 method
, net_log
, this);
509 if (rv
== ERR_IO_PENDING
) {
510 host_port_pair_
= host_port_pair
;
512 callback_
= callback
;
521 void QuicStreamRequest::set_stream(scoped_ptr
<QuicHttpStream
> stream
) {
523 stream_
= stream
.Pass();
526 void QuicStreamRequest::OnRequestComplete(int rv
) {
531 scoped_ptr
<QuicHttpStream
> QuicStreamRequest::ReleaseStream() {
533 return stream_
.Pass();
536 QuicStreamFactory::QuicStreamFactory(
537 HostResolver
* host_resolver
,
538 ClientSocketFactory
* client_socket_factory
,
539 base::WeakPtr
<HttpServerProperties
> http_server_properties
,
540 CertVerifier
* cert_verifier
,
541 ChannelIDService
* channel_id_service
,
542 TransportSecurityState
* transport_security_state
,
543 QuicCryptoClientStreamFactory
* quic_crypto_client_stream_factory
,
544 QuicRandom
* random_generator
,
546 size_t max_packet_length
,
547 const std::string
& user_agent_id
,
548 const QuicVersionVector
& supported_versions
,
549 bool enable_port_selection
,
550 bool always_require_handshake_confirmation
,
551 bool disable_connection_pooling
,
552 float load_server_info_timeout_srtt_multiplier
,
553 bool enable_connection_racing
,
554 bool enable_non_blocking_io
,
555 bool disable_disk_cache
,
556 int max_number_of_lossy_connections
,
557 float packet_loss_threshold
,
558 int socket_receive_buffer_size
,
559 const QuicTagVector
& connection_options
)
560 : require_confirmation_(true),
561 host_resolver_(host_resolver
),
562 client_socket_factory_(client_socket_factory
),
563 http_server_properties_(http_server_properties
),
564 transport_security_state_(transport_security_state
),
565 quic_server_info_factory_(nullptr),
566 quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory
),
567 random_generator_(random_generator
),
569 max_packet_length_(max_packet_length
),
570 config_(InitializeQuicConfig(connection_options
)),
571 supported_versions_(supported_versions
),
572 enable_port_selection_(enable_port_selection
),
573 always_require_handshake_confirmation_(
574 always_require_handshake_confirmation
),
575 disable_connection_pooling_(disable_connection_pooling
),
576 load_server_info_timeout_srtt_multiplier_(
577 load_server_info_timeout_srtt_multiplier
),
578 enable_connection_racing_(enable_connection_racing
),
579 enable_non_blocking_io_(enable_non_blocking_io
),
580 disable_disk_cache_(disable_disk_cache
),
581 max_number_of_lossy_connections_(max_number_of_lossy_connections
),
582 packet_loss_threshold_(packet_loss_threshold
),
583 socket_receive_buffer_size_(socket_receive_buffer_size
),
584 port_seed_(random_generator_
->RandUint64()),
585 check_persisted_supports_quic_(true),
586 task_runner_(nullptr),
587 weak_factory_(this) {
588 DCHECK(transport_security_state_
);
589 crypto_config_
.set_user_agent_id(user_agent_id
);
590 crypto_config_
.AddCanonicalSuffix(".c.youtube.com");
591 crypto_config_
.AddCanonicalSuffix(".googlevideo.com");
592 crypto_config_
.AddCanonicalSuffix(".googleusercontent.com");
593 crypto_config_
.SetProofVerifier(
594 new ProofVerifierChromium(cert_verifier
, transport_security_state
));
595 // TODO(rtenneti): http://crbug.com/487355. Temporary fix for b/20760730 until
596 // channel_id_service is supported in cronet.
597 if (channel_id_service
) {
598 crypto_config_
.SetChannelIDSource(
599 new ChannelIDSourceChromium(channel_id_service
));
602 bool has_aes_hardware_support
= cpu
.has_aesni() && cpu
.has_avx();
603 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.PreferAesGcm",
604 has_aes_hardware_support
);
605 if (has_aes_hardware_support
)
606 crypto_config_
.PreferAesGcm();
607 if (!IsEcdsaSupported())
608 crypto_config_
.DisableEcdsa();
611 QuicStreamFactory::~QuicStreamFactory() {
612 CloseAllSessions(ERR_ABORTED
);
613 while (!all_sessions_
.empty()) {
614 delete all_sessions_
.begin()->first
;
615 all_sessions_
.erase(all_sessions_
.begin());
617 while (!active_jobs_
.empty()) {
618 const QuicServerId server_id
= active_jobs_
.begin()->first
;
619 STLDeleteElements(&(active_jobs_
[server_id
]));
620 active_jobs_
.erase(server_id
);
624 void QuicStreamFactory::set_require_confirmation(bool require_confirmation
) {
625 require_confirmation_
= require_confirmation
;
626 if (http_server_properties_
&& (!(local_address_
== IPEndPoint()))) {
627 http_server_properties_
->SetSupportsQuic(!require_confirmation
,
628 local_address_
.address());
632 int QuicStreamFactory::Create(const HostPortPair
& host_port_pair
,
634 PrivacyMode privacy_mode
,
635 base::StringPiece origin_host
,
636 base::StringPiece method
,
637 const BoundNetLog
& net_log
,
638 QuicStreamRequest
* request
) {
639 QuicServerId
server_id(host_port_pair
, is_https
, privacy_mode
);
640 SessionMap::iterator it
= active_sessions_
.find(server_id
);
641 if (it
!= active_sessions_
.end()) {
642 QuicClientSession
* session
= it
->second
;
643 if (!session
->CanPool(origin_host
.as_string(), privacy_mode
))
644 return ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN
;
645 request
->set_stream(CreateFromSession(session
));
649 if (HasActiveJob(server_id
)) {
650 active_requests_
[request
] = server_id
;
651 job_requests_map_
[server_id
].insert(request
);
652 return ERR_IO_PENDING
;
655 // TODO(rtenneti): |task_runner_| is used by the Job. Initialize task_runner_
656 // in the constructor after WebRequestActionWithThreadsTest.* tests are fixed.
658 task_runner_
= base::MessageLoop::current()->message_loop_proxy().get();
660 QuicServerInfo
* quic_server_info
= nullptr;
661 if (quic_server_info_factory_
) {
662 bool load_from_disk_cache
= !disable_disk_cache_
;
663 if (http_server_properties_
) {
664 const AlternativeServiceMap
& alternative_service_map
=
665 http_server_properties_
->alternative_service_map();
666 AlternativeServiceMap::const_iterator it
=
667 alternative_service_map
.Peek(server_id
.host_port_pair());
668 if (it
== alternative_service_map
.end() ||
669 it
->second
.alternative_service
.protocol
!= QUIC
) {
670 // If there is no entry for QUIC, consider that as a new server and
671 // don't wait for Cache thread to load the data for that server.
672 load_from_disk_cache
= false;
675 if (load_from_disk_cache
&& CryptoConfigCacheIsEmpty(server_id
)) {
676 quic_server_info
= quic_server_info_factory_
->GetForServer(server_id
);
680 bool server_and_origin_have_same_host
= host_port_pair
.host() == origin_host
;
681 scoped_ptr
<Job
> job(new Job(
682 this, host_resolver_
, host_port_pair
, server_and_origin_have_same_host
,
683 is_https
, WasQuicRecentlyBroken(server_id
), privacy_mode
,
684 method
== "POST" /* is_post */, quic_server_info
, net_log
));
685 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
686 base::Unretained(this), job
.get()));
687 if (rv
== ERR_IO_PENDING
) {
688 active_requests_
[request
] = server_id
;
689 job_requests_map_
[server_id
].insert(request
);
690 active_jobs_
[server_id
].insert(job
.release());
694 it
= active_sessions_
.find(server_id
);
695 DCHECK(it
!= active_sessions_
.end());
696 QuicClientSession
* session
= it
->second
;
697 if (!session
->CanPool(origin_host
.as_string(), privacy_mode
))
698 return ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN
;
699 request
->set_stream(CreateFromSession(session
));
704 void QuicStreamFactory::CreateAuxilaryJob(const QuicServerId server_id
,
705 bool server_and_origin_have_same_host
,
707 const BoundNetLog
& net_log
) {
708 Job
* aux_job
= new Job(this, host_resolver_
, server_id
.host_port_pair(),
709 server_and_origin_have_same_host
, server_id
.is_https(),
710 WasQuicRecentlyBroken(server_id
),
711 server_id
.privacy_mode(), is_post
, nullptr, net_log
);
712 active_jobs_
[server_id
].insert(aux_job
);
713 task_runner_
->PostTask(FROM_HERE
,
714 base::Bind(&QuicStreamFactory::Job::RunAuxilaryJob
,
715 aux_job
->GetWeakPtr()));
718 bool QuicStreamFactory::OnResolution(
719 const QuicServerId
& server_id
,
720 const AddressList
& address_list
) {
721 DCHECK(!HasActiveSession(server_id
));
722 if (disable_connection_pooling_
) {
725 for (const IPEndPoint
& address
: address_list
) {
726 const IpAliasKey
ip_alias_key(address
, server_id
.is_https());
727 if (!ContainsKey(ip_aliases_
, ip_alias_key
))
730 const SessionSet
& sessions
= ip_aliases_
[ip_alias_key
];
731 for (QuicClientSession
* session
: sessions
) {
732 if (!session
->CanPool(server_id
.host(), server_id
.privacy_mode()))
734 active_sessions_
[server_id
] = session
;
735 session_aliases_
[session
].insert(server_id
);
742 void QuicStreamFactory::OnJobComplete(Job
* job
, int rv
) {
743 QuicServerId server_id
= job
->server_id();
745 JobSet
* jobs
= &(active_jobs_
[server_id
]);
746 if (jobs
->size() > 1) {
747 // If there is another pending job, then we can delete this job and let
748 // the other job handle the request.
757 if (!always_require_handshake_confirmation_
)
758 set_require_confirmation(false);
760 // Create all the streams, but do not notify them yet.
761 SessionMap::iterator session_it
= active_sessions_
.find(server_id
);
762 for (RequestSet::iterator request_it
= job_requests_map_
[server_id
].begin();
763 request_it
!= job_requests_map_
[server_id
].end();) {
764 DCHECK(session_it
!= active_sessions_
.end());
765 QuicClientSession
* session
= session_it
->second
;
766 QuicStreamRequest
* request
= *request_it
;
767 if (!session
->CanPool(request
->origin_host(), request
->privacy_mode())) {
768 RequestSet::iterator old_request_it
= request_it
;
770 // Remove request from containers so that OnRequestComplete() is not
771 // called later again on the same request.
772 job_requests_map_
[server_id
].erase(old_request_it
);
773 active_requests_
.erase(request
);
774 // Notify request of certificate error.
775 request
->OnRequestComplete(ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN
);
778 request
->set_stream(CreateFromSession(session
));
783 while (!job_requests_map_
[server_id
].empty()) {
784 RequestSet::iterator it
= job_requests_map_
[server_id
].begin();
785 QuicStreamRequest
* request
= *it
;
786 job_requests_map_
[server_id
].erase(it
);
787 active_requests_
.erase(request
);
788 // Even though we're invoking callbacks here, we don't need to worry
789 // about |this| being deleted, because the factory is owned by the
790 // profile which can not be deleted via callbacks.
791 request
->OnRequestComplete(rv
);
794 for (Job
* other_job
: active_jobs_
[server_id
]) {
795 if (other_job
!= job
)
799 STLDeleteElements(&(active_jobs_
[server_id
]));
800 active_jobs_
.erase(server_id
);
801 job_requests_map_
.erase(server_id
);
804 scoped_ptr
<QuicHttpStream
> QuicStreamFactory::CreateFromSession(
805 QuicClientSession
* session
) {
806 return scoped_ptr
<QuicHttpStream
>(new QuicHttpStream(session
->GetWeakPtr()));
809 bool QuicStreamFactory::IsQuicDisabled(uint16 port
) {
810 return max_number_of_lossy_connections_
> 0 &&
811 number_of_lossy_connections_
[port
] >= max_number_of_lossy_connections_
;
814 bool QuicStreamFactory::OnHandshakeConfirmed(QuicClientSession
* session
,
815 float packet_loss_rate
) {
817 uint16 port
= session
->server_id().port();
818 if (packet_loss_rate
< packet_loss_threshold_
) {
819 number_of_lossy_connections_
[port
] = 0;
823 if (http_server_properties_
) {
824 // We mark it as recently broken, which means that 0-RTT will be disabled
825 // but we'll still race.
826 http_server_properties_
->MarkAlternativeServiceRecentlyBroken(
827 AlternativeService(QUIC
, session
->server_id().host(), port
));
830 // We abandon the connection if packet loss rate is too bad.
831 session
->CloseSessionOnErrorAndNotifyFactoryLater(ERR_ABORTED
,
832 QUIC_BAD_PACKET_LOSS_RATE
);
834 if (IsQuicDisabled(port
))
835 return true; // Exit if Quic is already disabled for this port.
837 if (++number_of_lossy_connections_
[port
] >=
838 max_number_of_lossy_connections_
) {
839 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicStreamFactory.QuicIsDisabled", port
);
842 // Collect data for port 443 for packet loss events.
843 if (port
== 443 && max_number_of_lossy_connections_
> 0) {
844 UMA_HISTOGRAM_SPARSE_SLOWLY(
845 base::StringPrintf("Net.QuicStreamFactory.BadPacketLossEvents%d",
846 max_number_of_lossy_connections_
),
847 std::min(number_of_lossy_connections_
[port
],
848 max_number_of_lossy_connections_
));
853 void QuicStreamFactory::OnIdleSession(QuicClientSession
* session
) {
856 void QuicStreamFactory::OnSessionGoingAway(QuicClientSession
* session
) {
857 const AliasSet
& aliases
= session_aliases_
[session
];
858 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
860 DCHECK(active_sessions_
.count(*it
));
861 DCHECK_EQ(session
, active_sessions_
[*it
]);
862 // Track sessions which have recently gone away so that we can disable
864 if (session
->goaway_received()) {
865 gone_away_aliases_
.insert(*it
);
868 active_sessions_
.erase(*it
);
869 ProcessGoingAwaySession(session
, *it
, true);
871 ProcessGoingAwaySession(session
, all_sessions_
[session
], false);
872 if (!aliases
.empty()) {
873 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
874 aliases
.begin()->is_https());
875 ip_aliases_
[ip_alias_key
].erase(session
);
876 if (ip_aliases_
[ip_alias_key
].empty()) {
877 ip_aliases_
.erase(ip_alias_key
);
880 session_aliases_
.erase(session
);
883 void QuicStreamFactory::OnSessionClosed(QuicClientSession
* session
) {
884 DCHECK_EQ(0u, session
->GetNumOpenStreams());
885 OnSessionGoingAway(session
);
887 all_sessions_
.erase(session
);
890 void QuicStreamFactory::OnSessionConnectTimeout(
891 QuicClientSession
* session
) {
892 const AliasSet
& aliases
= session_aliases_
[session
];
893 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
895 DCHECK(active_sessions_
.count(*it
));
896 DCHECK_EQ(session
, active_sessions_
[*it
]);
897 active_sessions_
.erase(*it
);
900 if (aliases
.empty()) {
904 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
905 aliases
.begin()->is_https());
906 ip_aliases_
[ip_alias_key
].erase(session
);
907 if (ip_aliases_
[ip_alias_key
].empty()) {
908 ip_aliases_
.erase(ip_alias_key
);
910 QuicServerId server_id
= *aliases
.begin();
911 session_aliases_
.erase(session
);
912 Job
* job
= new Job(this, host_resolver_
, session
, server_id
);
913 active_jobs_
[server_id
].insert(job
);
914 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
915 base::Unretained(this), job
));
916 DCHECK_EQ(ERR_IO_PENDING
, rv
);
919 void QuicStreamFactory::CancelRequest(QuicStreamRequest
* request
) {
920 DCHECK(ContainsKey(active_requests_
, request
));
921 QuicServerId server_id
= active_requests_
[request
];
922 job_requests_map_
[server_id
].erase(request
);
923 active_requests_
.erase(request
);
926 void QuicStreamFactory::CloseAllSessions(int error
) {
927 while (!active_sessions_
.empty()) {
928 size_t initial_size
= active_sessions_
.size();
929 active_sessions_
.begin()->second
->CloseSessionOnError(error
,
930 QUIC_INTERNAL_ERROR
);
931 DCHECK_NE(initial_size
, active_sessions_
.size());
933 while (!all_sessions_
.empty()) {
934 size_t initial_size
= all_sessions_
.size();
935 all_sessions_
.begin()->first
->CloseSessionOnError(error
,
936 QUIC_INTERNAL_ERROR
);
937 DCHECK_NE(initial_size
, all_sessions_
.size());
939 DCHECK(all_sessions_
.empty());
942 scoped_ptr
<base::Value
> QuicStreamFactory::QuicStreamFactoryInfoToValue()
944 scoped_ptr
<base::ListValue
> list(new base::ListValue());
946 for (SessionMap::const_iterator it
= active_sessions_
.begin();
947 it
!= active_sessions_
.end(); ++it
) {
948 const QuicServerId
& server_id
= it
->first
;
949 QuicClientSession
* session
= it
->second
;
950 const AliasSet
& aliases
= session_aliases_
.find(session
)->second
;
951 // Only add a session to the list once.
952 if (server_id
== *aliases
.begin()) {
953 std::set
<HostPortPair
> hosts
;
954 for (AliasSet::const_iterator alias_it
= aliases
.begin();
955 alias_it
!= aliases
.end(); ++alias_it
) {
956 hosts
.insert(alias_it
->host_port_pair());
958 list
->Append(session
->GetInfoAsValue(hosts
));
964 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
965 crypto_config_
.ClearCachedStates();
968 void QuicStreamFactory::OnIPAddressChanged() {
969 CloseAllSessions(ERR_NETWORK_CHANGED
);
970 set_require_confirmation(true);
973 void QuicStreamFactory::OnCertAdded(const X509Certificate
* cert
) {
974 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
977 void QuicStreamFactory::OnCACertChanged(const X509Certificate
* cert
) {
978 // We should flush the sessions if we removed trust from a
979 // cert, because a previously trusted server may have become
982 // We should not flush the sessions if we added trust to a cert.
984 // Since the OnCACertChanged method doesn't tell us what
985 // kind of change it is, we have to flush the socket
987 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
990 bool QuicStreamFactory::HasActiveSession(
991 const QuicServerId
& server_id
) const {
992 return ContainsKey(active_sessions_
, server_id
);
995 bool QuicStreamFactory::HasActiveJob(const QuicServerId
& key
) const {
996 return ContainsKey(active_jobs_
, key
);
999 int QuicStreamFactory::CreateSession(const QuicServerId
& server_id
,
1000 scoped_ptr
<QuicServerInfo
> server_info
,
1001 const AddressList
& address_list
,
1002 base::TimeTicks dns_resolution_end_time
,
1003 const BoundNetLog
& net_log
,
1004 QuicClientSession
** session
) {
1005 bool enable_port_selection
= enable_port_selection_
;
1006 if (enable_port_selection
&&
1007 ContainsKey(gone_away_aliases_
, server_id
)) {
1008 // Disable port selection when the server is going away.
1009 // There is no point in trying to return to the same server, if
1010 // that server is no longer handling requests.
1011 enable_port_selection
= false;
1012 gone_away_aliases_
.erase(server_id
);
1015 QuicConnectionId connection_id
= random_generator_
->RandUint64();
1016 IPEndPoint addr
= *address_list
.begin();
1017 scoped_refptr
<PortSuggester
> port_suggester
=
1018 new PortSuggester(server_id
.host_port_pair(), port_seed_
);
1019 DatagramSocket::BindType bind_type
= enable_port_selection
?
1020 DatagramSocket::RANDOM_BIND
: // Use our callback.
1021 DatagramSocket::DEFAULT_BIND
; // Use OS to randomize.
1022 scoped_ptr
<DatagramClientSocket
> socket(
1023 client_socket_factory_
->CreateDatagramClientSocket(
1025 base::Bind(&PortSuggester::SuggestPort
, port_suggester
),
1026 net_log
.net_log(), net_log
.source()));
1028 if (enable_non_blocking_io_
&&
1029 client_socket_factory_
== ClientSocketFactory::GetDefaultFactory()) {
1031 static_cast<UDPClientSocket
*>(socket
.get())->UseNonBlockingIO();
1035 int rv
= socket
->Connect(addr
);
1038 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET
);
1041 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested",
1042 port_suggester
->call_count());
1043 if (enable_port_selection
) {
1044 DCHECK_LE(1u, port_suggester
->call_count());
1046 DCHECK_EQ(0u, port_suggester
->call_count());
1049 rv
= socket
->SetReceiveBufferSize(socket_receive_buffer_size_
);
1051 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER
);
1054 // Set a buffer large enough to contain the initial CWND's worth of packet
1055 // to work around the problem with CHLO packets being sent out with the
1056 // wrong encryption level, when the send buffer is full.
1057 rv
= socket
->SetSendBufferSize(kMaxPacketSize
* 20);
1059 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER
);
1063 socket
->GetLocalAddress(&local_address_
);
1064 if (check_persisted_supports_quic_
&& http_server_properties_
) {
1065 check_persisted_supports_quic_
= false;
1066 IPAddressNumber last_address
;
1067 if (http_server_properties_
->GetSupportsQuic(&last_address
) &&
1068 last_address
== local_address_
.address()) {
1069 require_confirmation_
= false;
1073 DefaultPacketWriterFactory
packet_writer_factory(socket
.get());
1075 if (!helper_
.get()) {
1076 helper_
.reset(new QuicConnectionHelper(
1077 base::MessageLoop::current()->message_loop_proxy().get(),
1078 clock_
.get(), random_generator_
));
1081 QuicConnection
* connection
= new QuicConnection(
1082 connection_id
, addr
, helper_
.get(), packet_writer_factory
,
1083 true /* owns_writer */, Perspective::IS_CLIENT
, server_id
.is_https(),
1084 supported_versions_
);
1085 connection
->set_max_packet_length(max_packet_length_
);
1087 InitializeCachedStateInCryptoConfig(server_id
, server_info
);
1089 QuicConfig config
= config_
;
1090 config
.SetSocketReceiveBufferToSend(socket_receive_buffer_size_
);
1091 config
.set_max_undecryptable_packets(kMaxUndecryptablePackets
);
1092 config
.SetInitialSessionFlowControlWindowToSend(
1093 kQuicSessionMaxRecvWindowSize
);
1094 config
.SetInitialStreamFlowControlWindowToSend(kQuicStreamMaxRecvWindowSize
);
1095 int64 srtt
= GetServerNetworkStatsSmoothedRttInMicroseconds(server_id
);
1097 config
.SetInitialRoundTripTimeUsToSend(static_cast<uint32
>(srtt
));
1098 config
.SetBytesForConnectionIdToSend(0);
1100 if (quic_server_info_factory_
&& !server_info
) {
1101 // Start the disk cache loading so that we can persist the newer QUIC server
1102 // information and/or inform the disk cache that we have reused
1104 server_info
.reset(quic_server_info_factory_
->GetForServer(server_id
));
1105 server_info
->Start();
1108 *session
= new QuicClientSession(
1109 connection
, socket
.Pass(), this, transport_security_state_
,
1110 server_info
.Pass(), config
, network_connection_
.GetDescription(),
1111 dns_resolution_end_time
,
1112 base::MessageLoop::current()->message_loop_proxy().get(),
1115 all_sessions_
[*session
] = server_id
; // owning pointer
1117 (*session
)->InitializeSession(server_id
, &crypto_config_
,
1118 quic_crypto_client_stream_factory_
);
1119 bool closed_during_initialize
=
1120 !ContainsKey(all_sessions_
, *session
) ||
1121 !(*session
)->connection()->connected();
1122 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedDuringInitializeSession",
1123 closed_during_initialize
);
1124 if (closed_during_initialize
) {
1125 DLOG(DFATAL
) << "Session closed during initialize";
1127 return ERR_CONNECTION_CLOSED
;
1132 void QuicStreamFactory::ActivateSession(
1133 const QuicServerId
& server_id
,
1134 QuicClientSession
* session
) {
1135 DCHECK(!HasActiveSession(server_id
));
1136 UMA_HISTOGRAM_COUNTS("Net.QuicActiveSessions", active_sessions_
.size());
1137 active_sessions_
[server_id
] = session
;
1138 session_aliases_
[session
].insert(server_id
);
1139 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
1140 server_id
.is_https());
1141 DCHECK(!ContainsKey(ip_aliases_
[ip_alias_key
], session
));
1142 ip_aliases_
[ip_alias_key
].insert(session
);
1145 int64
QuicStreamFactory::GetServerNetworkStatsSmoothedRttInMicroseconds(
1146 const QuicServerId
& server_id
) const {
1147 if (!http_server_properties_
)
1149 const ServerNetworkStats
* stats
=
1150 http_server_properties_
->GetServerNetworkStats(
1151 server_id
.host_port_pair());
1152 if (stats
== nullptr)
1154 return stats
->srtt
.InMicroseconds();
1157 bool QuicStreamFactory::WasQuicRecentlyBroken(
1158 const QuicServerId
& server_id
) const {
1159 if (!http_server_properties_
)
1161 const AlternativeService
alternative_service(QUIC
,
1162 server_id
.host_port_pair());
1163 return http_server_properties_
->WasAlternativeServiceRecentlyBroken(
1164 alternative_service
);
1167 bool QuicStreamFactory::CryptoConfigCacheIsEmpty(
1168 const QuicServerId
& server_id
) {
1169 QuicCryptoClientConfig::CachedState
* cached
=
1170 crypto_config_
.LookupOrCreate(server_id
);
1171 return cached
->IsEmpty();
1174 void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
1175 const QuicServerId
& server_id
,
1176 const scoped_ptr
<QuicServerInfo
>& server_info
) {
1177 // |server_info| will be NULL, if a non-empty server config already exists in
1178 // the memory cache. This is a minor optimization to avoid LookupOrCreate.
1182 QuicCryptoClientConfig::CachedState
* cached
=
1183 crypto_config_
.LookupOrCreate(server_id
);
1184 if (!cached
->IsEmpty())
1187 if (http_server_properties_
) {
1188 if (quic_supported_servers_at_startup_
.empty()) {
1189 for (const std::pair
<const HostPortPair
, AlternativeServiceInfo
>&
1190 key_value
: http_server_properties_
->alternative_service_map()) {
1191 if (key_value
.second
.alternative_service
.protocol
== QUIC
) {
1192 quic_supported_servers_at_startup_
.insert(key_value
.first
);
1197 // TODO(rtenneti): Delete the following histogram after collecting stats.
1198 // If the AlternativeServiceMap contained an entry for this host, check if
1199 // the disk cache contained an entry for it.
1200 if (ContainsKey(quic_supported_servers_at_startup_
,
1201 server_id
.host_port_pair())) {
1202 UMA_HISTOGRAM_BOOLEAN(
1203 "Net.QuicServerInfo.ExpectConfigMissingFromDiskCache",
1204 server_info
->state().server_config
.empty());
1208 if (!cached
->Initialize(server_info
->state().server_config
,
1209 server_info
->state().source_address_token
,
1210 server_info
->state().certs
,
1211 server_info
->state().server_config_sig
,
1215 if (!server_id
.is_https()) {
1216 // Don't check the certificates for insecure QUIC.
1217 cached
->SetProofValid();
1221 void QuicStreamFactory::ProcessGoingAwaySession(
1222 QuicClientSession
* session
,
1223 const QuicServerId
& server_id
,
1224 bool session_was_active
) {
1225 if (!http_server_properties_
)
1228 const QuicConnectionStats
& stats
= session
->connection()->GetStats();
1229 const AlternativeService
alternative_service(QUIC
,
1230 server_id
.host_port_pair());
1231 if (session
->IsCryptoHandshakeConfirmed()) {
1232 http_server_properties_
->ConfirmAlternativeService(alternative_service
);
1233 ServerNetworkStats network_stats
;
1234 network_stats
.srtt
= base::TimeDelta::FromMicroseconds(stats
.srtt_us
);
1235 network_stats
.bandwidth_estimate
= stats
.estimated_bandwidth
;
1236 http_server_properties_
->SetServerNetworkStats(server_id
.host_port_pair(),
1241 UMA_HISTOGRAM_COUNTS("Net.QuicHandshakeNotConfirmedNumPacketsReceived",
1242 stats
.packets_received
);
1244 if (!session_was_active
)
1247 // TODO(rch): In the special case where the session has received no
1248 // packets from the peer, we should consider blacklisting this
1249 // differently so that we still race TCP but we don't consider the
1250 // session connected until the handshake has been confirmed.
1251 HistogramBrokenAlternateProtocolLocation(
1252 BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY
);
1254 // Since the session was active, there's no longer an
1255 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the TCP
1256 // job also fails. So to avoid not using QUIC when we otherwise could, we mark
1257 // it as recently broken, which means that 0-RTT will be disabled but we'll
1259 http_server_properties_
->MarkAlternativeServiceRecentlyBroken(
1260 alternative_service
);