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"
10 #include "base/message_loop/message_loop.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/metrics/field_trial.h"
13 #include "base/metrics/histogram.h"
14 #include "base/rand_util.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string_util.h"
17 #include "base/values.h"
18 #include "net/base/net_errors.h"
19 #include "net/cert/cert_verifier.h"
20 #include "net/dns/host_resolver.h"
21 #include "net/dns/single_request_host_resolver.h"
22 #include "net/http/http_server_properties.h"
23 #include "net/quic/crypto/channel_id_chromium.h"
24 #include "net/quic/crypto/proof_verifier_chromium.h"
25 #include "net/quic/crypto/quic_random.h"
26 #include "net/quic/crypto/quic_server_info.h"
27 #include "net/quic/port_suggester.h"
28 #include "net/quic/quic_client_session.h"
29 #include "net/quic/quic_clock.h"
30 #include "net/quic/quic_connection.h"
31 #include "net/quic/quic_connection_helper.h"
32 #include "net/quic/quic_crypto_client_stream_factory.h"
33 #include "net/quic/quic_default_packet_writer.h"
34 #include "net/quic/quic_flags.h"
35 #include "net/quic/quic_http_stream.h"
36 #include "net/quic/quic_protocol.h"
37 #include "net/quic/quic_server_id.h"
38 #include "net/socket/client_socket_factory.h"
39 #include "net/udp/udp_client_socket.h"
42 #include "base/win/windows_version.h"
49 enum CreateSessionFailure
{
50 CREATION_ERROR_CONNECTING_SOCKET
,
51 CREATION_ERROR_SETTING_RECEIVE_BUFFER
,
52 CREATION_ERROR_SETTING_SEND_BUFFER
,
56 // When a connection is idle for 30 seconds it will be closed.
57 const int kIdleConnectionTimeoutSeconds
= 30;
59 // The initial receive window size for both streams and sessions.
60 const int32 kInitialReceiveWindowSize
= 10 * 1024 * 1024; // 10MB
62 // Set the maximum number of undecryptable packets the connection will store.
63 const int32 kMaxUndecryptablePackets
= 100;
65 void HistogramCreateSessionFailure(enum CreateSessionFailure error
) {
66 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error
,
70 bool IsEcdsaSupported() {
72 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
79 QuicConfig
InitializeQuicConfig(const QuicTagVector
& connection_options
) {
81 config
.SetIdleConnectionStateLifetime(
82 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
),
83 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
));
84 config
.SetConnectionOptionsToSend(connection_options
);
88 class DefaultPacketWriterFactory
: public QuicConnection::PacketWriterFactory
{
90 explicit DefaultPacketWriterFactory(DatagramClientSocket
* socket
)
92 ~DefaultPacketWriterFactory() override
{}
94 QuicPacketWriter
* Create(QuicConnection
* connection
) const override
;
97 DatagramClientSocket
* socket_
;
100 QuicPacketWriter
* DefaultPacketWriterFactory::Create(
101 QuicConnection
* connection
) const {
102 scoped_ptr
<QuicDefaultPacketWriter
> writer(
103 new QuicDefaultPacketWriter(socket_
));
104 writer
->SetConnection(connection
);
105 return writer
.release();
110 QuicStreamFactory::IpAliasKey::IpAliasKey() {}
112 QuicStreamFactory::IpAliasKey::IpAliasKey(IPEndPoint ip_endpoint
,
114 : ip_endpoint(ip_endpoint
),
115 is_https(is_https
) {}
117 QuicStreamFactory::IpAliasKey::~IpAliasKey() {}
119 bool QuicStreamFactory::IpAliasKey::operator<(
120 const QuicStreamFactory::IpAliasKey
& other
) const {
121 if (!(ip_endpoint
== other
.ip_endpoint
)) {
122 return ip_endpoint
< other
.ip_endpoint
;
124 return is_https
< other
.is_https
;
127 bool QuicStreamFactory::IpAliasKey::operator==(
128 const QuicStreamFactory::IpAliasKey
& other
) const {
129 return is_https
== other
.is_https
&&
130 ip_endpoint
== other
.ip_endpoint
;
133 // Responsible for creating a new QUIC session to the specified server, and
134 // for notifying any associated requests when complete.
135 class QuicStreamFactory::Job
{
137 Job(QuicStreamFactory
* factory
,
138 HostResolver
* host_resolver
,
139 const HostPortPair
& host_port_pair
,
141 bool was_alternate_protocol_recently_broken
,
142 PrivacyMode privacy_mode
,
144 QuicServerInfo
* server_info
,
145 const BoundNetLog
& net_log
);
147 // Creates a new job to handle the resumption of for connecting an
149 Job(QuicStreamFactory
* factory
,
150 HostResolver
* host_resolver
,
151 QuicClientSession
* session
,
152 QuicServerId server_id
);
156 int Run(const CompletionCallback
& callback
);
160 int DoResolveHostComplete(int rv
);
161 int DoLoadServerInfo();
162 int DoLoadServerInfoComplete(int rv
);
164 int DoResumeConnect();
165 int DoConnectComplete(int rv
);
167 void OnIOComplete(int rv
);
169 void RunAuxilaryJob();
173 void CancelWaitForDataReadyCallback();
175 const QuicServerId
server_id() const { return server_id_
; }
177 base::WeakPtr
<Job
> GetWeakPtr() { return weak_factory_
.GetWeakPtr(); }
183 STATE_RESOLVE_HOST_COMPLETE
,
184 STATE_LOAD_SERVER_INFO
,
185 STATE_LOAD_SERVER_INFO_COMPLETE
,
187 STATE_RESUME_CONNECT
,
188 STATE_CONNECT_COMPLETE
,
192 QuicStreamFactory
* factory_
;
193 SingleRequestHostResolver host_resolver_
;
194 QuicServerId server_id_
;
196 bool was_alternate_protocol_recently_broken_
;
197 scoped_ptr
<QuicServerInfo
> server_info_
;
198 bool started_another_job_
;
199 const BoundNetLog net_log_
;
200 QuicClientSession
* session_
;
201 CompletionCallback callback_
;
202 AddressList address_list_
;
203 base::TimeTicks dns_resolution_start_time_
;
204 base::TimeTicks dns_resolution_end_time_
;
205 base::WeakPtrFactory
<Job
> weak_factory_
;
206 DISALLOW_COPY_AND_ASSIGN(Job
);
209 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
210 HostResolver
* host_resolver
,
211 const HostPortPair
& host_port_pair
,
213 bool was_alternate_protocol_recently_broken
,
214 PrivacyMode privacy_mode
,
216 QuicServerInfo
* server_info
,
217 const BoundNetLog
& net_log
)
218 : io_state_(STATE_RESOLVE_HOST
),
220 host_resolver_(host_resolver
),
221 server_id_(host_port_pair
, is_https
, privacy_mode
),
223 was_alternate_protocol_recently_broken_(
224 was_alternate_protocol_recently_broken
),
225 server_info_(server_info
),
226 started_another_job_(false),
229 weak_factory_(this) {
232 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
233 HostResolver
* host_resolver
,
234 QuicClientSession
* session
,
235 QuicServerId server_id
)
236 : io_state_(STATE_RESUME_CONNECT
),
238 host_resolver_(host_resolver
), // unused
239 server_id_(server_id
),
240 is_post_(false), // unused
241 was_alternate_protocol_recently_broken_(false), // unused
242 started_another_job_(false), // unused
243 net_log_(session
->net_log()), // unused
245 weak_factory_(this) {
248 QuicStreamFactory::Job::~Job() {
249 // If disk cache has a pending WaitForDataReadyCallback, cancel that callback.
251 server_info_
->ResetWaitForDataReadyCallback();
254 int QuicStreamFactory::Job::Run(const CompletionCallback
& callback
) {
256 if (rv
== ERR_IO_PENDING
)
257 callback_
= callback
;
259 return rv
> 0 ? OK
: rv
;
262 int QuicStreamFactory::Job::DoLoop(int rv
) {
264 IoState state
= io_state_
;
265 io_state_
= STATE_NONE
;
267 case STATE_RESOLVE_HOST
:
269 rv
= DoResolveHost();
271 case STATE_RESOLVE_HOST_COMPLETE
:
272 rv
= DoResolveHostComplete(rv
);
274 case STATE_LOAD_SERVER_INFO
:
276 rv
= DoLoadServerInfo();
278 case STATE_LOAD_SERVER_INFO_COMPLETE
:
279 rv
= DoLoadServerInfoComplete(rv
);
285 case STATE_RESUME_CONNECT
:
287 rv
= DoResumeConnect();
289 case STATE_CONNECT_COMPLETE
:
290 rv
= DoConnectComplete(rv
);
293 NOTREACHED() << "io_state_: " << io_state_
;
296 } while (io_state_
!= STATE_NONE
&& rv
!= ERR_IO_PENDING
);
300 void QuicStreamFactory::Job::OnIOComplete(int rv
) {
302 if (rv
!= ERR_IO_PENDING
&& !callback_
.is_null()) {
307 void QuicStreamFactory::Job::RunAuxilaryJob() {
308 int rv
= Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
309 base::Unretained(factory_
), this));
310 if (rv
!= ERR_IO_PENDING
)
311 factory_
->OnJobComplete(this, rv
);
314 void QuicStreamFactory::Job::Cancel() {
317 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_CANCELLED
);
320 void QuicStreamFactory::Job::CancelWaitForDataReadyCallback() {
321 // If we are waiting for WaitForDataReadyCallback, then cancel the callback.
322 if (io_state_
!= STATE_LOAD_SERVER_INFO_COMPLETE
)
324 server_info_
->CancelWaitForDataReadyCallback();
328 int QuicStreamFactory::Job::DoResolveHost() {
329 // Start loading the data now, and wait for it after we resolve the host.
331 server_info_
->Start();
334 io_state_
= STATE_RESOLVE_HOST_COMPLETE
;
335 dns_resolution_start_time_
= base::TimeTicks::Now();
336 return host_resolver_
.Resolve(
337 HostResolver::RequestInfo(server_id_
.host_port_pair()), DEFAULT_PRIORITY
,
339 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()),
343 int QuicStreamFactory::Job::DoResolveHostComplete(int rv
) {
344 dns_resolution_end_time_
= base::TimeTicks::Now();
345 UMA_HISTOGRAM_TIMES("Net.QuicSession.HostResolutionTime",
346 dns_resolution_end_time_
- dns_resolution_start_time_
);
350 DCHECK(!factory_
->HasActiveSession(server_id_
));
352 // Inform the factory of this resolution, which will set up
353 // a session alias, if possible.
354 if (factory_
->OnResolution(server_id_
, address_list_
)) {
359 io_state_
= STATE_LOAD_SERVER_INFO
;
361 io_state_
= STATE_CONNECT
;
365 int QuicStreamFactory::Job::DoLoadServerInfo() {
366 io_state_
= STATE_LOAD_SERVER_INFO_COMPLETE
;
368 DCHECK(server_info_
);
370 // To mitigate the effects of disk cache taking too long to load QUIC server
371 // information, set up a timer to cancel WaitForDataReady's callback.
372 if (factory_
->load_server_info_timeout_srtt_multiplier_
> 0) {
373 int64 load_server_info_timeout_ms
=
374 (factory_
->load_server_info_timeout_srtt_multiplier_
*
375 factory_
->GetServerNetworkStatsSmoothedRttInMicroseconds(server_id_
)) /
377 if (load_server_info_timeout_ms
> 0) {
378 factory_
->task_runner_
->PostDelayedTask(
380 base::Bind(&QuicStreamFactory::Job::CancelWaitForDataReadyCallback
,
382 base::TimeDelta::FromMilliseconds(load_server_info_timeout_ms
));
386 int rv
= server_info_
->WaitForDataReady(
387 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
388 if (rv
== ERR_IO_PENDING
&& factory_
->enable_connection_racing()) {
389 // If we are waiting to load server config from the disk cache, then start
391 started_another_job_
= true;
392 factory_
->CreateAuxilaryJob(server_id_
, is_post_
, net_log_
);
397 int QuicStreamFactory::Job::DoLoadServerInfoComplete(int rv
) {
398 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheWaitForDataReadyTime",
399 base::TimeTicks::Now() - dns_resolution_end_time_
);
402 server_info_
.reset();
404 if (started_another_job_
&&
405 (!server_info_
|| server_info_
->state().server_config
.empty() ||
406 !factory_
->CryptoConfigCacheIsEmpty(server_id_
))) {
407 // If we have started another job and if we didn't load the server config
408 // from the disk cache or if we have received a new server config from the
409 // server, then cancel the current job.
410 io_state_
= STATE_NONE
;
411 return ERR_CONNECTION_CLOSED
;
414 io_state_
= STATE_CONNECT
;
418 int QuicStreamFactory::Job::DoConnect() {
419 io_state_
= STATE_CONNECT_COMPLETE
;
422 factory_
->CreateSession(server_id_
, server_info_
.Pass(), address_list_
,
423 dns_resolution_end_time_
, net_log_
, &session_
);
425 DCHECK(rv
!= ERR_IO_PENDING
);
430 if (!session_
->connection()->connected()) {
431 return ERR_CONNECTION_CLOSED
;
434 session_
->StartReading();
435 if (!session_
->connection()->connected()) {
436 return ERR_QUIC_PROTOCOL_ERROR
;
438 bool require_confirmation
=
439 factory_
->require_confirmation() || is_post_
||
440 was_alternate_protocol_recently_broken_
;
442 rv
= session_
->CryptoConnect(
443 require_confirmation
,
444 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
448 int QuicStreamFactory::Job::DoResumeConnect() {
449 io_state_
= STATE_CONNECT_COMPLETE
;
451 int rv
= session_
->ResumeCryptoConnect(
452 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
457 int QuicStreamFactory::Job::DoConnectComplete(int rv
) {
461 DCHECK(!factory_
->HasActiveSession(server_id_
));
462 // There may well now be an active session for this IP. If so, use the
463 // existing session instead.
464 AddressList
address(session_
->connection()->peer_address());
465 if (factory_
->OnResolution(server_id_
, address
)) {
466 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_IP_POOLED
);
471 factory_
->ActivateSession(server_id_
, session_
);
476 QuicStreamRequest::QuicStreamRequest(QuicStreamFactory
* factory
)
477 : factory_(factory
) {}
479 QuicStreamRequest::~QuicStreamRequest() {
480 if (factory_
&& !callback_
.is_null())
481 factory_
->CancelRequest(this);
484 int QuicStreamRequest::Request(const HostPortPair
& host_port_pair
,
486 PrivacyMode privacy_mode
,
487 base::StringPiece method
,
488 const BoundNetLog
& net_log
,
489 const CompletionCallback
& callback
) {
491 DCHECK(callback_
.is_null());
493 int rv
= factory_
->Create(host_port_pair
, is_https
, privacy_mode
, method
,
495 if (rv
== ERR_IO_PENDING
) {
496 host_port_pair_
= host_port_pair
;
498 callback_
= callback
;
507 void QuicStreamRequest::set_stream(scoped_ptr
<QuicHttpStream
> stream
) {
509 stream_
= stream
.Pass();
512 void QuicStreamRequest::OnRequestComplete(int rv
) {
517 scoped_ptr
<QuicHttpStream
> QuicStreamRequest::ReleaseStream() {
519 return stream_
.Pass();
522 QuicStreamFactory::QuicStreamFactory(
523 HostResolver
* host_resolver
,
524 ClientSocketFactory
* client_socket_factory
,
525 base::WeakPtr
<HttpServerProperties
> http_server_properties
,
526 CertVerifier
* cert_verifier
,
527 ChannelIDService
* channel_id_service
,
528 TransportSecurityState
* transport_security_state
,
529 QuicCryptoClientStreamFactory
* quic_crypto_client_stream_factory
,
530 QuicRandom
* random_generator
,
532 size_t max_packet_length
,
533 const std::string
& user_agent_id
,
534 const QuicVersionVector
& supported_versions
,
535 bool enable_port_selection
,
536 bool always_require_handshake_confirmation
,
537 bool disable_connection_pooling
,
538 float load_server_info_timeout_srtt_multiplier
,
539 bool enable_connection_racing
,
540 bool enable_non_blocking_io
,
541 bool disable_disk_cache
,
542 int socket_receive_buffer_size
,
543 const QuicTagVector
& connection_options
)
544 : require_confirmation_(true),
545 host_resolver_(host_resolver
),
546 client_socket_factory_(client_socket_factory
),
547 http_server_properties_(http_server_properties
),
548 transport_security_state_(transport_security_state
),
549 quic_server_info_factory_(nullptr),
550 quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory
),
551 random_generator_(random_generator
),
553 max_packet_length_(max_packet_length
),
554 config_(InitializeQuicConfig(connection_options
)),
555 supported_versions_(supported_versions
),
556 enable_port_selection_(enable_port_selection
),
557 always_require_handshake_confirmation_(
558 always_require_handshake_confirmation
),
559 disable_connection_pooling_(disable_connection_pooling
),
560 load_server_info_timeout_srtt_multiplier_(
561 load_server_info_timeout_srtt_multiplier
),
562 enable_connection_racing_(enable_connection_racing
),
563 enable_non_blocking_io_(enable_non_blocking_io
),
564 disable_disk_cache_(disable_disk_cache
),
565 socket_receive_buffer_size_(socket_receive_buffer_size
),
566 port_seed_(random_generator_
->RandUint64()),
567 check_persisted_supports_quic_(true),
568 task_runner_(nullptr),
569 weak_factory_(this) {
570 DCHECK(transport_security_state_
);
571 crypto_config_
.set_user_agent_id(user_agent_id
);
572 crypto_config_
.AddCanonicalSuffix(".c.youtube.com");
573 crypto_config_
.AddCanonicalSuffix(".googlevideo.com");
574 crypto_config_
.SetProofVerifier(
575 new ProofVerifierChromium(cert_verifier
, transport_security_state
));
576 crypto_config_
.SetChannelIDSource(
577 new ChannelIDSourceChromium(channel_id_service
));
579 if (cpu
.has_aesni() && cpu
.has_avx())
580 crypto_config_
.PreferAesGcm();
581 if (!IsEcdsaSupported())
582 crypto_config_
.DisableEcdsa();
585 QuicStreamFactory::~QuicStreamFactory() {
586 CloseAllSessions(ERR_ABORTED
);
587 while (!all_sessions_
.empty()) {
588 delete all_sessions_
.begin()->first
;
589 all_sessions_
.erase(all_sessions_
.begin());
591 while (!active_jobs_
.empty()) {
592 const QuicServerId server_id
= active_jobs_
.begin()->first
;
593 STLDeleteElements(&(active_jobs_
[server_id
]));
594 active_jobs_
.erase(server_id
);
598 void QuicStreamFactory::set_require_confirmation(bool require_confirmation
) {
599 require_confirmation_
= require_confirmation
;
600 if (http_server_properties_
&& (!(local_address_
== IPEndPoint()))) {
601 http_server_properties_
->SetSupportsQuic(!require_confirmation
,
602 local_address_
.address());
606 int QuicStreamFactory::Create(const HostPortPair
& host_port_pair
,
608 PrivacyMode privacy_mode
,
609 base::StringPiece method
,
610 const BoundNetLog
& net_log
,
611 QuicStreamRequest
* request
) {
612 QuicServerId
server_id(host_port_pair
, is_https
, privacy_mode
);
613 if (HasActiveSession(server_id
)) {
614 request
->set_stream(CreateIfSessionExists(server_id
, net_log
));
618 if (HasActiveJob(server_id
)) {
619 active_requests_
[request
] = server_id
;
620 job_requests_map_
[server_id
].insert(request
);
621 return ERR_IO_PENDING
;
624 // TODO(rtenneti): |task_runner_| is used by the Job. Initialize task_runner_
625 // in the constructor after WebRequestActionWithThreadsTest.* tests are fixed.
627 task_runner_
= base::MessageLoop::current()->message_loop_proxy().get();
629 QuicServerInfo
* quic_server_info
= nullptr;
630 if (quic_server_info_factory_
) {
631 bool load_from_disk_cache
= !disable_disk_cache_
;
632 if (http_server_properties_
) {
633 const AlternateProtocolMap
& alternate_protocol_map
=
634 http_server_properties_
->alternate_protocol_map();
635 AlternateProtocolMap::const_iterator it
=
636 alternate_protocol_map
.Peek(server_id
.host_port_pair());
637 if (it
== alternate_protocol_map
.end() || it
->second
.protocol
!= QUIC
) {
638 // If there is no entry for QUIC, consider that as a new server and
639 // don't wait for Cache thread to load the data for that server.
640 load_from_disk_cache
= false;
643 if (load_from_disk_cache
&& CryptoConfigCacheIsEmpty(server_id
)) {
644 quic_server_info
= quic_server_info_factory_
->GetForServer(server_id
);
648 scoped_ptr
<Job
> job(new Job(this, host_resolver_
, host_port_pair
, is_https
,
649 WasQuicRecentlyBroken(server_id
), privacy_mode
,
650 method
== "POST" /* is_post */, quic_server_info
,
652 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
653 base::Unretained(this), job
.get()));
654 if (rv
== ERR_IO_PENDING
) {
655 active_requests_
[request
] = server_id
;
656 job_requests_map_
[server_id
].insert(request
);
657 active_jobs_
[server_id
].insert(job
.release());
661 DCHECK(HasActiveSession(server_id
));
662 request
->set_stream(CreateIfSessionExists(server_id
, net_log
));
667 void QuicStreamFactory::CreateAuxilaryJob(const QuicServerId server_id
,
669 const BoundNetLog
& net_log
) {
670 Job
* aux_job
= new Job(this, host_resolver_
, server_id
.host_port_pair(),
671 server_id
.is_https(), WasQuicRecentlyBroken(server_id
),
672 server_id
.privacy_mode(), is_post
, nullptr, net_log
);
673 active_jobs_
[server_id
].insert(aux_job
);
674 task_runner_
->PostTask(FROM_HERE
,
675 base::Bind(&QuicStreamFactory::Job::RunAuxilaryJob
,
676 aux_job
->GetWeakPtr()));
679 bool QuicStreamFactory::OnResolution(
680 const QuicServerId
& server_id
,
681 const AddressList
& address_list
) {
682 DCHECK(!HasActiveSession(server_id
));
683 if (disable_connection_pooling_
) {
686 for (const IPEndPoint
& address
: address_list
) {
687 const IpAliasKey
ip_alias_key(address
, server_id
.is_https());
688 if (!ContainsKey(ip_aliases_
, ip_alias_key
))
691 const SessionSet
& sessions
= ip_aliases_
[ip_alias_key
];
692 for (QuicClientSession
* session
: sessions
) {
693 if (!session
->CanPool(server_id
.host(), server_id
.privacy_mode()))
695 active_sessions_
[server_id
] = session
;
696 session_aliases_
[session
].insert(server_id
);
703 void QuicStreamFactory::OnJobComplete(Job
* job
, int rv
) {
704 QuicServerId server_id
= job
->server_id();
706 JobSet
* jobs
= &(active_jobs_
[server_id
]);
707 if (jobs
->size() > 1) {
708 // If there is another pending job, then we can delete this job and let
709 // the other job handle the request.
718 if (!always_require_handshake_confirmation_
)
719 set_require_confirmation(false);
721 // Create all the streams, but do not notify them yet.
722 for (QuicStreamRequest
* request
: job_requests_map_
[server_id
]) {
723 DCHECK(HasActiveSession(server_id
));
724 request
->set_stream(CreateIfSessionExists(server_id
, request
->net_log()));
728 while (!job_requests_map_
[server_id
].empty()) {
729 RequestSet::iterator it
= job_requests_map_
[server_id
].begin();
730 QuicStreamRequest
* request
= *it
;
731 job_requests_map_
[server_id
].erase(it
);
732 active_requests_
.erase(request
);
733 // Even though we're invoking callbacks here, we don't need to worry
734 // about |this| being deleted, because the factory is owned by the
735 // profile which can not be deleted via callbacks.
736 request
->OnRequestComplete(rv
);
739 for (Job
* other_job
: active_jobs_
[server_id
]) {
740 if (other_job
!= job
)
744 STLDeleteElements(&(active_jobs_
[server_id
]));
745 active_jobs_
.erase(server_id
);
746 job_requests_map_
.erase(server_id
);
749 // Returns a newly created QuicHttpStream owned by the caller, if a
750 // matching session already exists. Returns nullptr otherwise.
751 scoped_ptr
<QuicHttpStream
> QuicStreamFactory::CreateIfSessionExists(
752 const QuicServerId
& server_id
,
753 const BoundNetLog
& net_log
) {
754 if (!HasActiveSession(server_id
)) {
755 DVLOG(1) << "No active session";
756 return scoped_ptr
<QuicHttpStream
>();
759 QuicClientSession
* session
= active_sessions_
[server_id
];
761 return scoped_ptr
<QuicHttpStream
>(
762 new QuicHttpStream(session
->GetWeakPtr()));
765 void QuicStreamFactory::OnIdleSession(QuicClientSession
* session
) {
768 void QuicStreamFactory::OnSessionGoingAway(QuicClientSession
* session
) {
769 const AliasSet
& aliases
= session_aliases_
[session
];
770 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
772 DCHECK(active_sessions_
.count(*it
));
773 DCHECK_EQ(session
, active_sessions_
[*it
]);
774 // Track sessions which have recently gone away so that we can disable
776 if (session
->goaway_received()) {
777 gone_away_aliases_
.insert(*it
);
780 active_sessions_
.erase(*it
);
781 ProcessGoingAwaySession(session
, *it
, true);
783 ProcessGoingAwaySession(session
, all_sessions_
[session
], false);
784 if (!aliases
.empty()) {
785 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
786 aliases
.begin()->is_https());
787 ip_aliases_
[ip_alias_key
].erase(session
);
788 if (ip_aliases_
[ip_alias_key
].empty()) {
789 ip_aliases_
.erase(ip_alias_key
);
792 session_aliases_
.erase(session
);
795 void QuicStreamFactory::OnSessionClosed(QuicClientSession
* session
) {
796 DCHECK_EQ(0u, session
->GetNumOpenStreams());
797 OnSessionGoingAway(session
);
799 all_sessions_
.erase(session
);
802 void QuicStreamFactory::OnSessionConnectTimeout(
803 QuicClientSession
* session
) {
804 const AliasSet
& aliases
= session_aliases_
[session
];
805 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
807 DCHECK(active_sessions_
.count(*it
));
808 DCHECK_EQ(session
, active_sessions_
[*it
]);
809 active_sessions_
.erase(*it
);
812 if (aliases
.empty()) {
816 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
817 aliases
.begin()->is_https());
818 ip_aliases_
[ip_alias_key
].erase(session
);
819 if (ip_aliases_
[ip_alias_key
].empty()) {
820 ip_aliases_
.erase(ip_alias_key
);
822 QuicServerId server_id
= *aliases
.begin();
823 session_aliases_
.erase(session
);
824 Job
* job
= new Job(this, host_resolver_
, session
, server_id
);
825 active_jobs_
[server_id
].insert(job
);
826 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
827 base::Unretained(this), job
));
828 DCHECK_EQ(ERR_IO_PENDING
, rv
);
831 void QuicStreamFactory::CancelRequest(QuicStreamRequest
* request
) {
832 DCHECK(ContainsKey(active_requests_
, request
));
833 QuicServerId server_id
= active_requests_
[request
];
834 job_requests_map_
[server_id
].erase(request
);
835 active_requests_
.erase(request
);
838 void QuicStreamFactory::CloseAllSessions(int error
) {
839 while (!active_sessions_
.empty()) {
840 size_t initial_size
= active_sessions_
.size();
841 active_sessions_
.begin()->second
->CloseSessionOnError(error
);
842 DCHECK_NE(initial_size
, active_sessions_
.size());
844 while (!all_sessions_
.empty()) {
845 size_t initial_size
= all_sessions_
.size();
846 all_sessions_
.begin()->first
->CloseSessionOnError(error
);
847 DCHECK_NE(initial_size
, all_sessions_
.size());
849 DCHECK(all_sessions_
.empty());
852 base::Value
* QuicStreamFactory::QuicStreamFactoryInfoToValue() const {
853 base::ListValue
* list
= new base::ListValue();
855 for (SessionMap::const_iterator it
= active_sessions_
.begin();
856 it
!= active_sessions_
.end(); ++it
) {
857 const QuicServerId
& server_id
= it
->first
;
858 QuicClientSession
* session
= it
->second
;
859 const AliasSet
& aliases
= session_aliases_
.find(session
)->second
;
860 // Only add a session to the list once.
861 if (server_id
== *aliases
.begin()) {
862 std::set
<HostPortPair
> hosts
;
863 for (AliasSet::const_iterator alias_it
= aliases
.begin();
864 alias_it
!= aliases
.end(); ++alias_it
) {
865 hosts
.insert(alias_it
->host_port_pair());
867 list
->Append(session
->GetInfoAsValue(hosts
));
873 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
874 crypto_config_
.ClearCachedStates();
877 void QuicStreamFactory::OnIPAddressChanged() {
878 CloseAllSessions(ERR_NETWORK_CHANGED
);
879 set_require_confirmation(true);
882 void QuicStreamFactory::OnCertAdded(const X509Certificate
* cert
) {
883 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
886 void QuicStreamFactory::OnCACertChanged(const X509Certificate
* cert
) {
887 // We should flush the sessions if we removed trust from a
888 // cert, because a previously trusted server may have become
891 // We should not flush the sessions if we added trust to a cert.
893 // Since the OnCACertChanged method doesn't tell us what
894 // kind of change it is, we have to flush the socket
896 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
899 bool QuicStreamFactory::HasActiveSession(
900 const QuicServerId
& server_id
) const {
901 return ContainsKey(active_sessions_
, server_id
);
904 bool QuicStreamFactory::HasActiveJob(const QuicServerId
& key
) const {
905 return ContainsKey(active_jobs_
, key
);
908 int QuicStreamFactory::CreateSession(const QuicServerId
& server_id
,
909 scoped_ptr
<QuicServerInfo
> server_info
,
910 const AddressList
& address_list
,
911 base::TimeTicks dns_resolution_end_time
,
912 const BoundNetLog
& net_log
,
913 QuicClientSession
** session
) {
914 bool enable_port_selection
= enable_port_selection_
;
915 if (enable_port_selection
&&
916 ContainsKey(gone_away_aliases_
, server_id
)) {
917 // Disable port selection when the server is going away.
918 // There is no point in trying to return to the same server, if
919 // that server is no longer handling requests.
920 enable_port_selection
= false;
921 gone_away_aliases_
.erase(server_id
);
924 QuicConnectionId connection_id
= random_generator_
->RandUint64();
925 IPEndPoint addr
= *address_list
.begin();
926 scoped_refptr
<PortSuggester
> port_suggester
=
927 new PortSuggester(server_id
.host_port_pair(), port_seed_
);
928 DatagramSocket::BindType bind_type
= enable_port_selection
?
929 DatagramSocket::RANDOM_BIND
: // Use our callback.
930 DatagramSocket::DEFAULT_BIND
; // Use OS to randomize.
931 scoped_ptr
<DatagramClientSocket
> socket(
932 client_socket_factory_
->CreateDatagramClientSocket(
934 base::Bind(&PortSuggester::SuggestPort
, port_suggester
),
935 net_log
.net_log(), net_log
.source()));
937 if (enable_non_blocking_io_
&&
938 client_socket_factory_
== ClientSocketFactory::GetDefaultFactory()) {
940 static_cast<UDPClientSocket
*>(socket
.get())->UseNonBlockingIO();
944 int rv
= socket
->Connect(addr
);
947 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET
);
950 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested",
951 port_suggester
->call_count());
952 if (enable_port_selection
) {
953 DCHECK_LE(1u, port_suggester
->call_count());
955 DCHECK_EQ(0u, port_suggester
->call_count());
958 rv
= socket
->SetReceiveBufferSize(socket_receive_buffer_size_
);
960 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER
);
963 // Set a buffer large enough to contain the initial CWND's worth of packet
964 // to work around the problem with CHLO packets being sent out with the
965 // wrong encryption level, when the send buffer is full.
966 rv
= socket
->SetSendBufferSize(kMaxPacketSize
* 20);
968 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER
);
972 socket
->GetLocalAddress(&local_address_
);
973 if (check_persisted_supports_quic_
&& http_server_properties_
) {
974 check_persisted_supports_quic_
= false;
975 IPAddressNumber last_address
;
976 if (http_server_properties_
->GetSupportsQuic(&last_address
) &&
977 last_address
== local_address_
.address()) {
978 require_confirmation_
= false;
982 DefaultPacketWriterFactory
packet_writer_factory(socket
.get());
984 if (!helper_
.get()) {
985 helper_
.reset(new QuicConnectionHelper(
986 base::MessageLoop::current()->message_loop_proxy().get(),
987 clock_
.get(), random_generator_
));
990 QuicConnection
* connection
= new QuicConnection(
991 connection_id
, addr
, helper_
.get(), packet_writer_factory
,
992 true /* owns_writer */, Perspective::IS_CLIENT
, server_id
.is_https(),
993 supported_versions_
);
994 connection
->set_max_packet_length(max_packet_length_
);
996 InitializeCachedStateInCryptoConfig(server_id
, server_info
);
998 QuicConfig config
= config_
;
999 config
.SetSocketReceiveBufferToSend(socket_receive_buffer_size_
);
1000 config
.set_max_undecryptable_packets(kMaxUndecryptablePackets
);
1001 config
.SetInitialStreamFlowControlWindowToSend(kInitialReceiveWindowSize
);
1002 config
.SetInitialSessionFlowControlWindowToSend(kInitialReceiveWindowSize
);
1003 int64 srtt
= GetServerNetworkStatsSmoothedRttInMicroseconds(server_id
);
1005 config
.SetInitialRoundTripTimeUsToSend(static_cast<uint32
>(srtt
));
1006 config
.SetBytesForConnectionIdToSend(0);
1008 if (quic_server_info_factory_
&& !server_info
) {
1009 // Start the disk cache loading so that we can persist the newer QUIC server
1010 // information and/or inform the disk cache that we have reused
1012 server_info
.reset(quic_server_info_factory_
->GetForServer(server_id
));
1013 server_info
->Start();
1016 *session
= new QuicClientSession(
1017 connection
, socket
.Pass(), this, transport_security_state_
,
1018 server_info
.Pass(), config
, network_connection_
.GetDescription(),
1019 dns_resolution_end_time
,
1020 base::MessageLoop::current()->message_loop_proxy().get(),
1023 all_sessions_
[*session
] = server_id
; // owning pointer
1025 (*session
)->InitializeSession(server_id
, &crypto_config_
,
1026 quic_crypto_client_stream_factory_
);
1027 bool closed_during_initialize
=
1028 !ContainsKey(all_sessions_
, *session
) ||
1029 !(*session
)->connection()->connected();
1030 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedDuringInitializeSession",
1031 closed_during_initialize
);
1032 if (closed_during_initialize
) {
1033 DLOG(DFATAL
) << "Session closed during initialize";
1035 return ERR_CONNECTION_CLOSED
;
1040 void QuicStreamFactory::ActivateSession(
1041 const QuicServerId
& server_id
,
1042 QuicClientSession
* session
) {
1043 DCHECK(!HasActiveSession(server_id
));
1044 UMA_HISTOGRAM_COUNTS("Net.QuicActiveSessions", active_sessions_
.size());
1045 active_sessions_
[server_id
] = session
;
1046 session_aliases_
[session
].insert(server_id
);
1047 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
1048 server_id
.is_https());
1049 DCHECK(!ContainsKey(ip_aliases_
[ip_alias_key
], session
));
1050 ip_aliases_
[ip_alias_key
].insert(session
);
1053 int64
QuicStreamFactory::GetServerNetworkStatsSmoothedRttInMicroseconds(
1054 const QuicServerId
& server_id
) const {
1055 if (!http_server_properties_
)
1057 const ServerNetworkStats
* stats
=
1058 http_server_properties_
->GetServerNetworkStats(
1059 server_id
.host_port_pair());
1060 if (stats
== nullptr)
1062 return stats
->srtt
.InMicroseconds();
1065 bool QuicStreamFactory::WasQuicRecentlyBroken(
1066 const QuicServerId
& server_id
) const {
1067 if (!http_server_properties_
)
1069 const AlternativeService
alternative_service(QUIC
,
1070 server_id
.host_port_pair());
1071 return http_server_properties_
->WasAlternativeServiceRecentlyBroken(
1072 alternative_service
);
1075 bool QuicStreamFactory::CryptoConfigCacheIsEmpty(
1076 const QuicServerId
& server_id
) {
1077 QuicCryptoClientConfig::CachedState
* cached
=
1078 crypto_config_
.LookupOrCreate(server_id
);
1079 return cached
->IsEmpty();
1082 void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
1083 const QuicServerId
& server_id
,
1084 const scoped_ptr
<QuicServerInfo
>& server_info
) {
1085 // |server_info| will be NULL, if a non-empty server config already exists in
1086 // the memory cache. This is a minor optimization to avoid LookupOrCreate.
1090 QuicCryptoClientConfig::CachedState
* cached
=
1091 crypto_config_
.LookupOrCreate(server_id
);
1092 if (!cached
->IsEmpty())
1095 if (http_server_properties_
) {
1096 if (quic_supported_servers_at_startup_
.empty()) {
1097 for (const std::pair
<const HostPortPair
, AlternateProtocolInfo
>&
1098 key_value
: http_server_properties_
->alternate_protocol_map()) {
1099 if (key_value
.second
.protocol
== QUIC
) {
1100 quic_supported_servers_at_startup_
.insert(key_value
.first
);
1105 // TODO(rtenneti): Delete the following histogram after collecting stats.
1106 // If the AlternateProtocolMap contained an entry for this host, check if
1107 // the disk cache contained an entry for it.
1108 if (ContainsKey(quic_supported_servers_at_startup_
,
1109 server_id
.host_port_pair())) {
1110 UMA_HISTOGRAM_BOOLEAN(
1111 "Net.QuicServerInfo.ExpectConfigMissingFromDiskCache",
1112 server_info
->state().server_config
.empty());
1116 if (!cached
->Initialize(server_info
->state().server_config
,
1117 server_info
->state().source_address_token
,
1118 server_info
->state().certs
,
1119 server_info
->state().server_config_sig
,
1123 if (!server_id
.is_https()) {
1124 // Don't check the certificates for insecure QUIC.
1125 cached
->SetProofValid();
1129 void QuicStreamFactory::ProcessGoingAwaySession(
1130 QuicClientSession
* session
,
1131 const QuicServerId
& server_id
,
1132 bool session_was_active
) {
1133 if (!http_server_properties_
)
1136 const QuicConnectionStats
& stats
= session
->connection()->GetStats();
1137 const AlternativeService
alternative_service(QUIC
,
1138 server_id
.host_port_pair());
1139 if (session
->IsCryptoHandshakeConfirmed()) {
1140 http_server_properties_
->ConfirmAlternativeService(alternative_service
);
1141 ServerNetworkStats network_stats
;
1142 network_stats
.srtt
= base::TimeDelta::FromMicroseconds(stats
.srtt_us
);
1143 network_stats
.bandwidth_estimate
= stats
.estimated_bandwidth
;
1144 http_server_properties_
->SetServerNetworkStats(server_id
.host_port_pair(),
1149 UMA_HISTOGRAM_COUNTS("Net.QuicHandshakeNotConfirmedNumPacketsReceived",
1150 stats
.packets_received
);
1152 if (!session_was_active
)
1155 // TODO(rch): In the special case where the session has received no
1156 // packets from the peer, we should consider blacklisting this
1157 // differently so that we still race TCP but we don't consider the
1158 // session connected until the handshake has been confirmed.
1159 HistogramBrokenAlternateProtocolLocation(
1160 BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY
);
1162 // Since the session was active, there's no longer an
1163 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the TCP
1164 // job also fails. So to avoid not using QUIC when we otherwise could, we mark
1165 // it as recently broken, which means that 0-RTT will be disabled but we'll
1167 http_server_properties_
->MarkAlternativeServiceRecentlyBroken(
1168 alternative_service
);