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/rand_util.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_util.h"
16 #include "base/values.h"
17 #include "net/base/net_errors.h"
18 #include "net/cert/cert_verifier.h"
19 #include "net/dns/host_resolver.h"
20 #include "net/dns/single_request_host_resolver.h"
21 #include "net/http/http_server_properties.h"
22 #include "net/quic/congestion_control/tcp_receiver.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_http_stream.h"
35 #include "net/quic/quic_protocol.h"
36 #include "net/quic/quic_server_id.h"
37 #include "net/socket/client_socket_factory.h"
40 #include "base/win/windows_version.h"
50 enum CreateSessionFailure
{
51 CREATION_ERROR_CONNECTING_SOCKET
,
52 CREATION_ERROR_SETTING_RECEIVE_BUFFER
,
53 CREATION_ERROR_SETTING_SEND_BUFFER
,
57 // When a connection is idle for 30 seconds it will be closed.
58 const int kIdleConnectionTimeoutSeconds
= 30;
60 // The initial receive window size for both streams and sessions.
61 const int32 kInitialReceiveWindowSize
= 10 * 1024 * 1024; // 10MB
63 // Set the maximum number of undecryptable packets the connection will store.
64 const int32 kMaxUndecryptablePackets
= 100;
66 const char kDummyHostname
[] = "quic.global.props";
67 const uint16 kDummyPort
= 0;
69 void HistogramCreateSessionFailure(enum CreateSessionFailure error
) {
70 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error
,
74 bool IsEcdsaSupported() {
76 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
83 QuicConfig
InitializeQuicConfig(const QuicTagVector
& connection_options
) {
85 config
.SetIdleConnectionStateLifetime(
86 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
),
87 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
));
88 config
.SetConnectionOptionsToSend(connection_options
);
92 class DefaultPacketWriterFactory
: public QuicConnection::PacketWriterFactory
{
94 explicit DefaultPacketWriterFactory(DatagramClientSocket
* socket
)
96 ~DefaultPacketWriterFactory() override
{}
98 QuicPacketWriter
* Create(QuicConnection
* connection
) const override
;
101 DatagramClientSocket
* socket_
;
104 QuicPacketWriter
* DefaultPacketWriterFactory::Create(
105 QuicConnection
* connection
) const {
106 scoped_ptr
<QuicDefaultPacketWriter
> writer(
107 new QuicDefaultPacketWriter(socket_
));
108 writer
->SetConnection(connection
);
109 return writer
.release();
114 QuicStreamFactory::IpAliasKey::IpAliasKey() {}
116 QuicStreamFactory::IpAliasKey::IpAliasKey(IPEndPoint ip_endpoint
,
118 : ip_endpoint(ip_endpoint
),
119 is_https(is_https
) {}
121 QuicStreamFactory::IpAliasKey::~IpAliasKey() {}
123 bool QuicStreamFactory::IpAliasKey::operator<(
124 const QuicStreamFactory::IpAliasKey
& other
) const {
125 if (!(ip_endpoint
== other
.ip_endpoint
)) {
126 return ip_endpoint
< other
.ip_endpoint
;
128 return is_https
< other
.is_https
;
131 bool QuicStreamFactory::IpAliasKey::operator==(
132 const QuicStreamFactory::IpAliasKey
& other
) const {
133 return is_https
== other
.is_https
&&
134 ip_endpoint
== other
.ip_endpoint
;
137 // Responsible for creating a new QUIC session to the specified server, and
138 // for notifying any associated requests when complete.
139 class QuicStreamFactory::Job
{
141 Job(QuicStreamFactory
* factory
,
142 HostResolver
* host_resolver
,
143 const HostPortPair
& host_port_pair
,
145 bool was_alternate_protocol_recently_broken
,
146 PrivacyMode privacy_mode
,
147 base::StringPiece method
,
148 QuicServerInfo
* server_info
,
149 const BoundNetLog
& net_log
);
151 // Creates a new job to handle the resumption of for connecting an
153 Job(QuicStreamFactory
* factory
,
154 HostResolver
* host_resolver
,
155 QuicClientSession
* session
,
156 QuicServerId server_id
);
160 int Run(const CompletionCallback
& callback
);
164 int DoResolveHostComplete(int rv
);
165 int DoLoadServerInfo();
166 int DoLoadServerInfoComplete(int rv
);
168 int DoResumeConnect();
169 int DoConnectComplete(int rv
);
171 void OnIOComplete(int rv
);
173 void CancelWaitForDataReadyCallback();
175 CompletionCallback
callback() {
179 const QuicServerId
server_id() const {
187 STATE_RESOLVE_HOST_COMPLETE
,
188 STATE_LOAD_SERVER_INFO
,
189 STATE_LOAD_SERVER_INFO_COMPLETE
,
191 STATE_RESUME_CONNECT
,
192 STATE_CONNECT_COMPLETE
,
196 QuicStreamFactory
* factory_
;
197 SingleRequestHostResolver host_resolver_
;
198 QuicServerId server_id_
;
200 bool was_alternate_protocol_recently_broken_
;
201 scoped_ptr
<QuicServerInfo
> server_info_
;
202 const BoundNetLog net_log_
;
203 QuicClientSession
* session_
;
204 CompletionCallback callback_
;
205 AddressList address_list_
;
206 base::TimeTicks disk_cache_load_start_time_
;
207 base::TimeTicks dns_resolution_start_time_
;
208 base::WeakPtrFactory
<Job
> weak_factory_
;
209 DISALLOW_COPY_AND_ASSIGN(Job
);
212 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
213 HostResolver
* host_resolver
,
214 const HostPortPair
& host_port_pair
,
216 bool was_alternate_protocol_recently_broken
,
217 PrivacyMode privacy_mode
,
218 base::StringPiece method
,
219 QuicServerInfo
* server_info
,
220 const BoundNetLog
& net_log
)
221 : io_state_(STATE_RESOLVE_HOST
),
223 host_resolver_(host_resolver
),
224 server_id_(host_port_pair
, is_https
, privacy_mode
),
225 is_post_(method
== "POST"),
226 was_alternate_protocol_recently_broken_(
227 was_alternate_protocol_recently_broken
),
228 server_info_(server_info
),
231 weak_factory_(this) {}
233 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
234 HostResolver
* host_resolver
,
235 QuicClientSession
* session
,
236 QuicServerId server_id
)
237 : io_state_(STATE_RESUME_CONNECT
),
239 host_resolver_(host_resolver
), // unused
240 server_id_(server_id
),
241 is_post_(false), // unused
242 was_alternate_protocol_recently_broken_(false), // unused
243 net_log_(session
->net_log()), // unused
245 weak_factory_(this) {}
247 QuicStreamFactory::Job::~Job() {
250 int QuicStreamFactory::Job::Run(const CompletionCallback
& callback
) {
252 if (rv
== ERR_IO_PENDING
)
253 callback_
= callback
;
255 return rv
> 0 ? OK
: rv
;
258 int QuicStreamFactory::Job::DoLoop(int rv
) {
260 IoState state
= io_state_
;
261 io_state_
= STATE_NONE
;
263 case STATE_RESOLVE_HOST
:
265 rv
= DoResolveHost();
267 case STATE_RESOLVE_HOST_COMPLETE
:
268 rv
= DoResolveHostComplete(rv
);
270 case STATE_LOAD_SERVER_INFO
:
272 rv
= DoLoadServerInfo();
274 case STATE_LOAD_SERVER_INFO_COMPLETE
:
275 rv
= DoLoadServerInfoComplete(rv
);
281 case STATE_RESUME_CONNECT
:
283 rv
= DoResumeConnect();
285 case STATE_CONNECT_COMPLETE
:
286 rv
= DoConnectComplete(rv
);
289 NOTREACHED() << "io_state_: " << io_state_
;
292 } while (io_state_
!= STATE_NONE
&& rv
!= ERR_IO_PENDING
);
296 void QuicStreamFactory::Job::OnIOComplete(int rv
) {
299 if (rv
!= ERR_IO_PENDING
&& !callback_
.is_null()) {
304 void QuicStreamFactory::Job::CancelWaitForDataReadyCallback() {
305 // If we are waiting for WaitForDataReadyCallback, then cancel the callback.
306 if (io_state_
!= STATE_LOAD_SERVER_INFO_COMPLETE
)
308 server_info_
->CancelWaitForDataReadyCallback();
312 int QuicStreamFactory::Job::DoResolveHost() {
313 // Start loading the data now, and wait for it after we resolve the host.
315 server_info_
->Start();
318 io_state_
= STATE_RESOLVE_HOST_COMPLETE
;
319 dns_resolution_start_time_
= base::TimeTicks::Now();
320 return host_resolver_
.Resolve(
321 HostResolver::RequestInfo(server_id_
.host_port_pair()),
324 base::Bind(&QuicStreamFactory::Job::OnIOComplete
,
325 weak_factory_
.GetWeakPtr()),
329 int QuicStreamFactory::Job::DoResolveHostComplete(int rv
) {
330 UMA_HISTOGRAM_TIMES("Net.QuicSession.HostResolutionTime",
331 base::TimeTicks::Now() - dns_resolution_start_time_
);
335 DCHECK(!factory_
->HasActiveSession(server_id_
));
337 // Inform the factory of this resolution, which will set up
338 // a session alias, if possible.
339 if (factory_
->OnResolution(server_id_
, address_list_
)) {
343 io_state_
= STATE_LOAD_SERVER_INFO
;
347 int QuicStreamFactory::Job::DoLoadServerInfo() {
348 io_state_
= STATE_LOAD_SERVER_INFO_COMPLETE
;
353 // To mitigate the effects of disk cache taking too long to load QUIC server
354 // information, set up a timer to cancel WaitForDataReady's callback.
355 if (factory_
->load_server_info_timeout_ms_
> 0) {
356 factory_
->task_runner_
->PostDelayedTask(
358 base::Bind(&QuicStreamFactory::Job::CancelWaitForDataReadyCallback
,
359 weak_factory_
.GetWeakPtr()),
360 base::TimeDelta::FromMilliseconds(
361 factory_
->load_server_info_timeout_ms_
));
364 disk_cache_load_start_time_
= base::TimeTicks::Now();
365 return server_info_
->WaitForDataReady(
366 base::Bind(&QuicStreamFactory::Job::OnIOComplete
,
367 weak_factory_
.GetWeakPtr()));
370 int QuicStreamFactory::Job::DoLoadServerInfoComplete(int rv
) {
372 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheWaitForDataReadyTime",
373 base::TimeTicks::Now() - disk_cache_load_start_time_
);
377 server_info_
.reset();
380 io_state_
= STATE_CONNECT
;
384 int QuicStreamFactory::Job::DoConnect() {
385 io_state_
= STATE_CONNECT_COMPLETE
;
387 int rv
= factory_
->CreateSession(server_id_
, server_info_
.Pass(),
388 address_list_
, net_log_
, &session_
);
390 DCHECK(rv
!= ERR_IO_PENDING
);
395 if (!session_
->connection()->connected()) {
396 return ERR_CONNECTION_CLOSED
;
399 session_
->StartReading();
400 if (!session_
->connection()->connected()) {
401 return ERR_QUIC_PROTOCOL_ERROR
;
403 bool require_confirmation
=
404 factory_
->require_confirmation() || is_post_
||
405 was_alternate_protocol_recently_broken_
;
406 rv
= session_
->CryptoConnect(
407 require_confirmation
,
408 base::Bind(&QuicStreamFactory::Job::OnIOComplete
,
409 base::Unretained(this)));
413 int QuicStreamFactory::Job::DoResumeConnect() {
414 io_state_
= STATE_CONNECT_COMPLETE
;
416 int rv
= session_
->ResumeCryptoConnect(
417 base::Bind(&QuicStreamFactory::Job::OnIOComplete
,
418 base::Unretained(this)));
423 int QuicStreamFactory::Job::DoConnectComplete(int rv
) {
427 DCHECK(!factory_
->HasActiveSession(server_id_
));
428 // There may well now be an active session for this IP. If so, use the
429 // existing session instead.
430 AddressList
address(session_
->connection()->peer_address());
431 if (factory_
->OnResolution(server_id_
, address
)) {
432 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_IP_POOLED
);
437 factory_
->ActivateSession(server_id_
, session_
);
442 QuicStreamRequest::QuicStreamRequest(QuicStreamFactory
* factory
)
443 : factory_(factory
) {}
445 QuicStreamRequest::~QuicStreamRequest() {
446 if (factory_
&& !callback_
.is_null())
447 factory_
->CancelRequest(this);
450 int QuicStreamRequest::Request(const HostPortPair
& host_port_pair
,
452 PrivacyMode privacy_mode
,
453 base::StringPiece method
,
454 const BoundNetLog
& net_log
,
455 const CompletionCallback
& callback
) {
457 DCHECK(callback_
.is_null());
459 int rv
= factory_
->Create(host_port_pair
, is_https
, privacy_mode
, method
,
461 if (rv
== ERR_IO_PENDING
) {
462 host_port_pair_
= host_port_pair
;
463 is_https_
= is_https
;
465 callback_
= callback
;
474 void QuicStreamRequest::set_stream(scoped_ptr
<QuicHttpStream
> stream
) {
476 stream_
= stream
.Pass();
479 void QuicStreamRequest::OnRequestComplete(int rv
) {
484 scoped_ptr
<QuicHttpStream
> QuicStreamRequest::ReleaseStream() {
486 return stream_
.Pass();
489 QuicStreamFactory::QuicStreamFactory(
490 HostResolver
* host_resolver
,
491 ClientSocketFactory
* client_socket_factory
,
492 base::WeakPtr
<HttpServerProperties
> http_server_properties
,
493 CertVerifier
* cert_verifier
,
494 ChannelIDService
* channel_id_service
,
495 TransportSecurityState
* transport_security_state
,
496 QuicCryptoClientStreamFactory
* quic_crypto_client_stream_factory
,
497 QuicRandom
* random_generator
,
499 size_t max_packet_length
,
500 const std::string
& user_agent_id
,
501 const QuicVersionVector
& supported_versions
,
502 bool enable_port_selection
,
503 bool always_require_handshake_confirmation
,
504 bool disable_connection_pooling
,
505 int load_server_info_timeout
,
506 const QuicTagVector
& connection_options
)
507 : require_confirmation_(true),
508 host_resolver_(host_resolver
),
509 client_socket_factory_(client_socket_factory
),
510 http_server_properties_(http_server_properties
),
511 transport_security_state_(transport_security_state
),
512 quic_server_info_factory_(nullptr),
513 quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory
),
514 random_generator_(random_generator
),
516 max_packet_length_(max_packet_length
),
517 config_(InitializeQuicConfig(connection_options
)),
518 supported_versions_(supported_versions
),
519 enable_port_selection_(enable_port_selection
),
520 always_require_handshake_confirmation_(
521 always_require_handshake_confirmation
),
522 disable_connection_pooling_(disable_connection_pooling
),
523 load_server_info_timeout_ms_(load_server_info_timeout
),
524 port_seed_(random_generator_
->RandUint64()),
525 check_persisted_supports_quic_(true),
526 task_runner_(nullptr),
527 weak_factory_(this) {
528 DCHECK(transport_security_state_
);
529 crypto_config_
.set_user_agent_id(user_agent_id
);
530 crypto_config_
.AddCanonicalSuffix(".c.youtube.com");
531 crypto_config_
.AddCanonicalSuffix(".googlevideo.com");
532 crypto_config_
.SetProofVerifier(
533 new ProofVerifierChromium(cert_verifier
, transport_security_state
));
534 crypto_config_
.SetChannelIDSource(
535 new ChannelIDSourceChromium(channel_id_service
));
537 if (cpu
.has_aesni() && cpu
.has_avx())
538 crypto_config_
.PreferAesGcm();
539 if (!IsEcdsaSupported())
540 crypto_config_
.DisableEcdsa();
543 QuicStreamFactory::~QuicStreamFactory() {
544 CloseAllSessions(ERR_ABORTED
);
545 while (!all_sessions_
.empty()) {
546 delete all_sessions_
.begin()->first
;
547 all_sessions_
.erase(all_sessions_
.begin());
549 STLDeleteValues(&active_jobs_
);
552 void QuicStreamFactory::set_require_confirmation(bool require_confirmation
) {
553 require_confirmation_
= require_confirmation
;
554 if (http_server_properties_
&& (!(local_address_
== IPEndPoint()))) {
555 // TODO(rtenneti): Delete host_port_pair and persist data in globals.
556 HostPortPair
host_port_pair(kDummyHostname
, kDummyPort
);
557 http_server_properties_
->SetSupportsQuic(
558 host_port_pair
, !require_confirmation
,
559 local_address_
.ToStringWithoutPort());
563 int QuicStreamFactory::Create(const HostPortPair
& host_port_pair
,
565 PrivacyMode privacy_mode
,
566 base::StringPiece method
,
567 const BoundNetLog
& net_log
,
568 QuicStreamRequest
* request
) {
569 QuicServerId
server_id(host_port_pair
, is_https
, privacy_mode
);
570 if (HasActiveSession(server_id
)) {
571 request
->set_stream(CreateIfSessionExists(server_id
, net_log
));
575 if (HasActiveJob(server_id
)) {
576 Job
* job
= active_jobs_
[server_id
];
577 active_requests_
[request
] = job
;
578 job_requests_map_
[job
].insert(request
);
579 return ERR_IO_PENDING
;
582 QuicServerInfo
* quic_server_info
= nullptr;
583 if (quic_server_info_factory_
) {
584 QuicCryptoClientConfig::CachedState
* cached
=
585 crypto_config_
.LookupOrCreate(server_id
);
587 if (cached
->IsEmpty()) {
588 quic_server_info
= quic_server_info_factory_
->GetForServer(server_id
);
591 // TODO(rtenneti): Initialize task_runner_ in the constructor after
592 // WebRequestActionWithThreadsTest.* tests are fixed.
594 task_runner_
= base::MessageLoop::current()->message_loop_proxy().get();
596 bool was_alternate_protocol_recently_broken
=
597 http_server_properties_
&&
598 http_server_properties_
->WasAlternateProtocolRecentlyBroken(
599 server_id
.host_port_pair());
600 scoped_ptr
<Job
> job(new Job(this, host_resolver_
, host_port_pair
, is_https
,
601 was_alternate_protocol_recently_broken
,
602 privacy_mode
, method
, quic_server_info
, net_log
));
603 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
604 base::Unretained(this), job
.get()));
606 if (rv
== ERR_IO_PENDING
) {
607 active_requests_
[request
] = job
.get();
608 job_requests_map_
[job
.get()].insert(request
);
609 active_jobs_
[server_id
] = job
.release();
612 DCHECK(HasActiveSession(server_id
));
613 request
->set_stream(CreateIfSessionExists(server_id
, net_log
));
618 bool QuicStreamFactory::OnResolution(
619 const QuicServerId
& server_id
,
620 const AddressList
& address_list
) {
621 DCHECK(!HasActiveSession(server_id
));
622 if (disable_connection_pooling_
) {
625 for (size_t i
= 0; i
< address_list
.size(); ++i
) {
626 const IPEndPoint
& address
= address_list
[i
];
627 const IpAliasKey
ip_alias_key(address
, server_id
.is_https());
628 if (!ContainsKey(ip_aliases_
, ip_alias_key
))
631 const SessionSet
& sessions
= ip_aliases_
[ip_alias_key
];
632 for (SessionSet::const_iterator i
= sessions
.begin();
633 i
!= sessions
.end(); ++i
) {
634 QuicClientSession
* session
= *i
;
635 if (!session
->CanPool(server_id
.host()))
637 active_sessions_
[server_id
] = session
;
638 session_aliases_
[session
].insert(server_id
);
645 void QuicStreamFactory::OnJobComplete(Job
* job
, int rv
) {
647 if (!always_require_handshake_confirmation_
)
648 set_require_confirmation(false);
650 // Create all the streams, but do not notify them yet.
651 for (RequestSet::iterator it
= job_requests_map_
[job
].begin();
652 it
!= job_requests_map_
[job
].end() ; ++it
) {
653 DCHECK(HasActiveSession(job
->server_id()));
654 (*it
)->set_stream(CreateIfSessionExists(job
->server_id(),
658 while (!job_requests_map_
[job
].empty()) {
659 RequestSet::iterator it
= job_requests_map_
[job
].begin();
660 QuicStreamRequest
* request
= *it
;
661 job_requests_map_
[job
].erase(it
);
662 active_requests_
.erase(request
);
663 // Even though we're invoking callbacks here, we don't need to worry
664 // about |this| being deleted, because the factory is owned by the
665 // profile which can not be deleted via callbacks.
666 request
->OnRequestComplete(rv
);
668 active_jobs_
.erase(job
->server_id());
669 job_requests_map_
.erase(job
);
674 // Returns a newly created QuicHttpStream owned by the caller, if a
675 // matching session already exists. Returns nullptr otherwise.
676 scoped_ptr
<QuicHttpStream
> QuicStreamFactory::CreateIfSessionExists(
677 const QuicServerId
& server_id
,
678 const BoundNetLog
& net_log
) {
679 if (!HasActiveSession(server_id
)) {
680 DVLOG(1) << "No active session";
681 return scoped_ptr
<QuicHttpStream
>();
684 QuicClientSession
* session
= active_sessions_
[server_id
];
686 return scoped_ptr
<QuicHttpStream
>(
687 new QuicHttpStream(session
->GetWeakPtr()));
690 void QuicStreamFactory::OnIdleSession(QuicClientSession
* session
) {
693 void QuicStreamFactory::OnSessionGoingAway(QuicClientSession
* session
) {
694 const AliasSet
& aliases
= session_aliases_
[session
];
695 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
697 DCHECK(active_sessions_
.count(*it
));
698 DCHECK_EQ(session
, active_sessions_
[*it
]);
699 // Track sessions which have recently gone away so that we can disable
701 if (session
->goaway_received()) {
702 gone_away_aliases_
.insert(*it
);
705 active_sessions_
.erase(*it
);
706 ProcessGoingAwaySession(session
, *it
, true);
708 ProcessGoingAwaySession(session
, all_sessions_
[session
], false);
709 if (!aliases
.empty()) {
710 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
711 aliases
.begin()->is_https());
712 ip_aliases_
[ip_alias_key
].erase(session
);
713 if (ip_aliases_
[ip_alias_key
].empty()) {
714 ip_aliases_
.erase(ip_alias_key
);
717 session_aliases_
.erase(session
);
720 void QuicStreamFactory::OnSessionClosed(QuicClientSession
* session
) {
721 DCHECK_EQ(0u, session
->GetNumOpenStreams());
722 OnSessionGoingAway(session
);
724 all_sessions_
.erase(session
);
727 void QuicStreamFactory::OnSessionConnectTimeout(
728 QuicClientSession
* session
) {
729 const AliasSet
& aliases
= session_aliases_
[session
];
730 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
732 DCHECK(active_sessions_
.count(*it
));
733 DCHECK_EQ(session
, active_sessions_
[*it
]);
734 active_sessions_
.erase(*it
);
737 if (aliases
.empty()) {
741 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
742 aliases
.begin()->is_https());
743 ip_aliases_
[ip_alias_key
].erase(session
);
744 if (ip_aliases_
[ip_alias_key
].empty()) {
745 ip_aliases_
.erase(ip_alias_key
);
747 QuicServerId server_id
= *aliases
.begin();
748 session_aliases_
.erase(session
);
749 Job
* job
= new Job(this, host_resolver_
, session
, server_id
);
750 active_jobs_
[server_id
] = job
;
751 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
752 base::Unretained(this), job
));
753 DCHECK_EQ(ERR_IO_PENDING
, rv
);
756 void QuicStreamFactory::CancelRequest(QuicStreamRequest
* request
) {
757 DCHECK(ContainsKey(active_requests_
, request
));
758 Job
* job
= active_requests_
[request
];
759 job_requests_map_
[job
].erase(request
);
760 active_requests_
.erase(request
);
763 void QuicStreamFactory::CloseAllSessions(int error
) {
764 while (!active_sessions_
.empty()) {
765 size_t initial_size
= active_sessions_
.size();
766 active_sessions_
.begin()->second
->CloseSessionOnError(error
);
767 DCHECK_NE(initial_size
, active_sessions_
.size());
769 while (!all_sessions_
.empty()) {
770 size_t initial_size
= all_sessions_
.size();
771 all_sessions_
.begin()->first
->CloseSessionOnError(error
);
772 DCHECK_NE(initial_size
, all_sessions_
.size());
774 DCHECK(all_sessions_
.empty());
777 base::Value
* QuicStreamFactory::QuicStreamFactoryInfoToValue() const {
778 base::ListValue
* list
= new base::ListValue();
780 for (SessionMap::const_iterator it
= active_sessions_
.begin();
781 it
!= active_sessions_
.end(); ++it
) {
782 const QuicServerId
& server_id
= it
->first
;
783 QuicClientSession
* session
= it
->second
;
784 const AliasSet
& aliases
= session_aliases_
.find(session
)->second
;
785 // Only add a session to the list once.
786 if (server_id
== *aliases
.begin()) {
787 std::set
<HostPortPair
> hosts
;
788 for (AliasSet::const_iterator alias_it
= aliases
.begin();
789 alias_it
!= aliases
.end(); ++alias_it
) {
790 hosts
.insert(alias_it
->host_port_pair());
792 list
->Append(session
->GetInfoAsValue(hosts
));
798 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
799 crypto_config_
.ClearCachedStates();
802 void QuicStreamFactory::OnIPAddressChanged() {
803 CloseAllSessions(ERR_NETWORK_CHANGED
);
804 set_require_confirmation(true);
807 void QuicStreamFactory::OnCertAdded(const X509Certificate
* cert
) {
808 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
811 void QuicStreamFactory::OnCACertChanged(const X509Certificate
* cert
) {
812 // We should flush the sessions if we removed trust from a
813 // cert, because a previously trusted server may have become
816 // We should not flush the sessions if we added trust to a cert.
818 // Since the OnCACertChanged method doesn't tell us what
819 // kind of change it is, we have to flush the socket
821 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
824 bool QuicStreamFactory::HasActiveSession(
825 const QuicServerId
& server_id
) const {
826 return ContainsKey(active_sessions_
, server_id
);
829 int QuicStreamFactory::CreateSession(
830 const QuicServerId
& server_id
,
831 scoped_ptr
<QuicServerInfo
> server_info
,
832 const AddressList
& address_list
,
833 const BoundNetLog
& net_log
,
834 QuicClientSession
** session
) {
835 bool enable_port_selection
= enable_port_selection_
;
836 if (enable_port_selection
&&
837 ContainsKey(gone_away_aliases_
, server_id
)) {
838 // Disable port selection when the server is going away.
839 // There is no point in trying to return to the same server, if
840 // that server is no longer handling requests.
841 enable_port_selection
= false;
842 gone_away_aliases_
.erase(server_id
);
845 QuicConnectionId connection_id
= random_generator_
->RandUint64();
846 IPEndPoint addr
= *address_list
.begin();
847 scoped_refptr
<PortSuggester
> port_suggester
=
848 new PortSuggester(server_id
.host_port_pair(), port_seed_
);
849 DatagramSocket::BindType bind_type
= enable_port_selection
?
850 DatagramSocket::RANDOM_BIND
: // Use our callback.
851 DatagramSocket::DEFAULT_BIND
; // Use OS to randomize.
852 scoped_ptr
<DatagramClientSocket
> socket(
853 client_socket_factory_
->CreateDatagramClientSocket(
855 base::Bind(&PortSuggester::SuggestPort
, port_suggester
),
856 net_log
.net_log(), net_log
.source()));
857 int rv
= socket
->Connect(addr
);
859 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET
);
862 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested",
863 port_suggester
->call_count());
864 if (enable_port_selection
) {
865 DCHECK_LE(1u, port_suggester
->call_count());
867 DCHECK_EQ(0u, port_suggester
->call_count());
870 // We should adaptively set this buffer size, but for now, we'll use a size
871 // that is more than large enough for a full receive window, and yet
872 // does not consume "too much" memory. If we see bursty packet loss, we may
873 // revisit this setting and test for its impact.
874 const int32
kSocketBufferSize(TcpReceiver::kReceiveWindowTCP
);
875 rv
= socket
->SetReceiveBufferSize(kSocketBufferSize
);
877 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER
);
880 // Set a buffer large enough to contain the initial CWND's worth of packet
881 // to work around the problem with CHLO packets being sent out with the
882 // wrong encryption level, when the send buffer is full.
883 rv
= socket
->SetSendBufferSize(kMaxPacketSize
* 20);
885 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER
);
889 socket
->GetLocalAddress(&local_address_
);
890 if (check_persisted_supports_quic_
&& http_server_properties_
) {
891 check_persisted_supports_quic_
= false;
892 // TODO(rtenneti): Delete host_port_pair and persist data in globals.
893 HostPortPair
host_port_pair(kDummyHostname
, kDummyPort
);
894 SupportsQuic
supports_quic(true, local_address_
.ToStringWithoutPort());
895 if (http_server_properties_
->GetSupportsQuic(
896 host_port_pair
).Equals(supports_quic
)) {
897 require_confirmation_
= false;
901 DefaultPacketWriterFactory
packet_writer_factory(socket
.get());
903 if (!helper_
.get()) {
904 helper_
.reset(new QuicConnectionHelper(
905 base::MessageLoop::current()->message_loop_proxy().get(),
906 clock_
.get(), random_generator_
));
909 QuicConnection
* connection
= new QuicConnection(connection_id
,
912 packet_writer_factory
,
913 true /* owns_writer */,
914 false /* is_server */,
915 server_id
.is_https(),
916 supported_versions_
);
917 connection
->set_max_packet_length(max_packet_length_
);
919 InitializeCachedStateInCryptoConfig(server_id
, server_info
);
921 QuicConfig config
= config_
;
922 config
.set_max_undecryptable_packets(kMaxUndecryptablePackets
);
923 config
.SetInitialFlowControlWindowToSend(kInitialReceiveWindowSize
);
924 config
.SetInitialStreamFlowControlWindowToSend(kInitialReceiveWindowSize
);
925 config
.SetInitialSessionFlowControlWindowToSend(kInitialReceiveWindowSize
);
926 if (http_server_properties_
) {
927 const HttpServerProperties::NetworkStats
* stats
=
928 http_server_properties_
->GetServerNetworkStats(
929 server_id
.host_port_pair());
930 if (stats
!= nullptr) {
931 config
.SetInitialRoundTripTimeUsToSend(stats
->srtt
.InMicroseconds());
935 if (quic_server_info_factory_
&& !server_info
) {
936 // Start the disk cache loading so that we can persist the newer QUIC server
937 // information and/or inform the disk cache that we have reused
939 server_info
.reset(quic_server_info_factory_
->GetForServer(server_id
));
940 server_info
->Start();
943 *session
= new QuicClientSession(
944 connection
, socket
.Pass(), this, transport_security_state_
,
945 server_info
.Pass(), config
,
946 base::MessageLoop::current()->message_loop_proxy().get(),
948 all_sessions_
[*session
] = server_id
; // owning pointer
949 (*session
)->InitializeSession(server_id
, &crypto_config_
,
950 quic_crypto_client_stream_factory_
);
951 bool closed_during_initialize
=
952 !ContainsKey(all_sessions_
, *session
) ||
953 !(*session
)->connection()->connected();
954 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedDuringInitializeSession",
955 closed_during_initialize
);
956 if (closed_during_initialize
) {
957 DLOG(DFATAL
) << "Session closed during initialize";
959 return ERR_CONNECTION_CLOSED
;
964 bool QuicStreamFactory::HasActiveJob(const QuicServerId
& key
) const {
965 return ContainsKey(active_jobs_
, key
);
968 void QuicStreamFactory::ActivateSession(
969 const QuicServerId
& server_id
,
970 QuicClientSession
* session
) {
971 DCHECK(!HasActiveSession(server_id
));
972 UMA_HISTOGRAM_COUNTS("Net.QuicActiveSessions", active_sessions_
.size());
973 active_sessions_
[server_id
] = session
;
974 session_aliases_
[session
].insert(server_id
);
975 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
976 server_id
.is_https());
977 DCHECK(!ContainsKey(ip_aliases_
[ip_alias_key
], session
));
978 ip_aliases_
[ip_alias_key
].insert(session
);
981 void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
982 const QuicServerId
& server_id
,
983 const scoped_ptr
<QuicServerInfo
>& server_info
) {
984 // |server_info| will be NULL, if a non-empty server config already exists in
985 // the memory cache. This is a minor optimization to avoid LookupOrCreate.
989 QuicCryptoClientConfig::CachedState
* cached
=
990 crypto_config_
.LookupOrCreate(server_id
);
991 if (!cached
->IsEmpty())
994 if (http_server_properties_
) {
995 if (quic_supported_servers_at_startup_
.empty()) {
996 for (const std::pair
<net::HostPortPair
, net::AlternateProtocolInfo
>&
997 key_value
: http_server_properties_
->alternate_protocol_map()) {
998 if (key_value
.second
.protocol
== QUIC
) {
999 quic_supported_servers_at_startup_
.insert(key_value
.first
);
1004 // TODO(rtenneti): Delete the following histogram after collecting stats.
1005 // If the AlternateProtocolMap contained an entry for this host, check if
1006 // the disk cache contained an entry for it.
1007 if (ContainsKey(quic_supported_servers_at_startup_
,
1008 server_id
.host_port_pair())) {
1009 UMA_HISTOGRAM_BOOLEAN(
1010 "Net.QuicServerInfo.ExpectConfigMissingFromDiskCache",
1011 server_info
->state().server_config
.empty());
1015 if (!cached
->Initialize(server_info
->state().server_config
,
1016 server_info
->state().source_address_token
,
1017 server_info
->state().certs
,
1018 server_info
->state().server_config_sig
,
1022 if (!server_id
.is_https()) {
1023 // Don't check the certificates for insecure QUIC.
1024 cached
->SetProofValid();
1028 void QuicStreamFactory::ProcessGoingAwaySession(
1029 QuicClientSession
* session
,
1030 const QuicServerId
& server_id
,
1031 bool session_was_active
) {
1032 if (!http_server_properties_
)
1035 const QuicConnectionStats
& stats
= session
->connection()->GetStats();
1036 if (session
->IsCryptoHandshakeConfirmed()) {
1037 HttpServerProperties::NetworkStats network_stats
;
1038 network_stats
.srtt
= base::TimeDelta::FromMicroseconds(stats
.srtt_us
);
1039 network_stats
.bandwidth_estimate
= stats
.estimated_bandwidth
;
1040 http_server_properties_
->SetServerNetworkStats(server_id
.host_port_pair(),
1045 UMA_HISTOGRAM_COUNTS("Net.QuicHandshakeNotConfirmedNumPacketsReceived",
1046 stats
.packets_received
);
1048 if (!session_was_active
)
1051 const HostPortPair
& server
= server_id
.host_port_pair();
1052 // Don't try to change the alternate-protocol state, if the
1053 // alternate-protocol state is unknown.
1054 if (!http_server_properties_
->HasAlternateProtocol(server
))
1057 // TODO(rch): In the special case where the session has received no
1058 // packets from the peer, we should consider blacklisting this
1059 // differently so that we still race TCP but we don't consider the
1060 // session connected until the handshake has been confirmed.
1061 HistogramBrokenAlternateProtocolLocation(
1062 BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY
);
1063 AlternateProtocolInfo alternate
=
1064 http_server_properties_
->GetAlternateProtocol(server
);
1065 DCHECK_EQ(QUIC
, alternate
.protocol
);
1067 // Since the session was active, there's no longer an
1068 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the
1069 // TCP job also fails. So to avoid not using QUIC when we otherwise could,
1070 // we mark it as broken, and then immediately re-enable it. This leaves
1071 // QUIC as "recently broken" which means that 0-RTT will be disabled but
1072 // we'll still race.
1073 http_server_properties_
->SetBrokenAlternateProtocol(server
);
1074 http_server_properties_
->ClearAlternateProtocol(server
);
1075 http_server_properties_
->SetAlternateProtocol(
1076 server
, alternate
.port
, alternate
.protocol
, 1);
1078 http_server_properties_
->GetAlternateProtocol(server
).protocol
);
1079 DCHECK(http_server_properties_
->WasAlternateProtocolRecentlyBroken(