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 // The suggested initial congestion windows for a server to use.
64 // TODO: This should be tested and optimized, and even better, suggest a window
65 // that corresponds to historical bandwidth and min-RTT.
66 // Larger initial congestion windows can, if we don't overshoot, reduce latency
67 // by avoiding the RTT needed for slow start to double (and re-double) from a
69 // We match SPDY's use of 32 when secure (since we'd compete with SPDY).
70 const int32 kServerSecureInitialCongestionWindow
= 32;
71 // Be conservative, and just use double a typical TCP ICWND for HTTP.
72 const int32 kServerInecureInitialCongestionWindow
= 20;
74 void HistogramCreateSessionFailure(enum CreateSessionFailure error
) {
75 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error
,
79 bool IsEcdsaSupported() {
81 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
88 QuicConfig
InitializeQuicConfig(bool enable_time_based_loss_detection
,
89 const QuicTagVector
& connection_options
) {
92 if (enable_time_based_loss_detection
)
93 config
.SetLossDetectionToSend(kTIME
);
94 config
.set_idle_connection_state_lifetime(
95 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
),
96 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
));
97 config
.SetConnectionOptionsToSend(connection_options
);
101 class DefaultPacketWriterFactory
: public QuicConnection::PacketWriterFactory
{
103 explicit DefaultPacketWriterFactory(DatagramClientSocket
* socket
)
105 virtual ~DefaultPacketWriterFactory() {}
107 virtual QuicPacketWriter
* Create(QuicConnection
* connection
) const OVERRIDE
;
110 DatagramClientSocket
* socket_
;
113 QuicPacketWriter
* DefaultPacketWriterFactory::Create(
114 QuicConnection
* connection
) const {
115 scoped_ptr
<QuicDefaultPacketWriter
> writer(
116 new QuicDefaultPacketWriter(socket_
));
117 writer
->SetConnection(connection
);
118 return writer
.release();
123 QuicStreamFactory::IpAliasKey::IpAliasKey() {}
125 QuicStreamFactory::IpAliasKey::IpAliasKey(IPEndPoint ip_endpoint
,
127 : ip_endpoint(ip_endpoint
),
128 is_https(is_https
) {}
130 QuicStreamFactory::IpAliasKey::~IpAliasKey() {}
132 bool QuicStreamFactory::IpAliasKey::operator<(
133 const QuicStreamFactory::IpAliasKey
& other
) const {
134 if (!(ip_endpoint
== other
.ip_endpoint
)) {
135 return ip_endpoint
< other
.ip_endpoint
;
137 return is_https
< other
.is_https
;
140 bool QuicStreamFactory::IpAliasKey::operator==(
141 const QuicStreamFactory::IpAliasKey
& other
) const {
142 return is_https
== other
.is_https
&&
143 ip_endpoint
== other
.ip_endpoint
;
146 // Responsible for creating a new QUIC session to the specified server, and
147 // for notifying any associated requests when complete.
148 class QuicStreamFactory::Job
{
150 Job(QuicStreamFactory
* factory
,
151 HostResolver
* host_resolver
,
152 const HostPortPair
& host_port_pair
,
154 bool was_alternate_protocol_recently_broken
,
155 PrivacyMode privacy_mode
,
156 base::StringPiece method
,
157 QuicServerInfo
* server_info
,
158 const BoundNetLog
& net_log
);
160 // Creates a new job to handle the resumption of for connecting an
162 Job(QuicStreamFactory
* factory
,
163 HostResolver
* host_resolver
,
164 QuicClientSession
* session
,
165 QuicServerId server_id
);
169 int Run(const CompletionCallback
& callback
);
173 int DoResolveHostComplete(int rv
);
174 int DoLoadServerInfo();
175 int DoLoadServerInfoComplete(int rv
);
177 int DoResumeConnect();
178 int DoConnectComplete(int rv
);
180 void OnIOComplete(int rv
);
182 CompletionCallback
callback() {
186 const QuicServerId
server_id() const {
194 STATE_RESOLVE_HOST_COMPLETE
,
195 STATE_LOAD_SERVER_INFO
,
196 STATE_LOAD_SERVER_INFO_COMPLETE
,
198 STATE_RESUME_CONNECT
,
199 STATE_CONNECT_COMPLETE
,
203 QuicStreamFactory
* factory_
;
204 SingleRequestHostResolver host_resolver_
;
205 QuicServerId server_id_
;
207 bool was_alternate_protocol_recently_broken_
;
208 scoped_ptr
<QuicServerInfo
> server_info_
;
209 const BoundNetLog net_log_
;
210 QuicClientSession
* session_
;
211 CompletionCallback callback_
;
212 AddressList address_list_
;
213 base::TimeTicks disk_cache_load_start_time_
;
214 base::WeakPtrFactory
<Job
> weak_factory_
;
215 DISALLOW_COPY_AND_ASSIGN(Job
);
218 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
219 HostResolver
* host_resolver
,
220 const HostPortPair
& host_port_pair
,
222 bool was_alternate_protocol_recently_broken
,
223 PrivacyMode privacy_mode
,
224 base::StringPiece method
,
225 QuicServerInfo
* server_info
,
226 const BoundNetLog
& net_log
)
227 : io_state_(STATE_RESOLVE_HOST
),
229 host_resolver_(host_resolver
),
230 server_id_(host_port_pair
, is_https
, privacy_mode
),
231 is_post_(method
== "POST"),
232 was_alternate_protocol_recently_broken_(
233 was_alternate_protocol_recently_broken
),
234 server_info_(server_info
),
237 weak_factory_(this) {}
239 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
240 HostResolver
* host_resolver
,
241 QuicClientSession
* session
,
242 QuicServerId server_id
)
243 : io_state_(STATE_RESUME_CONNECT
),
245 host_resolver_(host_resolver
), // unused
246 server_id_(server_id
),
247 is_post_(false), // unused
248 was_alternate_protocol_recently_broken_(false), // unused
249 net_log_(session
->net_log()), // unused
251 weak_factory_(this) {}
253 QuicStreamFactory::Job::~Job() {
256 int QuicStreamFactory::Job::Run(const CompletionCallback
& callback
) {
258 if (rv
== ERR_IO_PENDING
)
259 callback_
= callback
;
261 return rv
> 0 ? OK
: rv
;
264 int QuicStreamFactory::Job::DoLoop(int rv
) {
266 IoState state
= io_state_
;
267 io_state_
= STATE_NONE
;
269 case STATE_RESOLVE_HOST
:
271 rv
= DoResolveHost();
273 case STATE_RESOLVE_HOST_COMPLETE
:
274 rv
= DoResolveHostComplete(rv
);
276 case STATE_LOAD_SERVER_INFO
:
278 rv
= DoLoadServerInfo();
280 case STATE_LOAD_SERVER_INFO_COMPLETE
:
281 rv
= DoLoadServerInfoComplete(rv
);
287 case STATE_RESUME_CONNECT
:
289 rv
= DoResumeConnect();
291 case STATE_CONNECT_COMPLETE
:
292 rv
= DoConnectComplete(rv
);
295 NOTREACHED() << "io_state_: " << io_state_
;
298 } while (io_state_
!= STATE_NONE
&& rv
!= ERR_IO_PENDING
);
302 void QuicStreamFactory::Job::OnIOComplete(int rv
) {
305 if (rv
!= ERR_IO_PENDING
&& !callback_
.is_null()) {
310 int QuicStreamFactory::Job::DoResolveHost() {
311 // Start loading the data now, and wait for it after we resolve the host.
313 disk_cache_load_start_time_
= base::TimeTicks::Now();
314 server_info_
->Start();
317 io_state_
= STATE_RESOLVE_HOST_COMPLETE
;
318 return host_resolver_
.Resolve(
319 HostResolver::RequestInfo(server_id_
.host_port_pair()),
322 base::Bind(&QuicStreamFactory::Job::OnIOComplete
,
323 weak_factory_
.GetWeakPtr()),
327 int QuicStreamFactory::Job::DoResolveHostComplete(int rv
) {
331 DCHECK(!factory_
->HasActiveSession(server_id_
));
333 // Inform the factory of this resolution, which will set up
334 // a session alias, if possible.
335 if (factory_
->OnResolution(server_id_
, address_list_
)) {
339 io_state_
= STATE_LOAD_SERVER_INFO
;
343 int QuicStreamFactory::Job::DoLoadServerInfo() {
344 io_state_
= STATE_LOAD_SERVER_INFO_COMPLETE
;
349 return server_info_
->WaitForDataReady(
350 base::Bind(&QuicStreamFactory::Job::OnIOComplete
,
351 weak_factory_
.GetWeakPtr()));
354 int QuicStreamFactory::Job::DoLoadServerInfoComplete(int rv
) {
356 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheReadTime",
357 base::TimeTicks::Now() - disk_cache_load_start_time_
);
361 server_info_
.reset();
364 io_state_
= STATE_CONNECT
;
368 int QuicStreamFactory::Job::DoConnect() {
369 io_state_
= STATE_CONNECT_COMPLETE
;
371 int rv
= factory_
->CreateSession(server_id_
, server_info_
.Pass(),
372 address_list_
, net_log_
, &session_
);
374 DCHECK(rv
!= ERR_IO_PENDING
);
379 session_
->StartReading();
380 if (!session_
->connection()->connected()) {
381 return ERR_QUIC_PROTOCOL_ERROR
;
383 bool require_confirmation
=
384 factory_
->require_confirmation() || is_post_
||
385 was_alternate_protocol_recently_broken_
;
386 rv
= session_
->CryptoConnect(
387 require_confirmation
,
388 base::Bind(&QuicStreamFactory::Job::OnIOComplete
,
389 base::Unretained(this)));
393 int QuicStreamFactory::Job::DoResumeConnect() {
394 io_state_
= STATE_CONNECT_COMPLETE
;
396 int rv
= session_
->ResumeCryptoConnect(
397 base::Bind(&QuicStreamFactory::Job::OnIOComplete
,
398 base::Unretained(this)));
403 int QuicStreamFactory::Job::DoConnectComplete(int rv
) {
407 DCHECK(!factory_
->HasActiveSession(server_id_
));
408 // There may well now be an active session for this IP. If so, use the
409 // existing session instead.
410 AddressList
address(session_
->connection()->peer_address());
411 if (factory_
->OnResolution(server_id_
, address
)) {
412 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_IP_POOLED
);
417 factory_
->ActivateSession(server_id_
, session_
);
422 QuicStreamRequest::QuicStreamRequest(QuicStreamFactory
* factory
)
423 : factory_(factory
) {}
425 QuicStreamRequest::~QuicStreamRequest() {
426 if (factory_
&& !callback_
.is_null())
427 factory_
->CancelRequest(this);
430 int QuicStreamRequest::Request(const HostPortPair
& host_port_pair
,
432 PrivacyMode privacy_mode
,
433 base::StringPiece method
,
434 const BoundNetLog
& net_log
,
435 const CompletionCallback
& callback
) {
437 DCHECK(callback_
.is_null());
439 int rv
= factory_
->Create(host_port_pair
, is_https
, privacy_mode
, method
,
441 if (rv
== ERR_IO_PENDING
) {
442 host_port_pair_
= host_port_pair
;
443 is_https_
= is_https
;
445 callback_
= callback
;
454 void QuicStreamRequest::set_stream(scoped_ptr
<QuicHttpStream
> stream
) {
456 stream_
= stream
.Pass();
459 void QuicStreamRequest::OnRequestComplete(int rv
) {
464 scoped_ptr
<QuicHttpStream
> QuicStreamRequest::ReleaseStream() {
466 return stream_
.Pass();
469 QuicStreamFactory::QuicStreamFactory(
470 HostResolver
* host_resolver
,
471 ClientSocketFactory
* client_socket_factory
,
472 base::WeakPtr
<HttpServerProperties
> http_server_properties
,
473 CertVerifier
* cert_verifier
,
474 ChannelIDService
* channel_id_service
,
475 TransportSecurityState
* transport_security_state
,
476 QuicCryptoClientStreamFactory
* quic_crypto_client_stream_factory
,
477 QuicRandom
* random_generator
,
479 size_t max_packet_length
,
480 const std::string
& user_agent_id
,
481 const QuicVersionVector
& supported_versions
,
482 bool enable_port_selection
,
483 bool enable_time_based_loss_detection
,
484 const QuicTagVector
& connection_options
)
485 : require_confirmation_(true),
486 host_resolver_(host_resolver
),
487 client_socket_factory_(client_socket_factory
),
488 http_server_properties_(http_server_properties
),
489 transport_security_state_(transport_security_state
),
490 quic_server_info_factory_(NULL
),
491 quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory
),
492 random_generator_(random_generator
),
494 max_packet_length_(max_packet_length
),
495 config_(InitializeQuicConfig(enable_time_based_loss_detection
,
496 connection_options
)),
497 supported_versions_(supported_versions
),
498 enable_port_selection_(enable_port_selection
),
499 port_seed_(random_generator_
->RandUint64()),
500 weak_factory_(this) {
501 DCHECK(transport_security_state_
);
502 crypto_config_
.SetDefaults();
503 crypto_config_
.set_user_agent_id(user_agent_id
);
504 crypto_config_
.AddCanonicalSuffix(".c.youtube.com");
505 crypto_config_
.AddCanonicalSuffix(".googlevideo.com");
506 crypto_config_
.SetProofVerifier(
507 new ProofVerifierChromium(cert_verifier
, transport_security_state
));
508 crypto_config_
.SetChannelIDSource(
509 new ChannelIDSourceChromium(channel_id_service
));
511 if (cpu
.has_aesni() && cpu
.has_avx())
512 crypto_config_
.PreferAesGcm();
513 if (!IsEcdsaSupported())
514 crypto_config_
.DisableEcdsa();
517 QuicStreamFactory::~QuicStreamFactory() {
518 CloseAllSessions(ERR_ABORTED
);
519 while (!all_sessions_
.empty()) {
520 delete all_sessions_
.begin()->first
;
521 all_sessions_
.erase(all_sessions_
.begin());
523 STLDeleteValues(&active_jobs_
);
526 int QuicStreamFactory::Create(const HostPortPair
& host_port_pair
,
528 PrivacyMode privacy_mode
,
529 base::StringPiece method
,
530 const BoundNetLog
& net_log
,
531 QuicStreamRequest
* request
) {
532 QuicServerId
server_id(host_port_pair
, is_https
, privacy_mode
);
533 if (HasActiveSession(server_id
)) {
534 request
->set_stream(CreateIfSessionExists(server_id
, net_log
));
538 if (HasActiveJob(server_id
)) {
539 Job
* job
= active_jobs_
[server_id
];
540 active_requests_
[request
] = job
;
541 job_requests_map_
[job
].insert(request
);
542 return ERR_IO_PENDING
;
545 QuicServerInfo
* quic_server_info
= NULL
;
546 if (quic_server_info_factory_
) {
547 QuicCryptoClientConfig::CachedState
* cached
=
548 crypto_config_
.LookupOrCreate(server_id
);
550 if (cached
->IsEmpty()) {
551 quic_server_info
= quic_server_info_factory_
->GetForServer(server_id
);
554 bool was_alternate_protocol_recently_broken
=
555 http_server_properties_
&&
556 http_server_properties_
->WasAlternateProtocolRecentlyBroken(
557 server_id
.host_port_pair());
558 scoped_ptr
<Job
> job(new Job(this, host_resolver_
, host_port_pair
, is_https
,
559 was_alternate_protocol_recently_broken
,
560 privacy_mode
, method
, quic_server_info
, net_log
));
561 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
562 base::Unretained(this), job
.get()));
564 if (rv
== ERR_IO_PENDING
) {
565 active_requests_
[request
] = job
.get();
566 job_requests_map_
[job
.get()].insert(request
);
567 active_jobs_
[server_id
] = job
.release();
570 DCHECK(HasActiveSession(server_id
));
571 request
->set_stream(CreateIfSessionExists(server_id
, net_log
));
576 bool QuicStreamFactory::OnResolution(
577 const QuicServerId
& server_id
,
578 const AddressList
& address_list
) {
579 DCHECK(!HasActiveSession(server_id
));
580 for (size_t i
= 0; i
< address_list
.size(); ++i
) {
581 const IPEndPoint
& address
= address_list
[i
];
582 const IpAliasKey
ip_alias_key(address
, server_id
.is_https());
583 if (!ContainsKey(ip_aliases_
, ip_alias_key
))
586 const SessionSet
& sessions
= ip_aliases_
[ip_alias_key
];
587 for (SessionSet::const_iterator i
= sessions
.begin();
588 i
!= sessions
.end(); ++i
) {
589 QuicClientSession
* session
= *i
;
590 if (!session
->CanPool(server_id
.host()))
592 active_sessions_
[server_id
] = session
;
593 session_aliases_
[session
].insert(server_id
);
600 void QuicStreamFactory::OnJobComplete(Job
* job
, int rv
) {
602 require_confirmation_
= false;
604 // Create all the streams, but do not notify them yet.
605 for (RequestSet::iterator it
= job_requests_map_
[job
].begin();
606 it
!= job_requests_map_
[job
].end() ; ++it
) {
607 DCHECK(HasActiveSession(job
->server_id()));
608 (*it
)->set_stream(CreateIfSessionExists(job
->server_id(),
612 while (!job_requests_map_
[job
].empty()) {
613 RequestSet::iterator it
= job_requests_map_
[job
].begin();
614 QuicStreamRequest
* request
= *it
;
615 job_requests_map_
[job
].erase(it
);
616 active_requests_
.erase(request
);
617 // Even though we're invoking callbacks here, we don't need to worry
618 // about |this| being deleted, because the factory is owned by the
619 // profile which can not be deleted via callbacks.
620 request
->OnRequestComplete(rv
);
622 active_jobs_
.erase(job
->server_id());
623 job_requests_map_
.erase(job
);
628 // Returns a newly created QuicHttpStream owned by the caller, if a
629 // matching session already exists. Returns NULL otherwise.
630 scoped_ptr
<QuicHttpStream
> QuicStreamFactory::CreateIfSessionExists(
631 const QuicServerId
& server_id
,
632 const BoundNetLog
& net_log
) {
633 if (!HasActiveSession(server_id
)) {
634 DVLOG(1) << "No active session";
635 return scoped_ptr
<QuicHttpStream
>();
638 QuicClientSession
* session
= active_sessions_
[server_id
];
640 return scoped_ptr
<QuicHttpStream
>(
641 new QuicHttpStream(session
->GetWeakPtr()));
644 void QuicStreamFactory::OnIdleSession(QuicClientSession
* session
) {
647 void QuicStreamFactory::OnSessionGoingAway(QuicClientSession
* session
) {
648 const AliasSet
& aliases
= session_aliases_
[session
];
649 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
651 DCHECK(active_sessions_
.count(*it
));
652 DCHECK_EQ(session
, active_sessions_
[*it
]);
653 // Track sessions which have recently gone away so that we can disable
655 if (session
->goaway_received()) {
656 gone_away_aliases_
.insert(*it
);
659 active_sessions_
.erase(*it
);
660 ProcessGoingAwaySession(session
, *it
, true);
662 ProcessGoingAwaySession(session
, all_sessions_
[session
], false);
663 if (!aliases
.empty()) {
664 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
665 aliases
.begin()->is_https());
666 ip_aliases_
[ip_alias_key
].erase(session
);
667 if (ip_aliases_
[ip_alias_key
].empty()) {
668 ip_aliases_
.erase(ip_alias_key
);
671 session_aliases_
.erase(session
);
674 void QuicStreamFactory::OnSessionClosed(QuicClientSession
* session
) {
675 DCHECK_EQ(0u, session
->GetNumOpenStreams());
676 OnSessionGoingAway(session
);
678 all_sessions_
.erase(session
);
681 void QuicStreamFactory::OnSessionConnectTimeout(
682 QuicClientSession
* session
) {
683 const AliasSet
& aliases
= session_aliases_
[session
];
684 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
686 DCHECK(active_sessions_
.count(*it
));
687 DCHECK_EQ(session
, active_sessions_
[*it
]);
688 active_sessions_
.erase(*it
);
691 if (aliases
.empty()) {
695 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
696 aliases
.begin()->is_https());
697 ip_aliases_
[ip_alias_key
].erase(session
);
698 if (ip_aliases_
[ip_alias_key
].empty()) {
699 ip_aliases_
.erase(ip_alias_key
);
701 QuicServerId server_id
= *aliases
.begin();
702 session_aliases_
.erase(session
);
703 Job
* job
= new Job(this, host_resolver_
, session
, server_id
);
704 active_jobs_
[server_id
] = job
;
705 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
706 base::Unretained(this), job
));
707 DCHECK_EQ(ERR_IO_PENDING
, rv
);
710 void QuicStreamFactory::CancelRequest(QuicStreamRequest
* request
) {
711 DCHECK(ContainsKey(active_requests_
, request
));
712 Job
* job
= active_requests_
[request
];
713 job_requests_map_
[job
].erase(request
);
714 active_requests_
.erase(request
);
717 void QuicStreamFactory::CloseAllSessions(int error
) {
718 while (!active_sessions_
.empty()) {
719 size_t initial_size
= active_sessions_
.size();
720 active_sessions_
.begin()->second
->CloseSessionOnError(error
);
721 DCHECK_NE(initial_size
, active_sessions_
.size());
723 while (!all_sessions_
.empty()) {
724 size_t initial_size
= all_sessions_
.size();
725 all_sessions_
.begin()->first
->CloseSessionOnError(error
);
726 DCHECK_NE(initial_size
, all_sessions_
.size());
728 DCHECK(all_sessions_
.empty());
731 base::Value
* QuicStreamFactory::QuicStreamFactoryInfoToValue() const {
732 base::ListValue
* list
= new base::ListValue();
734 for (SessionMap::const_iterator it
= active_sessions_
.begin();
735 it
!= active_sessions_
.end(); ++it
) {
736 const QuicServerId
& server_id
= it
->first
;
737 QuicClientSession
* session
= it
->second
;
738 const AliasSet
& aliases
= session_aliases_
.find(session
)->second
;
739 // Only add a session to the list once.
740 if (server_id
== *aliases
.begin()) {
741 std::set
<HostPortPair
> hosts
;
742 for (AliasSet::const_iterator alias_it
= aliases
.begin();
743 alias_it
!= aliases
.end(); ++alias_it
) {
744 hosts
.insert(alias_it
->host_port_pair());
746 list
->Append(session
->GetInfoAsValue(hosts
));
752 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
753 crypto_config_
.ClearCachedStates();
756 void QuicStreamFactory::OnIPAddressChanged() {
757 CloseAllSessions(ERR_NETWORK_CHANGED
);
758 require_confirmation_
= true;
761 void QuicStreamFactory::OnCertAdded(const X509Certificate
* cert
) {
762 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
765 void QuicStreamFactory::OnCACertChanged(const X509Certificate
* cert
) {
766 // We should flush the sessions if we removed trust from a
767 // cert, because a previously trusted server may have become
770 // We should not flush the sessions if we added trust to a cert.
772 // Since the OnCACertChanged method doesn't tell us what
773 // kind of change it is, we have to flush the socket
775 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
778 bool QuicStreamFactory::HasActiveSession(
779 const QuicServerId
& server_id
) const {
780 return ContainsKey(active_sessions_
, server_id
);
783 int QuicStreamFactory::CreateSession(
784 const QuicServerId
& server_id
,
785 scoped_ptr
<QuicServerInfo
> server_info
,
786 const AddressList
& address_list
,
787 const BoundNetLog
& net_log
,
788 QuicClientSession
** session
) {
789 bool enable_port_selection
= enable_port_selection_
;
790 if (enable_port_selection
&&
791 ContainsKey(gone_away_aliases_
, server_id
)) {
792 // Disable port selection when the server is going away.
793 // There is no point in trying to return to the same server, if
794 // that server is no longer handling requests.
795 enable_port_selection
= false;
796 gone_away_aliases_
.erase(server_id
);
799 QuicConnectionId connection_id
= random_generator_
->RandUint64();
800 IPEndPoint addr
= *address_list
.begin();
801 scoped_refptr
<PortSuggester
> port_suggester
=
802 new PortSuggester(server_id
.host_port_pair(), port_seed_
);
803 DatagramSocket::BindType bind_type
= enable_port_selection
?
804 DatagramSocket::RANDOM_BIND
: // Use our callback.
805 DatagramSocket::DEFAULT_BIND
; // Use OS to randomize.
806 scoped_ptr
<DatagramClientSocket
> socket(
807 client_socket_factory_
->CreateDatagramClientSocket(
809 base::Bind(&PortSuggester::SuggestPort
, port_suggester
),
810 net_log
.net_log(), net_log
.source()));
811 int rv
= socket
->Connect(addr
);
813 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET
);
816 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested",
817 port_suggester
->call_count());
818 if (enable_port_selection
) {
819 DCHECK_LE(1u, port_suggester
->call_count());
821 DCHECK_EQ(0u, port_suggester
->call_count());
824 // We should adaptively set this buffer size, but for now, we'll use a size
825 // that is more than large enough for a full receive window, and yet
826 // does not consume "too much" memory. If we see bursty packet loss, we may
827 // revisit this setting and test for its impact.
828 const int32
kSocketBufferSize(TcpReceiver::kReceiveWindowTCP
);
829 rv
= socket
->SetReceiveBufferSize(kSocketBufferSize
);
831 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER
);
834 // Set a buffer large enough to contain the initial CWND's worth of packet
835 // to work around the problem with CHLO packets being sent out with the
836 // wrong encryption level, when the send buffer is full.
837 rv
= socket
->SetSendBufferSize(kMaxPacketSize
* 20);
839 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER
);
843 DefaultPacketWriterFactory
packet_writer_factory(socket
.get());
845 if (!helper_
.get()) {
846 helper_
.reset(new QuicConnectionHelper(
847 base::MessageLoop::current()->message_loop_proxy().get(),
848 clock_
.get(), random_generator_
));
851 QuicConnection
* connection
= new QuicConnection(connection_id
,
854 packet_writer_factory
,
855 true /* owns_writer */,
856 false /* is_server */,
857 supported_versions_
);
858 connection
->set_max_packet_length(max_packet_length_
);
860 InitializeCachedStateInCryptoConfig(server_id
, server_info
);
862 QuicConfig config
= config_
;
863 config
.SetInitialCongestionWindowToSend(
864 server_id
.is_https() ? kServerSecureInitialCongestionWindow
865 : kServerInecureInitialCongestionWindow
);
866 config
.SetInitialFlowControlWindowToSend(kInitialReceiveWindowSize
);
867 config
.SetInitialStreamFlowControlWindowToSend(kInitialReceiveWindowSize
);
868 config
.SetInitialSessionFlowControlWindowToSend(kInitialReceiveWindowSize
);
869 if (http_server_properties_
) {
870 const HttpServerProperties::NetworkStats
* stats
=
871 http_server_properties_
->GetServerNetworkStats(
872 server_id
.host_port_pair());
874 config
.SetInitialRoundTripTimeUsToSend(stats
->srtt
.InMicroseconds());
878 *session
= new QuicClientSession(
879 connection
, socket
.Pass(), this, transport_security_state_
,
880 server_info
.Pass(), config
,
881 base::MessageLoop::current()->message_loop_proxy().get(),
883 (*session
)->InitializeSession(server_id
, &crypto_config_
,
884 quic_crypto_client_stream_factory_
);
885 all_sessions_
[*session
] = server_id
; // owning pointer
889 bool QuicStreamFactory::HasActiveJob(const QuicServerId
& key
) const {
890 return ContainsKey(active_jobs_
, key
);
893 void QuicStreamFactory::ActivateSession(
894 const QuicServerId
& server_id
,
895 QuicClientSession
* session
) {
896 DCHECK(!HasActiveSession(server_id
));
897 UMA_HISTOGRAM_COUNTS("Net.QuicActiveSessions", active_sessions_
.size());
898 active_sessions_
[server_id
] = session
;
899 session_aliases_
[session
].insert(server_id
);
900 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
901 server_id
.is_https());
902 DCHECK(!ContainsKey(ip_aliases_
[ip_alias_key
], session
));
903 ip_aliases_
[ip_alias_key
].insert(session
);
906 void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
907 const QuicServerId
& server_id
,
908 const scoped_ptr
<QuicServerInfo
>& server_info
) {
912 QuicCryptoClientConfig::CachedState
* cached
=
913 crypto_config_
.LookupOrCreate(server_id
);
914 if (!cached
->IsEmpty())
917 if (!cached
->Initialize(server_info
->state().server_config
,
918 server_info
->state().source_address_token
,
919 server_info
->state().certs
,
920 server_info
->state().server_config_sig
,
924 if (!server_id
.is_https()) {
925 // Don't check the certificates for insecure QUIC.
926 cached
->SetProofValid();
930 void QuicStreamFactory::ProcessGoingAwaySession(
931 QuicClientSession
* session
,
932 const QuicServerId
& server_id
,
933 bool session_was_active
) {
934 if (!http_server_properties_
)
937 const QuicConnectionStats
& stats
= session
->connection()->GetStats();
938 if (session
->IsCryptoHandshakeConfirmed()) {
939 HttpServerProperties::NetworkStats network_stats
;
940 network_stats
.srtt
= base::TimeDelta::FromMicroseconds(stats
.srtt_us
);
941 network_stats
.bandwidth_estimate
= stats
.estimated_bandwidth
;
942 http_server_properties_
->SetServerNetworkStats(server_id
.host_port_pair(),
947 UMA_HISTOGRAM_COUNTS("Net.QuicHandshakeNotConfirmedNumPacketsReceived",
948 stats
.packets_received
);
950 if (!session_was_active
)
953 const HostPortPair
& server
= server_id
.host_port_pair();
954 // Don't try to change the alternate-protocol state, if the
955 // alternate-protocol state is unknown.
956 if (!http_server_properties_
->HasAlternateProtocol(server
))
959 // TODO(rch): In the special case where the session has received no
960 // packets from the peer, we should consider blacklisting this
961 // differently so that we still race TCP but we don't consider the
962 // session connected until the handshake has been confirmed.
963 HistogramBrokenAlternateProtocolLocation(
964 BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY
);
965 AlternateProtocolInfo alternate
=
966 http_server_properties_
->GetAlternateProtocol(server
);
967 DCHECK_EQ(QUIC
, alternate
.protocol
);
969 // Since the session was active, there's no longer an
970 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the
971 // TCP job also fails. So to avoid not using QUIC when we otherwise could,
972 // we mark it as broken, and then immediately re-enable it. This leaves
973 // QUIC as "recently broken" which means that 0-RTT will be disabled but
975 http_server_properties_
->SetBrokenAlternateProtocol(server
);
976 http_server_properties_
->ClearAlternateProtocol(server
);
977 http_server_properties_
->SetAlternateProtocol(
978 server
, alternate
.port
, alternate
.protocol
, 1);
980 http_server_properties_
->GetAlternateProtocol(server
).protocol
);
981 DCHECK(http_server_properties_
->WasAlternateProtocolRecentlyBroken(