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/histogram.h"
13 #include "base/profiler/scoped_tracker.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/congestion_control/tcp_receiver.h"
24 #include "net/quic/crypto/channel_id_chromium.h"
25 #include "net/quic/crypto/proof_verifier_chromium.h"
26 #include "net/quic/crypto/quic_random.h"
27 #include "net/quic/crypto/quic_server_info.h"
28 #include "net/quic/port_suggester.h"
29 #include "net/quic/quic_client_session.h"
30 #include "net/quic/quic_clock.h"
31 #include "net/quic/quic_connection.h"
32 #include "net/quic/quic_connection_helper.h"
33 #include "net/quic/quic_crypto_client_stream_factory.h"
34 #include "net/quic/quic_default_packet_writer.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"
41 #include "base/win/windows_version.h"
48 enum CreateSessionFailure
{
49 CREATION_ERROR_CONNECTING_SOCKET
,
50 CREATION_ERROR_SETTING_RECEIVE_BUFFER
,
51 CREATION_ERROR_SETTING_SEND_BUFFER
,
55 // When a connection is idle for 30 seconds it will be closed.
56 const int kIdleConnectionTimeoutSeconds
= 30;
58 // The initial receive window size for both streams and sessions.
59 const int32 kInitialReceiveWindowSize
= 10 * 1024 * 1024; // 10MB
61 // Set the maximum number of undecryptable packets the connection will store.
62 const int32 kMaxUndecryptablePackets
= 100;
64 const char kDummyHostname
[] = "quic.global.props";
65 const uint16 kDummyPort
= 0;
67 void HistogramCreateSessionFailure(enum CreateSessionFailure error
) {
68 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error
,
72 bool IsEcdsaSupported() {
74 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
81 QuicConfig
InitializeQuicConfig(const QuicTagVector
& connection_options
) {
83 config
.SetIdleConnectionStateLifetime(
84 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
),
85 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
));
86 config
.SetConnectionOptionsToSend(connection_options
);
90 class DefaultPacketWriterFactory
: public QuicConnection::PacketWriterFactory
{
92 explicit DefaultPacketWriterFactory(DatagramClientSocket
* socket
)
94 ~DefaultPacketWriterFactory() override
{}
96 QuicPacketWriter
* Create(QuicConnection
* connection
) const override
;
99 DatagramClientSocket
* socket_
;
102 QuicPacketWriter
* DefaultPacketWriterFactory::Create(
103 QuicConnection
* connection
) const {
104 scoped_ptr
<QuicDefaultPacketWriter
> writer(
105 new QuicDefaultPacketWriter(socket_
));
106 writer
->SetConnection(connection
);
107 return writer
.release();
112 QuicStreamFactory::IpAliasKey::IpAliasKey() {}
114 QuicStreamFactory::IpAliasKey::IpAliasKey(IPEndPoint ip_endpoint
,
116 : ip_endpoint(ip_endpoint
),
117 is_https(is_https
) {}
119 QuicStreamFactory::IpAliasKey::~IpAliasKey() {}
121 bool QuicStreamFactory::IpAliasKey::operator<(
122 const QuicStreamFactory::IpAliasKey
& other
) const {
123 if (!(ip_endpoint
== other
.ip_endpoint
)) {
124 return ip_endpoint
< other
.ip_endpoint
;
126 return is_https
< other
.is_https
;
129 bool QuicStreamFactory::IpAliasKey::operator==(
130 const QuicStreamFactory::IpAliasKey
& other
) const {
131 return is_https
== other
.is_https
&&
132 ip_endpoint
== other
.ip_endpoint
;
135 // Responsible for creating a new QUIC session to the specified server, and
136 // for notifying any associated requests when complete.
137 class QuicStreamFactory::Job
{
139 Job(QuicStreamFactory
* factory
,
140 HostResolver
* host_resolver
,
141 const HostPortPair
& host_port_pair
,
143 bool was_alternate_protocol_recently_broken
,
144 PrivacyMode privacy_mode
,
145 base::StringPiece method
,
146 QuicServerInfo
* server_info
,
147 const BoundNetLog
& net_log
);
149 // Creates a new job to handle the resumption of for connecting an
151 Job(QuicStreamFactory
* factory
,
152 HostResolver
* host_resolver
,
153 QuicClientSession
* session
,
154 QuicServerId server_id
);
158 int Run(const CompletionCallback
& callback
);
162 int DoResolveHostComplete(int rv
);
163 int DoLoadServerInfo();
164 int DoLoadServerInfoComplete(int rv
);
166 int DoResumeConnect();
167 int DoConnectComplete(int rv
);
169 void OnIOComplete(int rv
);
171 void CancelWaitForDataReadyCallback();
173 CompletionCallback
callback() {
177 const QuicServerId
server_id() const {
185 STATE_RESOLVE_HOST_COMPLETE
,
186 STATE_LOAD_SERVER_INFO
,
187 STATE_LOAD_SERVER_INFO_COMPLETE
,
189 STATE_RESUME_CONNECT
,
190 STATE_CONNECT_COMPLETE
,
194 QuicStreamFactory
* factory_
;
195 SingleRequestHostResolver host_resolver_
;
196 QuicServerId server_id_
;
198 bool was_alternate_protocol_recently_broken_
;
199 scoped_ptr
<QuicServerInfo
> server_info_
;
200 const BoundNetLog net_log_
;
201 QuicClientSession
* session_
;
202 CompletionCallback callback_
;
203 AddressList address_list_
;
204 base::TimeTicks disk_cache_load_start_time_
;
205 base::TimeTicks dns_resolution_start_time_
;
206 base::WeakPtrFactory
<Job
> weak_factory_
;
207 DISALLOW_COPY_AND_ASSIGN(Job
);
210 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
211 HostResolver
* host_resolver
,
212 const HostPortPair
& host_port_pair
,
214 bool was_alternate_protocol_recently_broken
,
215 PrivacyMode privacy_mode
,
216 base::StringPiece method
,
217 QuicServerInfo
* server_info
,
218 const BoundNetLog
& net_log
)
219 : io_state_(STATE_RESOLVE_HOST
),
221 host_resolver_(host_resolver
),
222 server_id_(host_port_pair
, is_https
, privacy_mode
),
223 is_post_(method
== "POST"),
224 was_alternate_protocol_recently_broken_(
225 was_alternate_protocol_recently_broken
),
226 server_info_(server_info
),
229 weak_factory_(this) {}
231 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
232 HostResolver
* host_resolver
,
233 QuicClientSession
* session
,
234 QuicServerId server_id
)
235 : io_state_(STATE_RESUME_CONNECT
),
237 host_resolver_(host_resolver
), // unused
238 server_id_(server_id
),
239 is_post_(false), // unused
240 was_alternate_protocol_recently_broken_(false), // unused
241 net_log_(session
->net_log()), // unused
243 weak_factory_(this) {}
245 QuicStreamFactory::Job::~Job() {
248 int QuicStreamFactory::Job::Run(const CompletionCallback
& callback
) {
250 if (rv
== ERR_IO_PENDING
)
251 callback_
= callback
;
253 return rv
> 0 ? OK
: rv
;
256 int QuicStreamFactory::Job::DoLoop(int rv
) {
258 IoState state
= io_state_
;
259 io_state_
= STATE_NONE
;
261 case STATE_RESOLVE_HOST
:
263 rv
= DoResolveHost();
265 case STATE_RESOLVE_HOST_COMPLETE
:
266 rv
= DoResolveHostComplete(rv
);
268 case STATE_LOAD_SERVER_INFO
:
270 rv
= DoLoadServerInfo();
272 case STATE_LOAD_SERVER_INFO_COMPLETE
:
273 rv
= DoLoadServerInfoComplete(rv
);
279 case STATE_RESUME_CONNECT
:
281 rv
= DoResumeConnect();
283 case STATE_CONNECT_COMPLETE
:
284 rv
= DoConnectComplete(rv
);
287 NOTREACHED() << "io_state_: " << io_state_
;
290 } while (io_state_
!= STATE_NONE
&& rv
!= ERR_IO_PENDING
);
294 void QuicStreamFactory::Job::OnIOComplete(int rv
) {
295 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
296 tracked_objects::ScopedTracker
tracking_profile1(
297 FROM_HERE_WITH_EXPLICIT_FUNCTION(
298 "422516 QuicStreamFactory::Job::OnIOComplete1"));
302 tracked_objects::ScopedTracker
tracking_profile2(
303 FROM_HERE_WITH_EXPLICIT_FUNCTION(
304 "422516 QuicStreamFactory::Job::OnIOComplete2"));
306 if (rv
!= ERR_IO_PENDING
&& !callback_
.is_null()) {
311 void QuicStreamFactory::Job::CancelWaitForDataReadyCallback() {
312 // If we are waiting for WaitForDataReadyCallback, then cancel the callback.
313 if (io_state_
!= STATE_LOAD_SERVER_INFO_COMPLETE
)
315 server_info_
->CancelWaitForDataReadyCallback();
319 int QuicStreamFactory::Job::DoResolveHost() {
320 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
321 tracked_objects::ScopedTracker
tracking_profile(
322 FROM_HERE_WITH_EXPLICIT_FUNCTION(
323 "422516 QuicStreamFactory::Job::DoResolveHost"));
325 // Start loading the data now, and wait for it after we resolve the host.
327 server_info_
->Start();
330 io_state_
= STATE_RESOLVE_HOST_COMPLETE
;
331 dns_resolution_start_time_
= base::TimeTicks::Now();
332 return host_resolver_
.Resolve(
333 HostResolver::RequestInfo(server_id_
.host_port_pair()),
336 base::Bind(&QuicStreamFactory::Job::OnIOComplete
,
337 weak_factory_
.GetWeakPtr()),
341 int QuicStreamFactory::Job::DoResolveHostComplete(int rv
) {
342 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
343 tracked_objects::ScopedTracker
tracking_profile(
344 FROM_HERE_WITH_EXPLICIT_FUNCTION(
345 "422516 QuicStreamFactory::Job::DoResolveHostComplete"));
347 UMA_HISTOGRAM_TIMES("Net.QuicSession.HostResolutionTime",
348 base::TimeTicks::Now() - dns_resolution_start_time_
);
352 DCHECK(!factory_
->HasActiveSession(server_id_
));
354 // Inform the factory of this resolution, which will set up
355 // a session alias, if possible.
356 if (factory_
->OnResolution(server_id_
, address_list_
)) {
360 io_state_
= STATE_LOAD_SERVER_INFO
;
364 int QuicStreamFactory::Job::DoLoadServerInfo() {
365 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
366 tracked_objects::ScopedTracker
tracking_profile(
367 FROM_HERE_WITH_EXPLICIT_FUNCTION(
368 "422516 QuicStreamFactory::Job::DoLoadServerInfo"));
370 io_state_
= STATE_LOAD_SERVER_INFO_COMPLETE
;
375 // To mitigate the effects of disk cache taking too long to load QUIC server
376 // information, set up a timer to cancel WaitForDataReady's callback.
377 if (factory_
->load_server_info_timeout_ms_
> 0) {
378 factory_
->task_runner_
->PostDelayedTask(
380 base::Bind(&QuicStreamFactory::Job::CancelWaitForDataReadyCallback
,
381 weak_factory_
.GetWeakPtr()),
382 base::TimeDelta::FromMilliseconds(
383 factory_
->load_server_info_timeout_ms_
));
386 disk_cache_load_start_time_
= base::TimeTicks::Now();
387 return server_info_
->WaitForDataReady(
388 base::Bind(&QuicStreamFactory::Job::OnIOComplete
,
389 weak_factory_
.GetWeakPtr()));
392 int QuicStreamFactory::Job::DoLoadServerInfoComplete(int rv
) {
393 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
394 tracked_objects::ScopedTracker
tracking_profile(
395 FROM_HERE_WITH_EXPLICIT_FUNCTION(
396 "422516 QuicStreamFactory::Job::DoLoadServerInfoComplete"));
399 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheWaitForDataReadyTime",
400 base::TimeTicks::Now() - disk_cache_load_start_time_
);
404 server_info_
.reset();
407 io_state_
= STATE_CONNECT
;
411 int QuicStreamFactory::Job::DoConnect() {
412 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
413 tracked_objects::ScopedTracker
tracking_profile(
414 FROM_HERE_WITH_EXPLICIT_FUNCTION(
415 "422516 QuicStreamFactory::Job::DoConnect"));
417 io_state_
= STATE_CONNECT_COMPLETE
;
419 int rv
= factory_
->CreateSession(server_id_
, server_info_
.Pass(),
420 address_list_
, net_log_
, &session_
);
422 DCHECK(rv
!= ERR_IO_PENDING
);
427 if (!session_
->connection()->connected()) {
428 return ERR_CONNECTION_CLOSED
;
431 session_
->StartReading();
432 if (!session_
->connection()->connected()) {
433 return ERR_QUIC_PROTOCOL_ERROR
;
435 bool require_confirmation
=
436 factory_
->require_confirmation() || is_post_
||
437 was_alternate_protocol_recently_broken_
;
438 rv
= session_
->CryptoConnect(
439 require_confirmation
,
440 base::Bind(&QuicStreamFactory::Job::OnIOComplete
,
441 base::Unretained(this)));
445 int QuicStreamFactory::Job::DoResumeConnect() {
446 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
447 tracked_objects::ScopedTracker
tracking_profile(
448 FROM_HERE_WITH_EXPLICIT_FUNCTION(
449 "422516 QuicStreamFactory::Job::DoResumeConnect"));
451 io_state_
= STATE_CONNECT_COMPLETE
;
453 int rv
= session_
->ResumeCryptoConnect(
454 base::Bind(&QuicStreamFactory::Job::OnIOComplete
,
455 base::Unretained(this)));
460 int QuicStreamFactory::Job::DoConnectComplete(int rv
) {
461 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
462 tracked_objects::ScopedTracker
tracking_profile(
463 FROM_HERE_WITH_EXPLICIT_FUNCTION(
464 "422516 QuicStreamFactory::Job::DoConnectComplete"));
469 DCHECK(!factory_
->HasActiveSession(server_id_
));
470 // There may well now be an active session for this IP. If so, use the
471 // existing session instead.
472 AddressList
address(session_
->connection()->peer_address());
473 if (factory_
->OnResolution(server_id_
, address
)) {
474 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_IP_POOLED
);
479 factory_
->ActivateSession(server_id_
, session_
);
484 QuicStreamRequest::QuicStreamRequest(QuicStreamFactory
* factory
)
485 : factory_(factory
) {}
487 QuicStreamRequest::~QuicStreamRequest() {
488 if (factory_
&& !callback_
.is_null())
489 factory_
->CancelRequest(this);
492 int QuicStreamRequest::Request(const HostPortPair
& host_port_pair
,
494 PrivacyMode privacy_mode
,
495 base::StringPiece method
,
496 const BoundNetLog
& net_log
,
497 const CompletionCallback
& callback
) {
499 DCHECK(callback_
.is_null());
501 int rv
= factory_
->Create(host_port_pair
, is_https
, privacy_mode
, method
,
503 if (rv
== ERR_IO_PENDING
) {
504 host_port_pair_
= host_port_pair
;
505 is_https_
= is_https
;
507 callback_
= callback
;
516 void QuicStreamRequest::set_stream(scoped_ptr
<QuicHttpStream
> stream
) {
518 stream_
= stream
.Pass();
521 void QuicStreamRequest::OnRequestComplete(int rv
) {
526 scoped_ptr
<QuicHttpStream
> QuicStreamRequest::ReleaseStream() {
528 return stream_
.Pass();
531 QuicStreamFactory::QuicStreamFactory(
532 HostResolver
* host_resolver
,
533 ClientSocketFactory
* client_socket_factory
,
534 base::WeakPtr
<HttpServerProperties
> http_server_properties
,
535 CertVerifier
* cert_verifier
,
536 ChannelIDService
* channel_id_service
,
537 TransportSecurityState
* transport_security_state
,
538 QuicCryptoClientStreamFactory
* quic_crypto_client_stream_factory
,
539 QuicRandom
* random_generator
,
541 size_t max_packet_length
,
542 const std::string
& user_agent_id
,
543 const QuicVersionVector
& supported_versions
,
544 bool enable_port_selection
,
545 bool always_require_handshake_confirmation
,
546 bool disable_connection_pooling
,
547 int load_server_info_timeout
,
548 bool disable_loading_server_info_for_new_servers
,
549 const QuicTagVector
& connection_options
)
550 : require_confirmation_(true),
551 host_resolver_(host_resolver
),
552 client_socket_factory_(client_socket_factory
),
553 http_server_properties_(http_server_properties
),
554 transport_security_state_(transport_security_state
),
555 quic_server_info_factory_(nullptr),
556 quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory
),
557 random_generator_(random_generator
),
559 max_packet_length_(max_packet_length
),
560 config_(InitializeQuicConfig(connection_options
)),
561 supported_versions_(supported_versions
),
562 enable_port_selection_(enable_port_selection
),
563 always_require_handshake_confirmation_(
564 always_require_handshake_confirmation
),
565 disable_connection_pooling_(disable_connection_pooling
),
566 load_server_info_timeout_ms_(load_server_info_timeout
),
567 disable_loading_server_info_for_new_servers_(
568 disable_loading_server_info_for_new_servers
),
569 port_seed_(random_generator_
->RandUint64()),
570 check_persisted_supports_quic_(true),
571 task_runner_(nullptr),
572 weak_factory_(this) {
573 DCHECK(transport_security_state_
);
574 crypto_config_
.set_user_agent_id(user_agent_id
);
575 crypto_config_
.AddCanonicalSuffix(".c.youtube.com");
576 crypto_config_
.AddCanonicalSuffix(".googlevideo.com");
577 crypto_config_
.SetProofVerifier(
578 new ProofVerifierChromium(cert_verifier
, transport_security_state
));
579 crypto_config_
.SetChannelIDSource(
580 new ChannelIDSourceChromium(channel_id_service
));
582 if (cpu
.has_aesni() && cpu
.has_avx())
583 crypto_config_
.PreferAesGcm();
584 if (!IsEcdsaSupported())
585 crypto_config_
.DisableEcdsa();
588 QuicStreamFactory::~QuicStreamFactory() {
589 CloseAllSessions(ERR_ABORTED
);
590 while (!all_sessions_
.empty()) {
591 delete all_sessions_
.begin()->first
;
592 all_sessions_
.erase(all_sessions_
.begin());
594 STLDeleteValues(&active_jobs_
);
597 void QuicStreamFactory::set_require_confirmation(bool require_confirmation
) {
598 require_confirmation_
= require_confirmation
;
599 if (http_server_properties_
&& (!(local_address_
== IPEndPoint()))) {
600 // TODO(rtenneti): Delete host_port_pair and persist data in globals.
601 HostPortPair
host_port_pair(kDummyHostname
, kDummyPort
);
602 http_server_properties_
->SetSupportsQuic(
603 host_port_pair
, !require_confirmation
,
604 local_address_
.ToStringWithoutPort());
608 int QuicStreamFactory::Create(const HostPortPair
& host_port_pair
,
610 PrivacyMode privacy_mode
,
611 base::StringPiece method
,
612 const BoundNetLog
& net_log
,
613 QuicStreamRequest
* request
) {
614 QuicServerId
server_id(host_port_pair
, is_https
, privacy_mode
);
615 if (HasActiveSession(server_id
)) {
616 request
->set_stream(CreateIfSessionExists(server_id
, net_log
));
620 if (HasActiveJob(server_id
)) {
621 Job
* job
= active_jobs_
[server_id
];
622 active_requests_
[request
] = job
;
623 job_requests_map_
[job
].insert(request
);
624 return ERR_IO_PENDING
;
627 QuicServerInfo
* quic_server_info
= nullptr;
628 if (quic_server_info_factory_
) {
629 bool load_from_disk_cache
= true;
630 if (disable_loading_server_info_for_new_servers_
) {
631 const AlternateProtocolMap
& alternate_protocol_map
=
632 http_server_properties_
->alternate_protocol_map();
633 AlternateProtocolMap::const_iterator it
=
634 alternate_protocol_map
.Peek(server_id
.host_port_pair());
635 if (it
== alternate_protocol_map
.end() || it
->second
.protocol
!= QUIC
) {
636 // If there is no entry for QUIC, consider that as a new server and
637 // don't wait for Cache thread to load the data for that server.
638 load_from_disk_cache
= false;
641 if (load_from_disk_cache
) {
642 QuicCryptoClientConfig::CachedState
* cached
=
643 crypto_config_
.LookupOrCreate(server_id
);
645 if (cached
->IsEmpty()) {
646 quic_server_info
= quic_server_info_factory_
->GetForServer(server_id
);
650 // TODO(rtenneti): Initialize task_runner_ in the constructor after
651 // WebRequestActionWithThreadsTest.* tests are fixed.
653 task_runner_
= base::MessageLoop::current()->message_loop_proxy().get();
655 bool was_alternate_protocol_recently_broken
=
656 http_server_properties_
&&
657 http_server_properties_
->WasAlternateProtocolRecentlyBroken(
658 server_id
.host_port_pair());
659 scoped_ptr
<Job
> job(new Job(this, host_resolver_
, host_port_pair
, is_https
,
660 was_alternate_protocol_recently_broken
,
661 privacy_mode
, method
, quic_server_info
, net_log
));
662 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
663 base::Unretained(this), job
.get()));
665 if (rv
== ERR_IO_PENDING
) {
666 active_requests_
[request
] = job
.get();
667 job_requests_map_
[job
.get()].insert(request
);
668 active_jobs_
[server_id
] = job
.release();
671 DCHECK(HasActiveSession(server_id
));
672 request
->set_stream(CreateIfSessionExists(server_id
, net_log
));
677 bool QuicStreamFactory::OnResolution(
678 const QuicServerId
& server_id
,
679 const AddressList
& address_list
) {
680 DCHECK(!HasActiveSession(server_id
));
681 if (disable_connection_pooling_
) {
684 for (size_t i
= 0; i
< address_list
.size(); ++i
) {
685 const IPEndPoint
& address
= address_list
[i
];
686 const IpAliasKey
ip_alias_key(address
, server_id
.is_https());
687 if (!ContainsKey(ip_aliases_
, ip_alias_key
))
690 const SessionSet
& sessions
= ip_aliases_
[ip_alias_key
];
691 for (SessionSet::const_iterator i
= sessions
.begin();
692 i
!= sessions
.end(); ++i
) {
693 QuicClientSession
* session
= *i
;
694 if (!session
->CanPool(server_id
.host()))
696 active_sessions_
[server_id
] = session
;
697 session_aliases_
[session
].insert(server_id
);
704 void QuicStreamFactory::OnJobComplete(Job
* job
, int rv
) {
706 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
707 tracked_objects::ScopedTracker
tracking_profile1(
708 FROM_HERE_WITH_EXPLICIT_FUNCTION(
709 "422516 QuicStreamFactory::OnJobComplete1"));
711 if (!always_require_handshake_confirmation_
)
712 set_require_confirmation(false);
714 // Create all the streams, but do not notify them yet.
715 for (RequestSet::iterator it
= job_requests_map_
[job
].begin();
716 it
!= job_requests_map_
[job
].end() ; ++it
) {
717 DCHECK(HasActiveSession(job
->server_id()));
718 (*it
)->set_stream(CreateIfSessionExists(job
->server_id(),
723 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
724 tracked_objects::ScopedTracker
tracking_profile2(
725 FROM_HERE_WITH_EXPLICIT_FUNCTION(
726 "422516 QuicStreamFactory::OnJobComplete2"));
728 while (!job_requests_map_
[job
].empty()) {
729 RequestSet::iterator it
= job_requests_map_
[job
].begin();
730 QuicStreamRequest
* request
= *it
;
731 job_requests_map_
[job
].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 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
740 tracked_objects::ScopedTracker
tracking_profile3(
741 FROM_HERE_WITH_EXPLICIT_FUNCTION(
742 "422516 QuicStreamFactory::OnJobComplete3"));
744 active_jobs_
.erase(job
->server_id());
745 job_requests_map_
.erase(job
);
750 // Returns a newly created QuicHttpStream owned by the caller, if a
751 // matching session already exists. Returns nullptr otherwise.
752 scoped_ptr
<QuicHttpStream
> QuicStreamFactory::CreateIfSessionExists(
753 const QuicServerId
& server_id
,
754 const BoundNetLog
& net_log
) {
755 if (!HasActiveSession(server_id
)) {
756 DVLOG(1) << "No active session";
757 return scoped_ptr
<QuicHttpStream
>();
760 QuicClientSession
* session
= active_sessions_
[server_id
];
762 return scoped_ptr
<QuicHttpStream
>(
763 new QuicHttpStream(session
->GetWeakPtr()));
766 void QuicStreamFactory::OnIdleSession(QuicClientSession
* session
) {
769 void QuicStreamFactory::OnSessionGoingAway(QuicClientSession
* session
) {
770 const AliasSet
& aliases
= session_aliases_
[session
];
771 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
773 DCHECK(active_sessions_
.count(*it
));
774 DCHECK_EQ(session
, active_sessions_
[*it
]);
775 // Track sessions which have recently gone away so that we can disable
777 if (session
->goaway_received()) {
778 gone_away_aliases_
.insert(*it
);
781 active_sessions_
.erase(*it
);
782 ProcessGoingAwaySession(session
, *it
, true);
784 ProcessGoingAwaySession(session
, all_sessions_
[session
], false);
785 if (!aliases
.empty()) {
786 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
787 aliases
.begin()->is_https());
788 ip_aliases_
[ip_alias_key
].erase(session
);
789 if (ip_aliases_
[ip_alias_key
].empty()) {
790 ip_aliases_
.erase(ip_alias_key
);
793 session_aliases_
.erase(session
);
796 void QuicStreamFactory::OnSessionClosed(QuicClientSession
* session
) {
797 DCHECK_EQ(0u, session
->GetNumOpenStreams());
798 OnSessionGoingAway(session
);
800 all_sessions_
.erase(session
);
803 void QuicStreamFactory::OnSessionConnectTimeout(
804 QuicClientSession
* session
) {
805 const AliasSet
& aliases
= session_aliases_
[session
];
806 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
808 DCHECK(active_sessions_
.count(*it
));
809 DCHECK_EQ(session
, active_sessions_
[*it
]);
810 active_sessions_
.erase(*it
);
813 if (aliases
.empty()) {
817 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
818 aliases
.begin()->is_https());
819 ip_aliases_
[ip_alias_key
].erase(session
);
820 if (ip_aliases_
[ip_alias_key
].empty()) {
821 ip_aliases_
.erase(ip_alias_key
);
823 QuicServerId server_id
= *aliases
.begin();
824 session_aliases_
.erase(session
);
825 Job
* job
= new Job(this, host_resolver_
, session
, server_id
);
826 active_jobs_
[server_id
] = job
;
827 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
828 base::Unretained(this), job
));
829 DCHECK_EQ(ERR_IO_PENDING
, rv
);
832 void QuicStreamFactory::CancelRequest(QuicStreamRequest
* request
) {
833 DCHECK(ContainsKey(active_requests_
, request
));
834 Job
* job
= active_requests_
[request
];
835 job_requests_map_
[job
].erase(request
);
836 active_requests_
.erase(request
);
839 void QuicStreamFactory::CloseAllSessions(int error
) {
840 while (!active_sessions_
.empty()) {
841 size_t initial_size
= active_sessions_
.size();
842 active_sessions_
.begin()->second
->CloseSessionOnError(error
);
843 DCHECK_NE(initial_size
, active_sessions_
.size());
845 while (!all_sessions_
.empty()) {
846 size_t initial_size
= all_sessions_
.size();
847 all_sessions_
.begin()->first
->CloseSessionOnError(error
);
848 DCHECK_NE(initial_size
, all_sessions_
.size());
850 DCHECK(all_sessions_
.empty());
853 base::Value
* QuicStreamFactory::QuicStreamFactoryInfoToValue() const {
854 base::ListValue
* list
= new base::ListValue();
856 for (SessionMap::const_iterator it
= active_sessions_
.begin();
857 it
!= active_sessions_
.end(); ++it
) {
858 const QuicServerId
& server_id
= it
->first
;
859 QuicClientSession
* session
= it
->second
;
860 const AliasSet
& aliases
= session_aliases_
.find(session
)->second
;
861 // Only add a session to the list once.
862 if (server_id
== *aliases
.begin()) {
863 std::set
<HostPortPair
> hosts
;
864 for (AliasSet::const_iterator alias_it
= aliases
.begin();
865 alias_it
!= aliases
.end(); ++alias_it
) {
866 hosts
.insert(alias_it
->host_port_pair());
868 list
->Append(session
->GetInfoAsValue(hosts
));
874 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
875 crypto_config_
.ClearCachedStates();
878 void QuicStreamFactory::OnIPAddressChanged() {
879 CloseAllSessions(ERR_NETWORK_CHANGED
);
880 set_require_confirmation(true);
883 void QuicStreamFactory::OnCertAdded(const X509Certificate
* cert
) {
884 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
887 void QuicStreamFactory::OnCACertChanged(const X509Certificate
* cert
) {
888 // We should flush the sessions if we removed trust from a
889 // cert, because a previously trusted server may have become
892 // We should not flush the sessions if we added trust to a cert.
894 // Since the OnCACertChanged method doesn't tell us what
895 // kind of change it is, we have to flush the socket
897 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
900 bool QuicStreamFactory::HasActiveSession(
901 const QuicServerId
& server_id
) const {
902 return ContainsKey(active_sessions_
, server_id
);
905 int QuicStreamFactory::CreateSession(
906 const QuicServerId
& server_id
,
907 scoped_ptr
<QuicServerInfo
> server_info
,
908 const AddressList
& address_list
,
909 const BoundNetLog
& net_log
,
910 QuicClientSession
** session
) {
911 bool enable_port_selection
= enable_port_selection_
;
912 if (enable_port_selection
&&
913 ContainsKey(gone_away_aliases_
, server_id
)) {
914 // Disable port selection when the server is going away.
915 // There is no point in trying to return to the same server, if
916 // that server is no longer handling requests.
917 enable_port_selection
= false;
918 gone_away_aliases_
.erase(server_id
);
921 QuicConnectionId connection_id
= random_generator_
->RandUint64();
922 IPEndPoint addr
= *address_list
.begin();
923 scoped_refptr
<PortSuggester
> port_suggester
=
924 new PortSuggester(server_id
.host_port_pair(), port_seed_
);
925 DatagramSocket::BindType bind_type
= enable_port_selection
?
926 DatagramSocket::RANDOM_BIND
: // Use our callback.
927 DatagramSocket::DEFAULT_BIND
; // Use OS to randomize.
928 scoped_ptr
<DatagramClientSocket
> socket(
929 client_socket_factory_
->CreateDatagramClientSocket(
931 base::Bind(&PortSuggester::SuggestPort
, port_suggester
),
932 net_log
.net_log(), net_log
.source()));
933 int rv
= socket
->Connect(addr
);
935 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET
);
938 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested",
939 port_suggester
->call_count());
940 if (enable_port_selection
) {
941 DCHECK_LE(1u, port_suggester
->call_count());
943 DCHECK_EQ(0u, port_suggester
->call_count());
946 // We should adaptively set this buffer size, but for now, we'll use a size
947 // that is more than large enough for a full receive window, and yet
948 // does not consume "too much" memory. If we see bursty packet loss, we may
949 // revisit this setting and test for its impact.
950 const int32 kSocketBufferSize
=
951 static_cast<int32
>(TcpReceiver::kReceiveWindowTCP
);
952 rv
= socket
->SetReceiveBufferSize(kSocketBufferSize
);
954 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER
);
957 // Set a buffer large enough to contain the initial CWND's worth of packet
958 // to work around the problem with CHLO packets being sent out with the
959 // wrong encryption level, when the send buffer is full.
960 rv
= socket
->SetSendBufferSize(kMaxPacketSize
* 20);
962 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER
);
966 socket
->GetLocalAddress(&local_address_
);
967 if (check_persisted_supports_quic_
&& http_server_properties_
) {
968 check_persisted_supports_quic_
= false;
969 // TODO(rtenneti): Delete host_port_pair and persist data in globals.
970 HostPortPair
host_port_pair(kDummyHostname
, kDummyPort
);
971 SupportsQuic
supports_quic(true, local_address_
.ToStringWithoutPort());
972 if (http_server_properties_
->GetSupportsQuic(
973 host_port_pair
).Equals(supports_quic
)) {
974 require_confirmation_
= false;
978 DefaultPacketWriterFactory
packet_writer_factory(socket
.get());
980 if (!helper_
.get()) {
981 helper_
.reset(new QuicConnectionHelper(
982 base::MessageLoop::current()->message_loop_proxy().get(),
983 clock_
.get(), random_generator_
));
986 QuicConnection
* connection
= new QuicConnection(connection_id
,
989 packet_writer_factory
,
990 true /* owns_writer */,
991 false /* is_server */,
992 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
.set_max_undecryptable_packets(kMaxUndecryptablePackets
);
1000 config
.SetInitialFlowControlWindowToSend(kInitialReceiveWindowSize
);
1001 config
.SetInitialStreamFlowControlWindowToSend(kInitialReceiveWindowSize
);
1002 config
.SetInitialSessionFlowControlWindowToSend(kInitialReceiveWindowSize
);
1003 if (http_server_properties_
) {
1004 const HttpServerProperties::NetworkStats
* stats
=
1005 http_server_properties_
->GetServerNetworkStats(
1006 server_id
.host_port_pair());
1007 if (stats
!= nullptr) {
1008 config
.SetInitialRoundTripTimeUsToSend(
1009 static_cast<uint32
>(stats
->srtt
.InMicroseconds()));
1013 if (quic_server_info_factory_
&& !server_info
) {
1014 // Start the disk cache loading so that we can persist the newer QUIC server
1015 // information and/or inform the disk cache that we have reused
1017 server_info
.reset(quic_server_info_factory_
->GetForServer(server_id
));
1018 server_info
->Start();
1021 *session
= new QuicClientSession(
1022 connection
, socket
.Pass(), this, transport_security_state_
,
1023 server_info
.Pass(), config
,
1024 base::MessageLoop::current()->message_loop_proxy().get(),
1026 all_sessions_
[*session
] = server_id
; // owning pointer
1027 (*session
)->InitializeSession(server_id
, &crypto_config_
,
1028 quic_crypto_client_stream_factory_
);
1029 bool closed_during_initialize
=
1030 !ContainsKey(all_sessions_
, *session
) ||
1031 !(*session
)->connection()->connected();
1032 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedDuringInitializeSession",
1033 closed_during_initialize
);
1034 if (closed_during_initialize
) {
1035 DLOG(DFATAL
) << "Session closed during initialize";
1037 return ERR_CONNECTION_CLOSED
;
1042 bool QuicStreamFactory::HasActiveJob(const QuicServerId
& key
) const {
1043 return ContainsKey(active_jobs_
, key
);
1046 void QuicStreamFactory::ActivateSession(
1047 const QuicServerId
& server_id
,
1048 QuicClientSession
* session
) {
1049 DCHECK(!HasActiveSession(server_id
));
1050 UMA_HISTOGRAM_COUNTS("Net.QuicActiveSessions", active_sessions_
.size());
1051 active_sessions_
[server_id
] = session
;
1052 session_aliases_
[session
].insert(server_id
);
1053 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
1054 server_id
.is_https());
1055 DCHECK(!ContainsKey(ip_aliases_
[ip_alias_key
], session
));
1056 ip_aliases_
[ip_alias_key
].insert(session
);
1059 void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
1060 const QuicServerId
& server_id
,
1061 const scoped_ptr
<QuicServerInfo
>& server_info
) {
1062 // |server_info| will be NULL, if a non-empty server config already exists in
1063 // the memory cache. This is a minor optimization to avoid LookupOrCreate.
1067 QuicCryptoClientConfig::CachedState
* cached
=
1068 crypto_config_
.LookupOrCreate(server_id
);
1069 if (!cached
->IsEmpty())
1072 if (http_server_properties_
) {
1073 if (quic_supported_servers_at_startup_
.empty()) {
1074 for (const std::pair
<net::HostPortPair
, net::AlternateProtocolInfo
>&
1075 key_value
: http_server_properties_
->alternate_protocol_map()) {
1076 if (key_value
.second
.protocol
== QUIC
) {
1077 quic_supported_servers_at_startup_
.insert(key_value
.first
);
1082 // TODO(rtenneti): Delete the following histogram after collecting stats.
1083 // If the AlternateProtocolMap contained an entry for this host, check if
1084 // the disk cache contained an entry for it.
1085 if (ContainsKey(quic_supported_servers_at_startup_
,
1086 server_id
.host_port_pair())) {
1087 UMA_HISTOGRAM_BOOLEAN(
1088 "Net.QuicServerInfo.ExpectConfigMissingFromDiskCache",
1089 server_info
->state().server_config
.empty());
1093 if (!cached
->Initialize(server_info
->state().server_config
,
1094 server_info
->state().source_address_token
,
1095 server_info
->state().certs
,
1096 server_info
->state().server_config_sig
,
1100 if (!server_id
.is_https()) {
1101 // Don't check the certificates for insecure QUIC.
1102 cached
->SetProofValid();
1106 void QuicStreamFactory::ProcessGoingAwaySession(
1107 QuicClientSession
* session
,
1108 const QuicServerId
& server_id
,
1109 bool session_was_active
) {
1110 if (!http_server_properties_
)
1113 const QuicConnectionStats
& stats
= session
->connection()->GetStats();
1114 if (session
->IsCryptoHandshakeConfirmed()) {
1115 HttpServerProperties::NetworkStats network_stats
;
1116 network_stats
.srtt
= base::TimeDelta::FromMicroseconds(stats
.srtt_us
);
1117 network_stats
.bandwidth_estimate
= stats
.estimated_bandwidth
;
1118 http_server_properties_
->SetServerNetworkStats(server_id
.host_port_pair(),
1123 UMA_HISTOGRAM_COUNTS("Net.QuicHandshakeNotConfirmedNumPacketsReceived",
1124 stats
.packets_received
);
1126 if (!session_was_active
)
1129 const HostPortPair
& server
= server_id
.host_port_pair();
1130 // Don't try to change the alternate-protocol state, if the
1131 // alternate-protocol state is unknown.
1132 if (!http_server_properties_
->HasAlternateProtocol(server
))
1135 // TODO(rch): In the special case where the session has received no
1136 // packets from the peer, we should consider blacklisting this
1137 // differently so that we still race TCP but we don't consider the
1138 // session connected until the handshake has been confirmed.
1139 HistogramBrokenAlternateProtocolLocation(
1140 BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY
);
1141 AlternateProtocolInfo alternate
=
1142 http_server_properties_
->GetAlternateProtocol(server
);
1143 DCHECK_EQ(QUIC
, alternate
.protocol
);
1145 // Since the session was active, there's no longer an
1146 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the
1147 // TCP job also fails. So to avoid not using QUIC when we otherwise could,
1148 // we mark it as broken, and then immediately re-enable it. This leaves
1149 // QUIC as "recently broken" which means that 0-RTT will be disabled but
1150 // we'll still race.
1151 http_server_properties_
->SetBrokenAlternateProtocol(server
);
1152 http_server_properties_
->ClearAlternateProtocol(server
);
1153 http_server_properties_
->SetAlternateProtocol(
1154 server
, alternate
.port
, alternate
.protocol
, 1);
1156 http_server_properties_
->GetAlternateProtocol(server
).protocol
);
1157 DCHECK(http_server_properties_
->WasAlternateProtocolRecentlyBroken(