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
,
150 QuicServerInfo
* server_info
,
151 const BoundNetLog
& net_log
);
153 // Creates a new job to handle the resumption of for connecting an
155 Job(QuicStreamFactory
* factory
,
156 HostResolver
* host_resolver
,
157 QuicClientSession
* session
,
158 QuicServerId server_id
);
162 int Run(const CompletionCallback
& callback
);
166 int DoResolveHostComplete(int rv
);
167 int DoLoadServerInfo();
168 int DoLoadServerInfoComplete(int rv
);
170 int DoResumeConnect();
171 int DoConnectComplete(int rv
);
173 void OnIOComplete(int rv
);
175 void RunAuxilaryJob();
179 void CancelWaitForDataReadyCallback();
181 const QuicServerId
server_id() const { return server_id_
; }
183 base::WeakPtr
<Job
> GetWeakPtr() { return weak_factory_
.GetWeakPtr(); }
189 STATE_RESOLVE_HOST_COMPLETE
,
190 STATE_LOAD_SERVER_INFO
,
191 STATE_LOAD_SERVER_INFO_COMPLETE
,
193 STATE_RESUME_CONNECT
,
194 STATE_CONNECT_COMPLETE
,
198 QuicStreamFactory
* factory_
;
199 SingleRequestHostResolver host_resolver_
;
200 QuicServerId server_id_
;
201 // True if and only if server and origin have the same hostname.
202 bool server_and_origin_have_same_host_
;
204 bool was_alternative_service_recently_broken_
;
205 scoped_ptr
<QuicServerInfo
> server_info_
;
206 bool started_another_job_
;
207 const BoundNetLog net_log_
;
208 QuicClientSession
* session_
;
209 CompletionCallback callback_
;
210 AddressList address_list_
;
211 base::TimeTicks dns_resolution_start_time_
;
212 base::TimeTicks dns_resolution_end_time_
;
213 base::WeakPtrFactory
<Job
> weak_factory_
;
214 DISALLOW_COPY_AND_ASSIGN(Job
);
217 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
218 HostResolver
* host_resolver
,
219 const HostPortPair
& host_port_pair
,
220 bool server_and_origin_have_same_host
,
222 bool was_alternative_service_recently_broken
,
223 PrivacyMode privacy_mode
,
225 QuicServerInfo
* server_info
,
226 const BoundNetLog
& net_log
)
227 : io_state_(STATE_RESOLVE_HOST
),
229 host_resolver_(host_resolver
),
230 server_id_(host_port_pair
, is_https
, privacy_mode
),
231 server_and_origin_have_same_host_(server_and_origin_have_same_host
),
233 was_alternative_service_recently_broken_(
234 was_alternative_service_recently_broken
),
235 server_info_(server_info
),
236 started_another_job_(false),
239 weak_factory_(this) {
242 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
243 HostResolver
* host_resolver
,
244 QuicClientSession
* session
,
245 QuicServerId server_id
)
246 : io_state_(STATE_RESUME_CONNECT
),
248 host_resolver_(host_resolver
), // unused
249 server_id_(server_id
),
250 server_and_origin_have_same_host_(false), // unused
251 is_post_(false), // unused
252 was_alternative_service_recently_broken_(false), // unused
253 started_another_job_(false), // unused
254 net_log_(session
->net_log()), // unused
256 weak_factory_(this) {
259 QuicStreamFactory::Job::~Job() {
260 // If disk cache has a pending WaitForDataReadyCallback, cancel that callback.
262 server_info_
->ResetWaitForDataReadyCallback();
265 int QuicStreamFactory::Job::Run(const CompletionCallback
& callback
) {
267 if (rv
== ERR_IO_PENDING
)
268 callback_
= callback
;
270 return rv
> 0 ? OK
: rv
;
273 int QuicStreamFactory::Job::DoLoop(int rv
) {
275 IoState state
= io_state_
;
276 io_state_
= STATE_NONE
;
278 case STATE_RESOLVE_HOST
:
280 rv
= DoResolveHost();
282 case STATE_RESOLVE_HOST_COMPLETE
:
283 rv
= DoResolveHostComplete(rv
);
285 case STATE_LOAD_SERVER_INFO
:
287 rv
= DoLoadServerInfo();
289 case STATE_LOAD_SERVER_INFO_COMPLETE
:
290 rv
= DoLoadServerInfoComplete(rv
);
296 case STATE_RESUME_CONNECT
:
298 rv
= DoResumeConnect();
300 case STATE_CONNECT_COMPLETE
:
301 rv
= DoConnectComplete(rv
);
304 NOTREACHED() << "io_state_: " << io_state_
;
307 } while (io_state_
!= STATE_NONE
&& rv
!= ERR_IO_PENDING
);
311 void QuicStreamFactory::Job::OnIOComplete(int rv
) {
313 if (rv
!= ERR_IO_PENDING
&& !callback_
.is_null()) {
318 void QuicStreamFactory::Job::RunAuxilaryJob() {
319 int rv
= Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
320 base::Unretained(factory_
), this));
321 if (rv
!= ERR_IO_PENDING
)
322 factory_
->OnJobComplete(this, rv
);
325 void QuicStreamFactory::Job::Cancel() {
328 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_CANCELLED
);
331 void QuicStreamFactory::Job::CancelWaitForDataReadyCallback() {
332 // If we are waiting for WaitForDataReadyCallback, then cancel the callback.
333 if (io_state_
!= STATE_LOAD_SERVER_INFO_COMPLETE
)
335 server_info_
->CancelWaitForDataReadyCallback();
339 int QuicStreamFactory::Job::DoResolveHost() {
340 // Start loading the data now, and wait for it after we resolve the host.
342 server_info_
->Start();
345 io_state_
= STATE_RESOLVE_HOST_COMPLETE
;
346 dns_resolution_start_time_
= base::TimeTicks::Now();
347 return host_resolver_
.Resolve(
348 HostResolver::RequestInfo(server_id_
.host_port_pair()), DEFAULT_PRIORITY
,
350 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()),
354 int QuicStreamFactory::Job::DoResolveHostComplete(int rv
) {
355 dns_resolution_end_time_
= base::TimeTicks::Now();
356 UMA_HISTOGRAM_TIMES("Net.QuicSession.HostResolutionTime",
357 dns_resolution_end_time_
- dns_resolution_start_time_
);
361 DCHECK(!factory_
->HasActiveSession(server_id_
));
363 // Inform the factory of this resolution, which will set up
364 // a session alias, if possible.
365 if (factory_
->OnResolution(server_id_
, address_list_
)) {
370 io_state_
= STATE_LOAD_SERVER_INFO
;
372 io_state_
= STATE_CONNECT
;
376 int QuicStreamFactory::Job::DoLoadServerInfo() {
377 io_state_
= STATE_LOAD_SERVER_INFO_COMPLETE
;
379 DCHECK(server_info_
);
381 // To mitigate the effects of disk cache taking too long to load QUIC server
382 // information, set up a timer to cancel WaitForDataReady's callback.
383 if (factory_
->load_server_info_timeout_srtt_multiplier_
> 0) {
384 int64 load_server_info_timeout_ms
=
385 (factory_
->load_server_info_timeout_srtt_multiplier_
*
386 factory_
->GetServerNetworkStatsSmoothedRttInMicroseconds(server_id_
)) /
388 if (load_server_info_timeout_ms
> 0) {
389 factory_
->task_runner_
->PostDelayedTask(
391 base::Bind(&QuicStreamFactory::Job::CancelWaitForDataReadyCallback
,
393 base::TimeDelta::FromMilliseconds(load_server_info_timeout_ms
));
397 int rv
= server_info_
->WaitForDataReady(
398 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
399 if (rv
== ERR_IO_PENDING
&& factory_
->enable_connection_racing()) {
400 // If we are waiting to load server config from the disk cache, then start
402 started_another_job_
= true;
403 factory_
->CreateAuxilaryJob(server_id_
, server_and_origin_have_same_host_
,
409 int QuicStreamFactory::Job::DoLoadServerInfoComplete(int rv
) {
410 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheWaitForDataReadyTime",
411 base::TimeTicks::Now() - dns_resolution_end_time_
);
414 server_info_
.reset();
416 if (started_another_job_
&&
417 (!server_info_
|| server_info_
->state().server_config
.empty() ||
418 !factory_
->CryptoConfigCacheIsEmpty(server_id_
))) {
419 // If we have started another job and if we didn't load the server config
420 // from the disk cache or if we have received a new server config from the
421 // server, then cancel the current job.
422 io_state_
= STATE_NONE
;
423 return ERR_CONNECTION_CLOSED
;
426 io_state_
= STATE_CONNECT
;
430 int QuicStreamFactory::Job::DoConnect() {
431 io_state_
= STATE_CONNECT_COMPLETE
;
434 factory_
->CreateSession(server_id_
, server_info_
.Pass(), address_list_
,
435 dns_resolution_end_time_
, net_log_
, &session_
);
437 DCHECK(rv
!= ERR_IO_PENDING
);
442 if (!session_
->connection()->connected()) {
443 return ERR_CONNECTION_CLOSED
;
446 session_
->StartReading();
447 if (!session_
->connection()->connected()) {
448 return ERR_QUIC_PROTOCOL_ERROR
;
450 bool require_confirmation
= factory_
->require_confirmation() ||
451 !server_and_origin_have_same_host_
|| is_post_
||
452 was_alternative_service_recently_broken_
;
454 rv
= session_
->CryptoConnect(
455 require_confirmation
,
456 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
460 int QuicStreamFactory::Job::DoResumeConnect() {
461 io_state_
= STATE_CONNECT_COMPLETE
;
463 int rv
= session_
->ResumeCryptoConnect(
464 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
469 int QuicStreamFactory::Job::DoConnectComplete(int rv
) {
473 DCHECK(!factory_
->HasActiveSession(server_id_
));
474 // There may well now be an active session for this IP. If so, use the
475 // existing session instead.
476 AddressList
address(session_
->connection()->peer_address());
477 if (factory_
->OnResolution(server_id_
, address
)) {
478 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_IP_POOLED
);
483 factory_
->ActivateSession(server_id_
, session_
);
488 QuicStreamRequest::QuicStreamRequest(QuicStreamFactory
* factory
)
489 : factory_(factory
) {}
491 QuicStreamRequest::~QuicStreamRequest() {
492 if (factory_
&& !callback_
.is_null())
493 factory_
->CancelRequest(this);
496 int QuicStreamRequest::Request(const HostPortPair
& host_port_pair
,
498 PrivacyMode privacy_mode
,
499 base::StringPiece origin_host
,
500 base::StringPiece method
,
501 const BoundNetLog
& net_log
,
502 const CompletionCallback
& callback
) {
504 DCHECK(callback_
.is_null());
506 origin_host_
= origin_host
.as_string();
507 privacy_mode_
= privacy_mode
;
508 int rv
= factory_
->Create(host_port_pair
, is_https
, privacy_mode
, origin_host
,
509 method
, net_log
, this);
510 if (rv
== ERR_IO_PENDING
) {
511 host_port_pair_
= host_port_pair
;
513 callback_
= callback
;
522 void QuicStreamRequest::set_stream(scoped_ptr
<QuicHttpStream
> stream
) {
524 stream_
= stream
.Pass();
527 void QuicStreamRequest::OnRequestComplete(int rv
) {
532 scoped_ptr
<QuicHttpStream
> QuicStreamRequest::ReleaseStream() {
534 return stream_
.Pass();
537 QuicStreamFactory::QuicStreamFactory(
538 HostResolver
* host_resolver
,
539 ClientSocketFactory
* client_socket_factory
,
540 base::WeakPtr
<HttpServerProperties
> http_server_properties
,
541 CertVerifier
* cert_verifier
,
542 ChannelIDService
* channel_id_service
,
543 TransportSecurityState
* transport_security_state
,
544 QuicCryptoClientStreamFactory
* quic_crypto_client_stream_factory
,
545 QuicRandom
* random_generator
,
547 size_t max_packet_length
,
548 const std::string
& user_agent_id
,
549 const QuicVersionVector
& supported_versions
,
550 bool enable_port_selection
,
551 bool always_require_handshake_confirmation
,
552 bool disable_connection_pooling
,
553 float load_server_info_timeout_srtt_multiplier
,
554 bool enable_connection_racing
,
555 bool enable_non_blocking_io
,
556 bool disable_disk_cache
,
558 int max_number_of_lossy_connections
,
559 float packet_loss_threshold
,
560 int socket_receive_buffer_size
,
561 const QuicTagVector
& connection_options
)
562 : require_confirmation_(true),
563 host_resolver_(host_resolver
),
564 client_socket_factory_(client_socket_factory
),
565 http_server_properties_(http_server_properties
),
566 transport_security_state_(transport_security_state
),
567 quic_server_info_factory_(nullptr),
568 quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory
),
569 random_generator_(random_generator
),
571 max_packet_length_(max_packet_length
),
572 config_(InitializeQuicConfig(connection_options
)),
573 supported_versions_(supported_versions
),
574 enable_port_selection_(enable_port_selection
),
575 always_require_handshake_confirmation_(
576 always_require_handshake_confirmation
),
577 disable_connection_pooling_(disable_connection_pooling
),
578 load_server_info_timeout_srtt_multiplier_(
579 load_server_info_timeout_srtt_multiplier
),
580 enable_connection_racing_(enable_connection_racing
),
581 enable_non_blocking_io_(enable_non_blocking_io
),
582 disable_disk_cache_(disable_disk_cache
),
583 prefer_aes_(prefer_aes
),
584 max_number_of_lossy_connections_(max_number_of_lossy_connections
),
585 packet_loss_threshold_(packet_loss_threshold
),
586 socket_receive_buffer_size_(socket_receive_buffer_size
),
587 port_seed_(random_generator_
->RandUint64()),
588 check_persisted_supports_quic_(true),
589 task_runner_(nullptr),
590 weak_factory_(this) {
591 DCHECK(transport_security_state_
);
592 crypto_config_
.set_user_agent_id(user_agent_id
);
593 crypto_config_
.AddCanonicalSuffix(".c.youtube.com");
594 crypto_config_
.AddCanonicalSuffix(".googlevideo.com");
595 crypto_config_
.AddCanonicalSuffix(".googleusercontent.com");
596 crypto_config_
.SetProofVerifier(
597 new ProofVerifierChromium(cert_verifier
, transport_security_state
));
598 // TODO(rtenneti): http://crbug.com/487355. Temporary fix for b/20760730 until
599 // channel_id_service is supported in cronet.
600 if (channel_id_service
) {
601 crypto_config_
.SetChannelIDSource(
602 new ChannelIDSourceChromium(channel_id_service
));
605 bool has_aes_hardware_support
= cpu
.has_aesni() && cpu
.has_avx();
606 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.PreferAesGcm",
607 has_aes_hardware_support
);
608 if (has_aes_hardware_support
|| prefer_aes_
)
609 crypto_config_
.PreferAesGcm();
610 if (!IsEcdsaSupported())
611 crypto_config_
.DisableEcdsa();
614 QuicStreamFactory::~QuicStreamFactory() {
615 CloseAllSessions(ERR_ABORTED
);
616 while (!all_sessions_
.empty()) {
617 delete all_sessions_
.begin()->first
;
618 all_sessions_
.erase(all_sessions_
.begin());
620 while (!active_jobs_
.empty()) {
621 const QuicServerId server_id
= active_jobs_
.begin()->first
;
622 STLDeleteElements(&(active_jobs_
[server_id
]));
623 active_jobs_
.erase(server_id
);
627 void QuicStreamFactory::set_require_confirmation(bool require_confirmation
) {
628 require_confirmation_
= require_confirmation
;
629 if (http_server_properties_
&& (!(local_address_
== IPEndPoint()))) {
630 http_server_properties_
->SetSupportsQuic(!require_confirmation
,
631 local_address_
.address());
635 int QuicStreamFactory::Create(const HostPortPair
& host_port_pair
,
637 PrivacyMode privacy_mode
,
638 base::StringPiece origin_host
,
639 base::StringPiece method
,
640 const BoundNetLog
& net_log
,
641 QuicStreamRequest
* request
) {
642 QuicServerId
server_id(host_port_pair
, is_https
, privacy_mode
);
643 SessionMap::iterator it
= active_sessions_
.find(server_id
);
644 if (it
!= active_sessions_
.end()) {
645 QuicClientSession
* session
= it
->second
;
646 if (!session
->CanPool(origin_host
.as_string(), privacy_mode
))
647 return ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN
;
648 request
->set_stream(CreateFromSession(session
));
652 if (HasActiveJob(server_id
)) {
653 active_requests_
[request
] = server_id
;
654 job_requests_map_
[server_id
].insert(request
);
655 return ERR_IO_PENDING
;
658 // TODO(rtenneti): |task_runner_| is used by the Job. Initialize task_runner_
659 // in the constructor after WebRequestActionWithThreadsTest.* tests are fixed.
661 task_runner_
= base::ThreadTaskRunnerHandle::Get().get();
663 QuicServerInfo
* quic_server_info
= nullptr;
664 if (quic_server_info_factory_
) {
665 bool load_from_disk_cache
= !disable_disk_cache_
;
666 if (http_server_properties_
) {
667 const AlternativeServiceMap
& alternative_service_map
=
668 http_server_properties_
->alternative_service_map();
669 AlternativeServiceMap::const_iterator it
=
670 alternative_service_map
.Peek(server_id
.host_port_pair());
671 if (it
== alternative_service_map
.end() ||
672 it
->second
.alternative_service
.protocol
!= QUIC
) {
673 // If there is no entry for QUIC, consider that as a new server and
674 // don't wait for Cache thread to load the data for that server.
675 load_from_disk_cache
= false;
678 if (load_from_disk_cache
&& CryptoConfigCacheIsEmpty(server_id
)) {
679 quic_server_info
= quic_server_info_factory_
->GetForServer(server_id
);
683 bool server_and_origin_have_same_host
= host_port_pair
.host() == origin_host
;
684 scoped_ptr
<Job
> job(new Job(
685 this, host_resolver_
, host_port_pair
, server_and_origin_have_same_host
,
686 is_https
, WasQuicRecentlyBroken(server_id
), privacy_mode
,
687 method
== "POST" /* is_post */, quic_server_info
, net_log
));
688 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
689 base::Unretained(this), job
.get()));
690 if (rv
== ERR_IO_PENDING
) {
691 active_requests_
[request
] = server_id
;
692 job_requests_map_
[server_id
].insert(request
);
693 active_jobs_
[server_id
].insert(job
.release());
697 it
= active_sessions_
.find(server_id
);
698 DCHECK(it
!= active_sessions_
.end());
699 QuicClientSession
* session
= it
->second
;
700 if (!session
->CanPool(origin_host
.as_string(), privacy_mode
))
701 return ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN
;
702 request
->set_stream(CreateFromSession(session
));
707 void QuicStreamFactory::CreateAuxilaryJob(const QuicServerId server_id
,
708 bool server_and_origin_have_same_host
,
710 const BoundNetLog
& net_log
) {
711 Job
* aux_job
= new Job(this, host_resolver_
, server_id
.host_port_pair(),
712 server_and_origin_have_same_host
, server_id
.is_https(),
713 WasQuicRecentlyBroken(server_id
),
714 server_id
.privacy_mode(), is_post
, nullptr, net_log
);
715 active_jobs_
[server_id
].insert(aux_job
);
716 task_runner_
->PostTask(FROM_HERE
,
717 base::Bind(&QuicStreamFactory::Job::RunAuxilaryJob
,
718 aux_job
->GetWeakPtr()));
721 bool QuicStreamFactory::OnResolution(
722 const QuicServerId
& server_id
,
723 const AddressList
& address_list
) {
724 DCHECK(!HasActiveSession(server_id
));
725 if (disable_connection_pooling_
) {
728 for (const IPEndPoint
& address
: address_list
) {
729 const IpAliasKey
ip_alias_key(address
, server_id
.is_https());
730 if (!ContainsKey(ip_aliases_
, ip_alias_key
))
733 const SessionSet
& sessions
= ip_aliases_
[ip_alias_key
];
734 for (QuicClientSession
* session
: sessions
) {
735 if (!session
->CanPool(server_id
.host(), server_id
.privacy_mode()))
737 active_sessions_
[server_id
] = session
;
738 session_aliases_
[session
].insert(server_id
);
745 void QuicStreamFactory::OnJobComplete(Job
* job
, int rv
) {
746 QuicServerId server_id
= job
->server_id();
748 JobSet
* jobs
= &(active_jobs_
[server_id
]);
749 if (jobs
->size() > 1) {
750 // If there is another pending job, then we can delete this job and let
751 // the other job handle the request.
760 if (!always_require_handshake_confirmation_
)
761 set_require_confirmation(false);
763 // Create all the streams, but do not notify them yet.
764 SessionMap::iterator session_it
= active_sessions_
.find(server_id
);
765 for (RequestSet::iterator request_it
= job_requests_map_
[server_id
].begin();
766 request_it
!= job_requests_map_
[server_id
].end();) {
767 DCHECK(session_it
!= active_sessions_
.end());
768 QuicClientSession
* session
= session_it
->second
;
769 QuicStreamRequest
* request
= *request_it
;
770 if (!session
->CanPool(request
->origin_host(), request
->privacy_mode())) {
771 RequestSet::iterator old_request_it
= request_it
;
773 // Remove request from containers so that OnRequestComplete() is not
774 // called later again on the same request.
775 job_requests_map_
[server_id
].erase(old_request_it
);
776 active_requests_
.erase(request
);
777 // Notify request of certificate error.
778 request
->OnRequestComplete(ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN
);
781 request
->set_stream(CreateFromSession(session
));
786 while (!job_requests_map_
[server_id
].empty()) {
787 RequestSet::iterator it
= job_requests_map_
[server_id
].begin();
788 QuicStreamRequest
* request
= *it
;
789 job_requests_map_
[server_id
].erase(it
);
790 active_requests_
.erase(request
);
791 // Even though we're invoking callbacks here, we don't need to worry
792 // about |this| being deleted, because the factory is owned by the
793 // profile which can not be deleted via callbacks.
794 request
->OnRequestComplete(rv
);
797 for (Job
* other_job
: active_jobs_
[server_id
]) {
798 if (other_job
!= job
)
802 STLDeleteElements(&(active_jobs_
[server_id
]));
803 active_jobs_
.erase(server_id
);
804 job_requests_map_
.erase(server_id
);
807 scoped_ptr
<QuicHttpStream
> QuicStreamFactory::CreateFromSession(
808 QuicClientSession
* session
) {
809 return scoped_ptr
<QuicHttpStream
>(new QuicHttpStream(session
->GetWeakPtr()));
812 bool QuicStreamFactory::IsQuicDisabled(uint16 port
) {
813 return max_number_of_lossy_connections_
> 0 &&
814 number_of_lossy_connections_
[port
] >= max_number_of_lossy_connections_
;
817 bool QuicStreamFactory::OnHandshakeConfirmed(QuicClientSession
* session
,
818 float packet_loss_rate
) {
820 uint16 port
= session
->server_id().port();
821 if (packet_loss_rate
< packet_loss_threshold_
) {
822 number_of_lossy_connections_
[port
] = 0;
826 if (http_server_properties_
) {
827 // We mark it as recently broken, which means that 0-RTT will be disabled
828 // but we'll still race.
829 http_server_properties_
->MarkAlternativeServiceRecentlyBroken(
830 AlternativeService(QUIC
, session
->server_id().host(), port
));
833 // We abandon the connection if packet loss rate is too bad.
834 session
->CloseSessionOnErrorAndNotifyFactoryLater(ERR_ABORTED
,
835 QUIC_BAD_PACKET_LOSS_RATE
);
837 if (IsQuicDisabled(port
))
838 return true; // Exit if Quic is already disabled for this port.
840 if (++number_of_lossy_connections_
[port
] >=
841 max_number_of_lossy_connections_
) {
842 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicStreamFactory.QuicIsDisabled", port
);
845 // Collect data for port 443 for packet loss events.
846 if (port
== 443 && max_number_of_lossy_connections_
> 0) {
847 UMA_HISTOGRAM_SPARSE_SLOWLY(
848 base::StringPrintf("Net.QuicStreamFactory.BadPacketLossEvents%d",
849 max_number_of_lossy_connections_
),
850 std::min(number_of_lossy_connections_
[port
],
851 max_number_of_lossy_connections_
));
856 void QuicStreamFactory::OnIdleSession(QuicClientSession
* session
) {
859 void QuicStreamFactory::OnSessionGoingAway(QuicClientSession
* session
) {
860 const AliasSet
& aliases
= session_aliases_
[session
];
861 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
863 DCHECK(active_sessions_
.count(*it
));
864 DCHECK_EQ(session
, active_sessions_
[*it
]);
865 // Track sessions which have recently gone away so that we can disable
867 if (session
->goaway_received()) {
868 gone_away_aliases_
.insert(*it
);
871 active_sessions_
.erase(*it
);
872 ProcessGoingAwaySession(session
, *it
, true);
874 ProcessGoingAwaySession(session
, all_sessions_
[session
], false);
875 if (!aliases
.empty()) {
876 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
877 aliases
.begin()->is_https());
878 ip_aliases_
[ip_alias_key
].erase(session
);
879 if (ip_aliases_
[ip_alias_key
].empty()) {
880 ip_aliases_
.erase(ip_alias_key
);
883 session_aliases_
.erase(session
);
886 void QuicStreamFactory::OnSessionClosed(QuicClientSession
* session
) {
887 DCHECK_EQ(0u, session
->GetNumOpenStreams());
888 OnSessionGoingAway(session
);
890 all_sessions_
.erase(session
);
893 void QuicStreamFactory::OnSessionConnectTimeout(
894 QuicClientSession
* session
) {
895 const AliasSet
& aliases
= session_aliases_
[session
];
896 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
898 DCHECK(active_sessions_
.count(*it
));
899 DCHECK_EQ(session
, active_sessions_
[*it
]);
900 active_sessions_
.erase(*it
);
903 if (aliases
.empty()) {
907 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
908 aliases
.begin()->is_https());
909 ip_aliases_
[ip_alias_key
].erase(session
);
910 if (ip_aliases_
[ip_alias_key
].empty()) {
911 ip_aliases_
.erase(ip_alias_key
);
913 QuicServerId server_id
= *aliases
.begin();
914 session_aliases_
.erase(session
);
915 Job
* job
= new Job(this, host_resolver_
, session
, server_id
);
916 active_jobs_
[server_id
].insert(job
);
917 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
918 base::Unretained(this), job
));
919 DCHECK_EQ(ERR_IO_PENDING
, rv
);
922 void QuicStreamFactory::CancelRequest(QuicStreamRequest
* request
) {
923 DCHECK(ContainsKey(active_requests_
, request
));
924 QuicServerId server_id
= active_requests_
[request
];
925 job_requests_map_
[server_id
].erase(request
);
926 active_requests_
.erase(request
);
929 void QuicStreamFactory::CloseAllSessions(int error
) {
930 while (!active_sessions_
.empty()) {
931 size_t initial_size
= active_sessions_
.size();
932 active_sessions_
.begin()->second
->CloseSessionOnError(error
,
933 QUIC_INTERNAL_ERROR
);
934 DCHECK_NE(initial_size
, active_sessions_
.size());
936 while (!all_sessions_
.empty()) {
937 size_t initial_size
= all_sessions_
.size();
938 all_sessions_
.begin()->first
->CloseSessionOnError(error
,
939 QUIC_INTERNAL_ERROR
);
940 DCHECK_NE(initial_size
, all_sessions_
.size());
942 DCHECK(all_sessions_
.empty());
945 scoped_ptr
<base::Value
> QuicStreamFactory::QuicStreamFactoryInfoToValue()
947 scoped_ptr
<base::ListValue
> list(new base::ListValue());
949 for (SessionMap::const_iterator it
= active_sessions_
.begin();
950 it
!= active_sessions_
.end(); ++it
) {
951 const QuicServerId
& server_id
= it
->first
;
952 QuicClientSession
* session
= it
->second
;
953 const AliasSet
& aliases
= session_aliases_
.find(session
)->second
;
954 // Only add a session to the list once.
955 if (server_id
== *aliases
.begin()) {
956 std::set
<HostPortPair
> hosts
;
957 for (AliasSet::const_iterator alias_it
= aliases
.begin();
958 alias_it
!= aliases
.end(); ++alias_it
) {
959 hosts
.insert(alias_it
->host_port_pair());
961 list
->Append(session
->GetInfoAsValue(hosts
));
967 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
968 crypto_config_
.ClearCachedStates();
971 void QuicStreamFactory::OnIPAddressChanged() {
972 CloseAllSessions(ERR_NETWORK_CHANGED
);
973 set_require_confirmation(true);
976 void QuicStreamFactory::OnCertAdded(const X509Certificate
* cert
) {
977 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
980 void QuicStreamFactory::OnCACertChanged(const X509Certificate
* cert
) {
981 // We should flush the sessions if we removed trust from a
982 // cert, because a previously trusted server may have become
985 // We should not flush the sessions if we added trust to a cert.
987 // Since the OnCACertChanged method doesn't tell us what
988 // kind of change it is, we have to flush the socket
990 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
993 bool QuicStreamFactory::HasActiveSession(
994 const QuicServerId
& server_id
) const {
995 return ContainsKey(active_sessions_
, server_id
);
998 bool QuicStreamFactory::HasActiveJob(const QuicServerId
& key
) const {
999 return ContainsKey(active_jobs_
, key
);
1002 int QuicStreamFactory::CreateSession(const QuicServerId
& server_id
,
1003 scoped_ptr
<QuicServerInfo
> server_info
,
1004 const AddressList
& address_list
,
1005 base::TimeTicks dns_resolution_end_time
,
1006 const BoundNetLog
& net_log
,
1007 QuicClientSession
** session
) {
1008 bool enable_port_selection
= enable_port_selection_
;
1009 if (enable_port_selection
&&
1010 ContainsKey(gone_away_aliases_
, server_id
)) {
1011 // Disable port selection when the server is going away.
1012 // There is no point in trying to return to the same server, if
1013 // that server is no longer handling requests.
1014 enable_port_selection
= false;
1015 gone_away_aliases_
.erase(server_id
);
1018 QuicConnectionId connection_id
= random_generator_
->RandUint64();
1019 IPEndPoint addr
= *address_list
.begin();
1020 scoped_refptr
<PortSuggester
> port_suggester
=
1021 new PortSuggester(server_id
.host_port_pair(), port_seed_
);
1022 DatagramSocket::BindType bind_type
= enable_port_selection
?
1023 DatagramSocket::RANDOM_BIND
: // Use our callback.
1024 DatagramSocket::DEFAULT_BIND
; // Use OS to randomize.
1025 scoped_ptr
<DatagramClientSocket
> socket(
1026 client_socket_factory_
->CreateDatagramClientSocket(
1028 base::Bind(&PortSuggester::SuggestPort
, port_suggester
),
1029 net_log
.net_log(), net_log
.source()));
1031 if (enable_non_blocking_io_
&&
1032 client_socket_factory_
== ClientSocketFactory::GetDefaultFactory()) {
1034 static_cast<UDPClientSocket
*>(socket
.get())->UseNonBlockingIO();
1038 int rv
= socket
->Connect(addr
);
1041 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET
);
1044 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested",
1045 port_suggester
->call_count());
1046 if (enable_port_selection
) {
1047 DCHECK_LE(1u, port_suggester
->call_count());
1049 DCHECK_EQ(0u, port_suggester
->call_count());
1052 rv
= socket
->SetReceiveBufferSize(socket_receive_buffer_size_
);
1054 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER
);
1057 // Set a buffer large enough to contain the initial CWND's worth of packet
1058 // to work around the problem with CHLO packets being sent out with the
1059 // wrong encryption level, when the send buffer is full.
1060 rv
= socket
->SetSendBufferSize(kMaxPacketSize
* 20);
1062 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER
);
1066 socket
->GetLocalAddress(&local_address_
);
1067 if (check_persisted_supports_quic_
&& http_server_properties_
) {
1068 check_persisted_supports_quic_
= false;
1069 IPAddressNumber last_address
;
1070 if (http_server_properties_
->GetSupportsQuic(&last_address
) &&
1071 last_address
== local_address_
.address()) {
1072 require_confirmation_
= false;
1076 DefaultPacketWriterFactory
packet_writer_factory(socket
.get());
1078 if (!helper_
.get()) {
1080 new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(),
1081 clock_
.get(), random_generator_
));
1084 QuicConnection
* connection
= new QuicConnection(
1085 connection_id
, addr
, helper_
.get(), packet_writer_factory
,
1086 true /* owns_writer */, Perspective::IS_CLIENT
, server_id
.is_https(),
1087 supported_versions_
);
1088 connection
->set_max_packet_length(max_packet_length_
);
1090 InitializeCachedStateInCryptoConfig(server_id
, server_info
);
1092 QuicConfig config
= config_
;
1093 config
.SetSocketReceiveBufferToSend(socket_receive_buffer_size_
);
1094 config
.set_max_undecryptable_packets(kMaxUndecryptablePackets
);
1095 config
.SetInitialSessionFlowControlWindowToSend(
1096 kQuicSessionMaxRecvWindowSize
);
1097 config
.SetInitialStreamFlowControlWindowToSend(kQuicStreamMaxRecvWindowSize
);
1098 int64 srtt
= GetServerNetworkStatsSmoothedRttInMicroseconds(server_id
);
1100 config
.SetInitialRoundTripTimeUsToSend(static_cast<uint32
>(srtt
));
1101 config
.SetBytesForConnectionIdToSend(0);
1103 if (quic_server_info_factory_
&& !server_info
) {
1104 // Start the disk cache loading so that we can persist the newer QUIC server
1105 // information and/or inform the disk cache that we have reused
1107 server_info
.reset(quic_server_info_factory_
->GetForServer(server_id
));
1108 server_info
->Start();
1111 *session
= new QuicClientSession(
1112 connection
, socket
.Pass(), this, quic_crypto_client_stream_factory_
,
1113 transport_security_state_
, server_info
.Pass(), server_id
, config
,
1114 &crypto_config_
, network_connection_
.GetDescription(),
1115 dns_resolution_end_time
, base::ThreadTaskRunnerHandle::Get().get(),
1118 all_sessions_
[*session
] = server_id
; // owning pointer
1120 (*session
)->Initialize();
1121 bool closed_during_initialize
=
1122 !ContainsKey(all_sessions_
, *session
) ||
1123 !(*session
)->connection()->connected();
1124 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedDuringInitializeSession",
1125 closed_during_initialize
);
1126 if (closed_during_initialize
) {
1127 DLOG(DFATAL
) << "Session closed during initialize";
1129 return ERR_CONNECTION_CLOSED
;
1134 void QuicStreamFactory::ActivateSession(
1135 const QuicServerId
& server_id
,
1136 QuicClientSession
* session
) {
1137 DCHECK(!HasActiveSession(server_id
));
1138 UMA_HISTOGRAM_COUNTS("Net.QuicActiveSessions", active_sessions_
.size());
1139 active_sessions_
[server_id
] = session
;
1140 session_aliases_
[session
].insert(server_id
);
1141 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
1142 server_id
.is_https());
1143 DCHECK(!ContainsKey(ip_aliases_
[ip_alias_key
], session
));
1144 ip_aliases_
[ip_alias_key
].insert(session
);
1147 int64
QuicStreamFactory::GetServerNetworkStatsSmoothedRttInMicroseconds(
1148 const QuicServerId
& server_id
) const {
1149 if (!http_server_properties_
)
1151 const ServerNetworkStats
* stats
=
1152 http_server_properties_
->GetServerNetworkStats(
1153 server_id
.host_port_pair());
1154 if (stats
== nullptr)
1156 return stats
->srtt
.InMicroseconds();
1159 bool QuicStreamFactory::WasQuicRecentlyBroken(
1160 const QuicServerId
& server_id
) const {
1161 if (!http_server_properties_
)
1163 const AlternativeService
alternative_service(QUIC
,
1164 server_id
.host_port_pair());
1165 return http_server_properties_
->WasAlternativeServiceRecentlyBroken(
1166 alternative_service
);
1169 bool QuicStreamFactory::CryptoConfigCacheIsEmpty(
1170 const QuicServerId
& server_id
) {
1171 QuicCryptoClientConfig::CachedState
* cached
=
1172 crypto_config_
.LookupOrCreate(server_id
);
1173 return cached
->IsEmpty();
1176 void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
1177 const QuicServerId
& server_id
,
1178 const scoped_ptr
<QuicServerInfo
>& server_info
) {
1179 // |server_info| will be NULL, if a non-empty server config already exists in
1180 // the memory cache. This is a minor optimization to avoid LookupOrCreate.
1184 QuicCryptoClientConfig::CachedState
* cached
=
1185 crypto_config_
.LookupOrCreate(server_id
);
1186 if (!cached
->IsEmpty())
1189 if (http_server_properties_
) {
1190 if (quic_supported_servers_at_startup_
.empty()) {
1191 for (const std::pair
<const HostPortPair
, AlternativeServiceInfo
>&
1192 key_value
: http_server_properties_
->alternative_service_map()) {
1193 if (key_value
.second
.alternative_service
.protocol
== QUIC
) {
1194 quic_supported_servers_at_startup_
.insert(key_value
.first
);
1199 // TODO(rtenneti): Delete the following histogram after collecting stats.
1200 // If the AlternativeServiceMap contained an entry for this host, check if
1201 // the disk cache contained an entry for it.
1202 if (ContainsKey(quic_supported_servers_at_startup_
,
1203 server_id
.host_port_pair())) {
1204 UMA_HISTOGRAM_BOOLEAN(
1205 "Net.QuicServerInfo.ExpectConfigMissingFromDiskCache",
1206 server_info
->state().server_config
.empty());
1210 if (!cached
->Initialize(server_info
->state().server_config
,
1211 server_info
->state().source_address_token
,
1212 server_info
->state().certs
,
1213 server_info
->state().server_config_sig
,
1217 if (!server_id
.is_https()) {
1218 // Don't check the certificates for insecure QUIC.
1219 cached
->SetProofValid();
1223 void QuicStreamFactory::ProcessGoingAwaySession(
1224 QuicClientSession
* session
,
1225 const QuicServerId
& server_id
,
1226 bool session_was_active
) {
1227 if (!http_server_properties_
)
1230 const QuicConnectionStats
& stats
= session
->connection()->GetStats();
1231 const AlternativeService
alternative_service(QUIC
,
1232 server_id
.host_port_pair());
1233 if (session
->IsCryptoHandshakeConfirmed()) {
1234 http_server_properties_
->ConfirmAlternativeService(alternative_service
);
1235 ServerNetworkStats network_stats
;
1236 network_stats
.srtt
= base::TimeDelta::FromMicroseconds(stats
.srtt_us
);
1237 network_stats
.bandwidth_estimate
= stats
.estimated_bandwidth
;
1238 http_server_properties_
->SetServerNetworkStats(server_id
.host_port_pair(),
1243 UMA_HISTOGRAM_COUNTS("Net.QuicHandshakeNotConfirmedNumPacketsReceived",
1244 stats
.packets_received
);
1246 if (!session_was_active
)
1249 // TODO(rch): In the special case where the session has received no
1250 // packets from the peer, we should consider blacklisting this
1251 // differently so that we still race TCP but we don't consider the
1252 // session connected until the handshake has been confirmed.
1253 HistogramBrokenAlternateProtocolLocation(
1254 BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY
);
1256 // Since the session was active, there's no longer an
1257 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the TCP
1258 // job also fails. So to avoid not using QUIC when we otherwise could, we mark
1259 // it as recently broken, which means that 0-RTT will be disabled but we'll
1261 http_server_properties_
->MarkAlternativeServiceRecentlyBroken(
1262 alternative_service
);