1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/quic/quic_session_pool.h"
6
7 #include <memory>
8 #include <optional>
9 #include <set>
10 #include <string_view>
11 #include <tuple>
12 #include <utility>
13
14 #include "base/containers/contains.h"
15 #include "base/feature_list.h"
16 #include "base/functional/bind.h"
17 #include "base/functional/callback_helpers.h"
18 #include "base/location.h"
19 #include "base/memory/raw_ptr.h"
20 #include "base/metrics/field_trial.h"
21 #include "base/metrics/histogram_functions.h"
22 #include "base/metrics/histogram_macros.h"
23 #include "base/no_destructor.h"
24 #include "base/not_fatal_until.h"
25 #include "base/numerics/safe_conversions.h"
26 #include "base/ranges/algorithm.h"
27 #include "base/strings/escape.h"
28 #include "base/strings/string_number_conversions.h"
29 #include "base/strings/string_util.h"
30 #include "base/strings/stringprintf.h"
31 #include "base/task/sequenced_task_runner.h"
32 #include "base/task/single_thread_task_runner.h"
33 #include "base/values.h"
34 #include "crypto/openssl_util.h"
35 #include "net/base/address_list.h"
36 #include "net/base/connection_endpoint_metadata.h"
37 #include "net/base/features.h"
38 #include "net/base/http_user_agent_settings.h"
39 #include "net/base/ip_address.h"
40 #include "net/base/net_errors.h"
41 #include "net/base/network_anonymization_key.h"
42 #include "net/base/network_handle.h"
43 #include "net/base/proxy_delegate.h"
44 #include "net/base/session_usage.h"
45 #include "net/base/trace_constants.h"
46 #include "net/base/tracing.h"
47 #include "net/base/url_util.h"
48 #include "net/cert/cert_verifier.h"
49 #include "net/dns/host_resolver.h"
50 #include "net/dns/public/secure_dns_policy.h"
51 #include "net/http/http_proxy_connect_job.h"
52 #include "net/log/net_log.h"
53 #include "net/log/net_log_capture_mode.h"
54 #include "net/log/net_log_event_type.h"
55 #include "net/log/net_log_source_type.h"
56 #include "net/quic/address_utils.h"
57 #include "net/quic/crypto/proof_verifier_chromium.h"
58 #include "net/quic/properties_based_quic_server_info.h"
59 #include "net/quic/quic_chromium_alarm_factory.h"
60 #include "net/quic/quic_chromium_client_session.h"
61 #include "net/quic/quic_chromium_connection_helper.h"
62 #include "net/quic/quic_chromium_packet_reader.h"
63 #include "net/quic/quic_chromium_packet_writer.h"
64 #include "net/quic/quic_context.h"
65 #include "net/quic/quic_crypto_client_stream_factory.h"
66 #include "net/quic/quic_server_info.h"
67 #include "net/quic/quic_session_key.h"
68 #include "net/quic/quic_session_pool_direct_job.h"
69 #include "net/quic/quic_session_pool_job.h"
70 #include "net/quic/quic_session_pool_proxy_job.h"
71 #include "net/socket/client_socket_factory.h"
72 #include "net/socket/next_proto.h"
73 #include "net/socket/socket_performance_watcher.h"
74 #include "net/socket/socket_performance_watcher_factory.h"
75 #include "net/socket/udp_client_socket.h"
76 #include "net/spdy/multiplexed_session_creation_initiator.h"
77 #include "net/third_party/quiche/src/quiche/quic/core/crypto/null_decrypter.h"
78 #include "net/third_party/quiche/src/quiche/quic/core/crypto/proof_verifier.h"
79 #include "net/third_party/quiche/src/quiche/quic/core/crypto/quic_random.h"
80 #include "net/third_party/quiche/src/quiche/quic/core/quic_clock.h"
81 #include "net/third_party/quiche/src/quiche/quic/core/quic_connection.h"
82 #include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
83 #include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
84 #include "net/third_party/quiche/src/quiche/quic/platform/api/quic_flags.h"
85 #include "net/traffic_annotation/network_traffic_annotation.h"
86 #include "third_party/boringssl/src/include/openssl/aead.h"
87 #include "url/gurl.h"
88 #include "url/scheme_host_port.h"
89 #include "url/url_constants.h"
90
91 namespace net {
92
93 namespace {
94
95 enum InitialRttEstimateSource {
96 INITIAL_RTT_DEFAULT,
97 INITIAL_RTT_CACHED,
98 INITIAL_RTT_2G,
99 INITIAL_RTT_3G,
100 INITIAL_RTT_SOURCE_MAX,
101 };
102
103 // These values are persisted to logs. Entries should not be renumbered and
104 // numeric values should never be reused.
105 enum FindMatchingIpSessionResult {
106 MATCHING_IP_SESSION_FOUND,
107 CAN_POOL_BUT_DIFFERENT_IP,
108 CANNOT_POOL_WITH_EXISTING_SESSIONS,
109 POOLED_WITH_DIFFERENT_IP_SESSION,
110 FIND_MATCHING_IP_SESSION_RESULT_MAX
111 };
112
QuicPlatformNotificationToString(QuicPlatformNotification notification)113 std::string QuicPlatformNotificationToString(
114 QuicPlatformNotification notification) {
115 switch (notification) {
116 case NETWORK_CONNECTED:
117 return "OnNetworkConnected";
118 case NETWORK_MADE_DEFAULT:
119 return "OnNetworkMadeDefault";
120 case NETWORK_DISCONNECTED:
121 return "OnNetworkDisconnected";
122 case NETWORK_SOON_TO_DISCONNECT:
123 return "OnNetworkSoonToDisconnect";
124 case NETWORK_IP_ADDRESS_CHANGED:
125 return "OnIPAddressChanged";
126 default:
127 QUICHE_NOTREACHED();
128 break;
129 }
130 return "InvalidNotification";
131 }
132
AllActiveSessionsGoingAwayReasonToString(AllActiveSessionsGoingAwayReason reason)133 const char* AllActiveSessionsGoingAwayReasonToString(
134 AllActiveSessionsGoingAwayReason reason) {
135 switch (reason) {
136 case kClockSkewDetected:
137 return "ClockSkewDetected";
138 case kIPAddressChanged:
139 return "IPAddressChanged";
140 case kCertDBChanged:
141 return "CertDBChanged";
142 case kCertVerifierChanged:
143 return "CertVerifierChanged";
144 }
145 }
146
HistogramCreateSessionFailure(enum CreateSessionFailure error)147 void HistogramCreateSessionFailure(enum CreateSessionFailure error) {
148 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error,
149 CREATION_ERROR_MAX);
150 }
151
LogFindMatchingIpSessionResult(const NetLogWithSource & net_log,FindMatchingIpSessionResult result,QuicChromiumClientSession * session,const url::SchemeHostPort & destination)152 void LogFindMatchingIpSessionResult(const NetLogWithSource& net_log,
153 FindMatchingIpSessionResult result,
154 QuicChromiumClientSession* session,
155 const url::SchemeHostPort& destination) {
156 NetLogEventType type =
157 NetLogEventType::QUIC_SESSION_POOL_CANNOT_POOL_WITH_EXISTING_SESSIONS;
158 switch (result) {
159 case MATCHING_IP_SESSION_FOUND:
160 type = NetLogEventType::QUIC_SESSION_POOL_MATCHING_IP_SESSION_FOUND;
161 break;
162 case POOLED_WITH_DIFFERENT_IP_SESSION:
163 type =
164 NetLogEventType::QUIC_SESSION_POOL_POOLED_WITH_DIFFERENT_IP_SESSION;
165 break;
166 case CAN_POOL_BUT_DIFFERENT_IP:
167 type = NetLogEventType::QUIC_SESSION_POOL_CAN_POOL_BUT_DIFFERENT_IP;
168 break;
169 case CANNOT_POOL_WITH_EXISTING_SESSIONS:
170 case FIND_MATCHING_IP_SESSION_RESULT_MAX:
171 break;
172 }
173 net_log.AddEvent(type, [&] {
174 base::Value::Dict dict;
175 dict.Set("destination", destination.Serialize());
176 if (session != nullptr) {
177 session->net_log().source().AddToEventParameters(dict);
178 }
179 return dict;
180 });
181 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.FindMatchingIpSessionResult",
182 result, FIND_MATCHING_IP_SESSION_RESULT_MAX);
183 if (IsGoogleHost(destination.host()) &&
184 !destination.host().ends_with(".googlevideo.com")) {
185 UMA_HISTOGRAM_ENUMERATION(
186 "Net.QuicSession.FindMatchingIpSessionResultGoogle", result,
187 FIND_MATCHING_IP_SESSION_RESULT_MAX);
188 }
189 }
190
SetInitialRttEstimate(base::TimeDelta estimate,enum InitialRttEstimateSource source,quic::QuicConfig * config)191 void SetInitialRttEstimate(base::TimeDelta estimate,
192 enum InitialRttEstimateSource source,
193 quic::QuicConfig* config) {
194 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.InitialRttEsitmateSource", source,
195 INITIAL_RTT_SOURCE_MAX);
196 if (estimate != base::TimeDelta()) {
197 config->SetInitialRoundTripTimeUsToSend(
198 base::checked_cast<uint64_t>(estimate.InMicroseconds()));
199 }
200 }
201
202 // An implementation of quic::QuicCryptoClientConfig::ServerIdFilter that wraps
203 // an |origin_filter|.
204 class ServerIdOriginFilter
205 : public quic::QuicCryptoClientConfig::ServerIdFilter {
206 public:
ServerIdOriginFilter(const base::RepeatingCallback<bool (const GURL &)> origin_filter)207 explicit ServerIdOriginFilter(
208 const base::RepeatingCallback<bool(const GURL&)> origin_filter)
209 : origin_filter_(origin_filter) {}
210
Matches(const quic::QuicServerId & server_id) const211 bool Matches(const quic::QuicServerId& server_id) const override {
212 if (origin_filter_.is_null()) {
213 return true;
214 }
215
216 GURL url(base::StringPrintf("%s%s%s:%d", url::kHttpsScheme,
217 url::kStandardSchemeSeparator,
218 server_id.host().c_str(), server_id.port()));
219 DCHECK(url.is_valid());
220 return origin_filter_.Run(url);
221 }
222
223 private:
224 const base::RepeatingCallback<bool(const GURL&)> origin_filter_;
225 };
226
HostsFromOrigins(std::set<HostPortPair> origins)227 std::set<std::string> HostsFromOrigins(std::set<HostPortPair> origins) {
228 std::set<std::string> hosts;
229 for (const auto& origin : origins) {
230 hosts.insert(origin.host());
231 }
232 return hosts;
233 }
234
LogUsingExistingSession(const NetLogWithSource & request_net_log,QuicChromiumClientSession * session,const url::SchemeHostPort & destination)235 void LogUsingExistingSession(const NetLogWithSource& request_net_log,
236 QuicChromiumClientSession* session,
237 const url::SchemeHostPort& destination) {
238 request_net_log.AddEvent(
239 NetLogEventType::QUIC_SESSION_POOL_USE_EXISTING_SESSION, [&] {
240 base::Value::Dict dict;
241 dict.Set("destination", destination.Serialize());
242 session->net_log().source().AddToEventParameters(dict);
243 return dict;
244 });
245 session->net_log().AddEventReferencingSource(
246 NetLogEventType::
247 QUIC_SESSION_POOL_ATTACH_HTTP_STREAM_JOB_TO_EXISTING_SESSION,
248 request_net_log.source());
249 }
250
251 } // namespace
252
QuicSessionRequest(QuicSessionPool * pool)253 QuicSessionRequest::QuicSessionRequest(QuicSessionPool* pool) : pool_(pool) {}
254
~QuicSessionRequest()255 QuicSessionRequest::~QuicSessionRequest() {
256 if (pool_ && !callback_.is_null()) {
257 pool_->CancelRequest(this);
258 }
259 }
260
Request(url::SchemeHostPort destination,quic::ParsedQuicVersion quic_version,const ProxyChain & proxy_chain,std::optional<NetworkTrafficAnnotationTag> proxy_annotation_tag,const HttpUserAgentSettings * http_user_agent_settings,SessionUsage session_usage,PrivacyMode privacy_mode,RequestPriority priority,const SocketTag & socket_tag,const NetworkAnonymizationKey & network_anonymization_key,SecureDnsPolicy secure_dns_policy,bool require_dns_https_alpn,int cert_verify_flags,const GURL & url,const NetLogWithSource & net_log,NetErrorDetails * net_error_details,MultiplexedSessionCreationInitiator session_creation_initiator,CompletionOnceCallback failed_on_default_network_callback,CompletionOnceCallback callback)261 int QuicSessionRequest::Request(
262 url::SchemeHostPort destination,
263 quic::ParsedQuicVersion quic_version,
264 const ProxyChain& proxy_chain,
265 std::optional<NetworkTrafficAnnotationTag> proxy_annotation_tag,
266 const HttpUserAgentSettings* http_user_agent_settings,
267 SessionUsage session_usage,
268 PrivacyMode privacy_mode,
269 RequestPriority priority,
270 const SocketTag& socket_tag,
271 const NetworkAnonymizationKey& network_anonymization_key,
272 SecureDnsPolicy secure_dns_policy,
273 bool require_dns_https_alpn,
274 int cert_verify_flags,
275 const GURL& url,
276 const NetLogWithSource& net_log,
277 NetErrorDetails* net_error_details,
278 MultiplexedSessionCreationInitiator session_creation_initiator,
279 CompletionOnceCallback failed_on_default_network_callback,
280 CompletionOnceCallback callback) {
281 DCHECK_EQ(quic_version.IsKnown(), !require_dns_https_alpn);
282 DCHECK(net_error_details);
283 DCHECK(callback_.is_null());
284 DCHECK(host_resolution_callback_.is_null());
285 DCHECK(pool_);
286
287 net_error_details_ = net_error_details;
288 failed_on_default_network_callback_ =
289 std::move(failed_on_default_network_callback);
290
291 session_key_ =
292 QuicSessionKey(HostPortPair::FromURL(url), privacy_mode, proxy_chain,
293 session_usage, socket_tag, network_anonymization_key,
294 secure_dns_policy, require_dns_https_alpn);
295 bool use_dns_aliases = session_usage == SessionUsage::kProxy ? false : true;
296
297 int rv = pool_->RequestSession(
298 session_key_, std::move(destination), quic_version,
299 std::move(proxy_annotation_tag), session_creation_initiator,
300 http_user_agent_settings, priority, use_dns_aliases, cert_verify_flags,
301 url, net_log, this);
302 if (rv == ERR_IO_PENDING) {
303 net_log_ = net_log;
304 callback_ = std::move(callback);
305 } else {
306 DCHECK(!expect_on_host_resolution_);
307 pool_ = nullptr;
308 }
309
310 if (rv == OK) {
311 DCHECK(session_);
312 }
313 return rv;
314 }
315
WaitForHostResolution(CompletionOnceCallback callback)316 bool QuicSessionRequest::WaitForHostResolution(
317 CompletionOnceCallback callback) {
318 DCHECK(host_resolution_callback_.is_null());
319 if (expect_on_host_resolution_) {
320 host_resolution_callback_ = std::move(callback);
321 }
322 return expect_on_host_resolution_;
323 }
324
ExpectOnHostResolution()325 void QuicSessionRequest::ExpectOnHostResolution() {
326 expect_on_host_resolution_ = true;
327 }
328
OnHostResolutionComplete(int rv,base::TimeTicks dns_resolution_start_time,base::TimeTicks dns_resolution_end_time)329 void QuicSessionRequest::OnHostResolutionComplete(
330 int rv,
331 base::TimeTicks dns_resolution_start_time,
332 base::TimeTicks dns_resolution_end_time) {
333 DCHECK(expect_on_host_resolution_);
334 expect_on_host_resolution_ = false;
335 dns_resolution_start_time_ = dns_resolution_start_time;
336 dns_resolution_end_time_ = dns_resolution_end_time;
337 if (!host_resolution_callback_.is_null()) {
338 std::move(host_resolution_callback_).Run(rv);
339 }
340 }
341
WaitForQuicSessionCreation(CompletionOnceCallback callback)342 bool QuicSessionRequest::WaitForQuicSessionCreation(
343 CompletionOnceCallback callback) {
344 DCHECK(create_session_callback_.is_null());
345 if (expect_on_quic_session_creation_) {
346 create_session_callback_ = std::move(callback);
347 }
348 return expect_on_quic_session_creation_;
349 }
350
ExpectQuicSessionCreation()351 void QuicSessionRequest::ExpectQuicSessionCreation() {
352 expect_on_quic_session_creation_ = true;
353 }
354
OnQuicSessionCreationComplete(int rv)355 void QuicSessionRequest::OnQuicSessionCreationComplete(int rv) {
356 // DCHECK(expect_on_quic_session_creation_);
357 expect_on_quic_session_creation_ = false;
358 if (!create_session_callback_.is_null()) {
359 std::move(create_session_callback_).Run(rv);
360 }
361 }
362
OnRequestComplete(int rv)363 void QuicSessionRequest::OnRequestComplete(int rv) {
364 pool_ = nullptr;
365 std::move(callback_).Run(rv);
366 }
367
OnConnectionFailedOnDefaultNetwork()368 void QuicSessionRequest::OnConnectionFailedOnDefaultNetwork() {
369 if (!failed_on_default_network_callback_.is_null()) {
370 std::move(failed_on_default_network_callback_).Run(OK);
371 }
372 }
373
GetTimeDelayForWaitingJob() const374 base::TimeDelta QuicSessionRequest::GetTimeDelayForWaitingJob() const {
375 if (!pool_) {
376 return base::TimeDelta();
377 }
378 return pool_->GetTimeDelayForWaitingJob(session_key_);
379 }
380
SetPriority(RequestPriority priority)381 void QuicSessionRequest::SetPriority(RequestPriority priority) {
382 if (pool_) {
383 pool_->SetRequestPriority(this, priority);
384 }
385 }
386
387 std::unique_ptr<QuicChromiumClientSession::Handle>
ReleaseSessionHandle()388 QuicSessionRequest::ReleaseSessionHandle() {
389 if (!session_ || !session_->IsConnected()) {
390 return nullptr;
391 }
392
393 return std::move(session_);
394 }
395
SetSession(std::unique_ptr<QuicChromiumClientSession::Handle> session)396 void QuicSessionRequest::SetSession(
397 std::unique_ptr<QuicChromiumClientSession::Handle> session) {
398 session_ = std::move(session);
399 }
400
QuicEndpoint(quic::ParsedQuicVersion quic_version,IPEndPoint ip_endpoint,ConnectionEndpointMetadata metadata)401 QuicEndpoint::QuicEndpoint(quic::ParsedQuicVersion quic_version,
402 IPEndPoint ip_endpoint,
403 ConnectionEndpointMetadata metadata)
404 : quic_version(quic_version),
405 ip_endpoint(ip_endpoint),
406 metadata(metadata) {}
407
408 QuicEndpoint::~QuicEndpoint() = default;
409
ToValue() const410 base::Value::Dict QuicEndpoint::ToValue() const {
411 base::Value::Dict dict;
412 dict.Set("quic_version", quic::ParsedQuicVersionToString(quic_version));
413 dict.Set("ip_endpoint", ip_endpoint.ToString());
414 dict.Set("metadata", metadata.ToValue());
415 return dict;
416 }
417
QuicCryptoClientConfigOwner(std::unique_ptr<quic::ProofVerifier> proof_verifier,std::unique_ptr<quic::QuicClientSessionCache> session_cache,QuicSessionPool * quic_session_pool)418 QuicSessionPool::QuicCryptoClientConfigOwner::QuicCryptoClientConfigOwner(
419 std::unique_ptr<quic::ProofVerifier> proof_verifier,
420 std::unique_ptr<quic::QuicClientSessionCache> session_cache,
421 QuicSessionPool* quic_session_pool)
422 : config_(std::move(proof_verifier), std::move(session_cache)),
423 clock_(base::DefaultClock::GetInstance()),
424 quic_session_pool_(quic_session_pool) {
425 DCHECK(quic_session_pool_);
426 memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
427 FROM_HERE,
428 base::BindRepeating(&QuicCryptoClientConfigOwner::OnMemoryPressure,
429 base::Unretained(this)));
430 if (quic_session_pool_->ssl_config_service_->GetSSLContextConfig()
431 .PostQuantumKeyAgreementEnabled()) {
432 uint16_t postquantum_group =
433 base::FeatureList::IsEnabled(features::kUseMLKEM)
434 ? SSL_GROUP_X25519_MLKEM768
435 : SSL_GROUP_X25519_KYBER768_DRAFT00;
436 config_.set_preferred_groups({postquantum_group, SSL_GROUP_X25519,
437 SSL_GROUP_SECP256R1, SSL_GROUP_SECP384R1});
438 }
439 }
~QuicCryptoClientConfigOwner()440 QuicSessionPool::QuicCryptoClientConfigOwner::~QuicCryptoClientConfigOwner() {
441 DCHECK_EQ(num_refs_, 0);
442 }
443
OnMemoryPressure(base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level)444 void QuicSessionPool::QuicCryptoClientConfigOwner::OnMemoryPressure(
445 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
446 quic::SessionCache* session_cache = config_.session_cache();
447 if (!session_cache) {
448 return;
449 }
450 time_t now = clock_->Now().ToTimeT();
451 uint64_t now_u64 = 0;
452 if (now > 0) {
453 now_u64 = static_cast<uint64_t>(now);
454 }
455 switch (memory_pressure_level) {
456 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
457 break;
458 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
459 session_cache->RemoveExpiredEntries(
460 quic::QuicWallTime::FromUNIXSeconds(now_u64));
461 break;
462 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
463 session_cache->Clear();
464 break;
465 }
466 }
467
CryptoClientConfigHandle(const QuicCryptoClientConfigMap::iterator & map_iterator)468 QuicSessionPool::CryptoClientConfigHandle::CryptoClientConfigHandle(
469 const QuicCryptoClientConfigMap::iterator& map_iterator)
470 : map_iterator_(map_iterator) {
471 DCHECK_GE(map_iterator_->second->num_refs(), 0);
472 map_iterator->second->AddRef();
473 }
474
~CryptoClientConfigHandle()475 QuicSessionPool::CryptoClientConfigHandle::~CryptoClientConfigHandle() {
476 DCHECK_GT(map_iterator_->second->num_refs(), 0);
477 map_iterator_->second->ReleaseRef();
478 if (map_iterator_->second->num_refs() == 0) {
479 map_iterator_->second->quic_session_pool()->OnAllCryptoClientRefReleased(
480 map_iterator_);
481 }
482 }
483
484 quic::QuicCryptoClientConfig*
GetConfig() const485 QuicSessionPool::CryptoClientConfigHandle::GetConfig() const {
486 return map_iterator_->second->config();
487 }
488
QuicSessionPool(NetLog * net_log,HostResolver * host_resolver,SSLConfigService * ssl_config_service,ClientSocketFactory * client_socket_factory,HttpServerProperties * http_server_properties,CertVerifier * cert_verifier,TransportSecurityState * transport_security_state,ProxyDelegate * proxy_delegate,SCTAuditingDelegate * sct_auditing_delegate,SocketPerformanceWatcherFactory * socket_performance_watcher_factory,QuicCryptoClientStreamFactory * quic_crypto_client_stream_factory,QuicContext * quic_context)489 QuicSessionPool::QuicSessionPool(
490 NetLog* net_log,
491 HostResolver* host_resolver,
492 SSLConfigService* ssl_config_service,
493 ClientSocketFactory* client_socket_factory,
494 HttpServerProperties* http_server_properties,
495 CertVerifier* cert_verifier,
496 TransportSecurityState* transport_security_state,
497 ProxyDelegate* proxy_delegate,
498 SCTAuditingDelegate* sct_auditing_delegate,
499 SocketPerformanceWatcherFactory* socket_performance_watcher_factory,
500 QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory,
501 QuicContext* quic_context)
502 : net_log_(
503 NetLogWithSource::Make(net_log, NetLogSourceType::QUIC_SESSION_POOL)),
504 host_resolver_(host_resolver),
505 client_socket_factory_(client_socket_factory),
506 http_server_properties_(http_server_properties),
507 cert_verifier_(cert_verifier),
508 transport_security_state_(transport_security_state),
509 proxy_delegate_(proxy_delegate),
510 sct_auditing_delegate_(sct_auditing_delegate),
511 quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory),
512 random_generator_(quic_context->random_generator()),
513 clock_(quic_context->clock()),
514 // TODO(vasilvv): figure out how to avoid having multiple copies of
515 // QuicParams.
516 params_(*quic_context->params()),
517 clock_skew_detector_(base::TimeTicks::Now(), base::Time::Now()),
518 socket_performance_watcher_factory_(socket_performance_watcher_factory),
519 recent_crypto_config_map_(kMaxRecentCryptoConfigs),
520 config_(InitializeQuicConfig(*quic_context->params())),
521 ping_timeout_(quic::QuicTime::Delta::FromSeconds(quic::kPingTimeoutSecs)),
522 reduced_ping_timeout_(quic::QuicTime::Delta::FromMicroseconds(
523 quic_context->params()->reduced_ping_timeout.InMicroseconds())),
524 retransmittable_on_wire_timeout_(quic::QuicTime::Delta::FromMicroseconds(
525 quic_context->params()
526 ->retransmittable_on_wire_timeout.InMicroseconds())),
527 yield_after_packets_(kQuicYieldAfterPacketsRead),
528 yield_after_duration_(quic::QuicTime::Delta::FromMilliseconds(
529 kQuicYieldAfterDurationMilliseconds)),
530 default_network_(handles::kInvalidNetworkHandle),
531 connectivity_monitor_(default_network_),
532 task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
533 tick_clock_(base::DefaultTickClock::GetInstance()),
534 ssl_config_service_(ssl_config_service),
535 use_network_anonymization_key_for_crypto_configs_(
536 NetworkAnonymizationKey::IsPartitioningEnabled()),
537 report_ecn_(quic_context->params()->report_ecn),
538 skip_dns_with_origin_frame_(
539 quic_context->params()->skip_dns_with_origin_frame),
540 ignore_ip_matching_when_finding_existing_sessions_(
541 quic_context->params()
542 ->ignore_ip_matching_when_finding_existing_sessions) {
543 DCHECK(transport_security_state_);
544 DCHECK(http_server_properties_);
545 if (params_.disable_tls_zero_rtt) {
546 SetQuicFlag(quic_disable_client_tls_zero_rtt, true);
547 }
548 InitializeMigrationOptions();
549 cert_verifier_->AddObserver(this);
550 CertDatabase::GetInstance()->AddObserver(this);
551 }
552
~QuicSessionPool()553 QuicSessionPool::~QuicSessionPool() {
554 UMA_HISTOGRAM_COUNTS_1000("Net.NumQuicSessionsAtShutdown",
555 all_sessions_.size());
556 CloseAllSessions(ERR_ABORTED, quic::QUIC_CONNECTION_CANCELLED);
557 all_sessions_.clear();
558
559 // Clear the active jobs, first moving out of the instance variable so that
560 // calls to CancelRequest for any pending requests do not cause recursion.
561 JobMap active_jobs = std::move(active_jobs_);
562 active_jobs.clear();
563
564 DCHECK(dns_aliases_by_session_key_.empty());
565
566 // This should have been moved to the recent map when all consumers of
567 // QuicCryptoClientConfigs were deleted, in the above lines.
568 DCHECK(active_crypto_config_map_.empty());
569
570 CertDatabase::GetInstance()->RemoveObserver(this);
571 cert_verifier_->RemoveObserver(this);
572 if (params_.close_sessions_on_ip_change ||
573 params_.goaway_sessions_on_ip_change) {
574 NetworkChangeNotifier::RemoveIPAddressObserver(this);
575 }
576 if (NetworkChangeNotifier::AreNetworkHandlesSupported()) {
577 NetworkChangeNotifier::RemoveNetworkObserver(this);
578 }
579 }
580
CanUseExistingSession(const QuicSessionKey & session_key,const url::SchemeHostPort & destination) const581 bool QuicSessionPool::CanUseExistingSession(
582 const QuicSessionKey& session_key,
583 const url::SchemeHostPort& destination) const {
584 return FindExistingSession(session_key, destination) != nullptr;
585 }
586
FindExistingSession(const QuicSessionKey & session_key,const url::SchemeHostPort & destination) const587 QuicChromiumClientSession* QuicSessionPool::FindExistingSession(
588 const QuicSessionKey& session_key,
589 const url::SchemeHostPort& destination) const {
590 auto active_session_it = active_sessions_.find(session_key);
591 if (active_session_it != active_sessions_.end()) {
592 return active_session_it->second;
593 }
594
595 for (const auto& key_value : active_sessions_) {
596 QuicChromiumClientSession* session = key_value.second;
597 if (CanWaiveIpMatching(destination, session) &&
598 session->CanPool(session_key.host(), session_key)) {
599 return session;
600 }
601 }
602
603 return nullptr;
604 }
605
HasMatchingIpSessionForServiceEndpoint(const QuicSessionAliasKey & session_alias_key,const ServiceEndpoint & service_endpoint,const std::set<std::string> & dns_aliases,bool use_dns_aliases)606 bool QuicSessionPool::HasMatchingIpSessionForServiceEndpoint(
607 const QuicSessionAliasKey& session_alias_key,
608 const ServiceEndpoint& service_endpoint,
609 const std::set<std::string>& dns_aliases,
610 bool use_dns_aliases) {
611 return HasMatchingIpSession(session_alias_key,
612 service_endpoint.ipv6_endpoints, dns_aliases,
613 use_dns_aliases) ||
614 HasMatchingIpSession(session_alias_key,
615 service_endpoint.ipv4_endpoints, dns_aliases,
616 use_dns_aliases);
617 }
618
RequestSession(const QuicSessionKey & session_key,url::SchemeHostPort destination,quic::ParsedQuicVersion quic_version,std::optional<NetworkTrafficAnnotationTag> proxy_annotation_tag,MultiplexedSessionCreationInitiator session_creation_initiator,const HttpUserAgentSettings * http_user_agent_settings,RequestPriority priority,bool use_dns_aliases,int cert_verify_flags,const GURL & url,const NetLogWithSource & net_log,QuicSessionRequest * request)619 int QuicSessionPool::RequestSession(
620 const QuicSessionKey& session_key,
621 url::SchemeHostPort destination,
622 quic::ParsedQuicVersion quic_version,
623 std::optional<NetworkTrafficAnnotationTag> proxy_annotation_tag,
624 MultiplexedSessionCreationInitiator session_creation_initiator,
625 const HttpUserAgentSettings* http_user_agent_settings,
626 RequestPriority priority,
627 bool use_dns_aliases,
628 int cert_verify_flags,
629 const GURL& url,
630 const NetLogWithSource& net_log,
631 QuicSessionRequest* request) {
632 if (clock_skew_detector_.ClockSkewDetected(base::TimeTicks::Now(),
633 base::Time::Now())) {
634 MarkAllActiveSessionsGoingAway(kClockSkewDetected);
635 }
636 DCHECK(HostPortPair(session_key.server_id().host(),
637 session_key.server_id().port())
638 .Equals(HostPortPair::FromURL(url)));
639
640 // Use active session for `session_key` if such exists, or pool to active
641 // session to `destination` if possible.
642 QuicChromiumClientSession* existing_session =
643 FindExistingSession(session_key, destination);
644 if (existing_session) {
645 LogUsingExistingSession(net_log, existing_session, destination);
646 if (!HasActiveSession(session_key)) {
647 QuicSessionAliasKey key(destination, session_key);
648 std::set<std::string> dns_aliases;
649 ActivateAndMapSessionToAliasKey(existing_session, key,
650 std::move(dns_aliases));
651 }
652 request->SetSession(existing_session->CreateHandle(std::move(destination)));
653 return OK;
654 }
655
656 // Associate with active job to |session_key| if such exists.
657 auto active_job = active_jobs_.find(session_key);
658 if (active_job != active_jobs_.end()) {
659 active_job->second->AssociateWithNetLogSource(net_log);
660 active_job->second->AddRequest(request);
661 return ERR_IO_PENDING;
662 }
663
664 // If a proxy is in use, then a traffic annotation is required.
665 if (!session_key.proxy_chain().is_direct()) {
666 DCHECK(proxy_annotation_tag);
667 }
668
669 QuicSessionAliasKey key(destination, session_key);
670 std::unique_ptr<Job> job;
671 // Connect start time, but only for direct connections to a proxy.
672 std::optional<base::TimeTicks> proxy_connect_start_time = std::nullopt;
673 if (session_key.proxy_chain().is_direct()) {
674 if (session_key.session_usage() == SessionUsage::kProxy) {
675 proxy_connect_start_time = base::TimeTicks::Now();
676 }
677 job = std::make_unique<DirectJob>(
678 this, quic_version, host_resolver_, std::move(key),
679 CreateCryptoConfigHandle(session_key.network_anonymization_key()),
680 params_.retry_on_alternate_network_before_handshake, priority,
681 use_dns_aliases, session_key.require_dns_https_alpn(),
682 cert_verify_flags, session_creation_initiator, net_log);
683 } else {
684 job = std::make_unique<ProxyJob>(
685 this, quic_version, std::move(key), *proxy_annotation_tag,
686 session_creation_initiator, http_user_agent_settings,
687 CreateCryptoConfigHandle(session_key.network_anonymization_key()),
688 priority, cert_verify_flags, net_log);
689 }
690 job->AssociateWithNetLogSource(net_log);
691 int rv = job->Run(base::BindOnce(&QuicSessionPool::OnJobComplete,
692 weak_factory_.GetWeakPtr(), job.get(),
693 proxy_connect_start_time));
694 if (rv == ERR_IO_PENDING) {
695 job->AddRequest(request);
696 active_jobs_[session_key] = std::move(job);
697 return rv;
698 }
699 if (rv == OK) {
700 auto it = active_sessions_.find(session_key);
701 CHECK(it != active_sessions_.end(), base::NotFatalUntil::M130);
702 if (it == active_sessions_.end()) {
703 return ERR_QUIC_PROTOCOL_ERROR;
704 }
705 QuicChromiumClientSession* session = it->second;
706 request->SetSession(session->CreateHandle(std::move(destination)));
707 }
708 return rv;
709 }
710
CreateSessionAttempt(QuicSessionAttempt::Delegate * delegate,const QuicSessionKey & session_key,QuicEndpoint quic_endpoint,int cert_verify_flags,base::TimeTicks dns_resolution_start_time,base::TimeTicks dns_resolution_end_time,bool use_dns_aliases,std::set<std::string> dns_aliases,MultiplexedSessionCreationInitiator session_creation_initiator)711 std::unique_ptr<QuicSessionAttempt> QuicSessionPool::CreateSessionAttempt(
712 QuicSessionAttempt::Delegate* delegate,
713 const QuicSessionKey& session_key,
714 QuicEndpoint quic_endpoint,
715 int cert_verify_flags,
716 base::TimeTicks dns_resolution_start_time,
717 base::TimeTicks dns_resolution_end_time,
718 bool use_dns_aliases,
719 std::set<std::string> dns_aliases,
720 MultiplexedSessionCreationInitiator session_creation_initiator) {
721 CHECK(!HasActiveSession(session_key));
722 CHECK(!HasActiveJob(session_key));
723
724 return std::make_unique<QuicSessionAttempt>(
725 delegate, quic_endpoint.ip_endpoint, std::move(quic_endpoint.metadata),
726 quic_endpoint.quic_version, cert_verify_flags, dns_resolution_start_time,
727 dns_resolution_end_time,
728 params_.retry_on_alternate_network_before_handshake, use_dns_aliases,
729 std::move(dns_aliases),
730 CreateCryptoConfigHandle(session_key.network_anonymization_key()),
731 session_creation_initiator);
732 }
733
OnSessionGoingAway(QuicChromiumClientSession * session)734 void QuicSessionPool::OnSessionGoingAway(QuicChromiumClientSession* session) {
735 const AliasSet& aliases = session_aliases_[session];
736 for (const auto& alias : aliases) {
737 const QuicSessionKey& session_key = alias.session_key();
738 DCHECK(active_sessions_.count(session_key));
739 DCHECK_EQ(session, active_sessions_[session_key]);
740 // Track sessions which have recently gone away so that we can disable
741 // port suggestions.
742 if (session->goaway_received()) {
743 gone_away_aliases_.insert(alias);
744 }
745
746 active_sessions_.erase(session_key);
747 ProcessGoingAwaySession(session, session_key.server_id(), true);
748 }
749 ProcessGoingAwaySession(session, session->session_alias_key().server_id(),
750 false);
751 if (!aliases.empty()) {
752 DCHECK(base::Contains(session_peer_ip_, session));
753 const IPEndPoint peer_address = session_peer_ip_[session];
754 ip_aliases_[peer_address].erase(session);
755 if (ip_aliases_[peer_address].empty()) {
756 ip_aliases_.erase(peer_address);
757 }
758 session_peer_ip_.erase(session);
759 }
760 UnmapSessionFromSessionAliases(session);
761 }
762
OnSessionClosed(QuicChromiumClientSession * session)763 void QuicSessionPool::OnSessionClosed(QuicChromiumClientSession* session) {
764 DCHECK_EQ(0u, session->GetNumActiveStreams());
765 OnSessionGoingAway(session);
766 auto it = all_sessions_.find(session);
767 CHECK(it != all_sessions_.end());
768 all_sessions_.erase(it);
769 }
770
OnBlackholeAfterHandshakeConfirmed(QuicChromiumClientSession * session)771 void QuicSessionPool::OnBlackholeAfterHandshakeConfirmed(
772 QuicChromiumClientSession* session) {
773 // Reduce PING timeout when connection blackholes after the handshake.
774 if (ping_timeout_ > reduced_ping_timeout_) {
775 ping_timeout_ = reduced_ping_timeout_;
776 }
777 }
778
CancelRequest(QuicSessionRequest * request)779 void QuicSessionPool::CancelRequest(QuicSessionRequest* request) {
780 auto job_iter = active_jobs_.find(request->session_key());
781 // If an error (or network context shutdown) happens early in a
782 // `QuicSessionRequest`, before it has been added to `active_jobs_`, then
783 // this method may be called and should be resilient to the job not
784 // being in the map.
785 if (job_iter != active_jobs_.end()) {
786 job_iter->second->RemoveRequest(request);
787 }
788 }
789
SetRequestPriority(QuicSessionRequest * request,RequestPriority priority)790 void QuicSessionPool::SetRequestPriority(QuicSessionRequest* request,
791 RequestPriority priority) {
792 auto job_iter = active_jobs_.find(request->session_key());
793 if (job_iter == active_jobs_.end()) {
794 return;
795 }
796 job_iter->second->SetPriority(priority);
797 }
798
CloseAllSessions(int error,quic::QuicErrorCode quic_error)799 void QuicSessionPool::CloseAllSessions(int error,
800 quic::QuicErrorCode quic_error) {
801 base::UmaHistogramSparse("Net.QuicSession.CloseAllSessionsError", -error);
802 size_t before_active_sessions_size = active_sessions_.size();
803 size_t before_all_sessions_size = active_sessions_.size();
804 while (!active_sessions_.empty()) {
805 size_t initial_size = active_sessions_.size();
806 active_sessions_.begin()->second->CloseSessionOnError(
807 error, quic_error,
808 quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
809 DCHECK_NE(initial_size, active_sessions_.size());
810 }
811 while (!all_sessions_.empty()) {
812 size_t initial_size = all_sessions_.size();
813 (*all_sessions_.begin())
814 ->CloseSessionOnError(
815 error, quic_error,
816 quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
817 DCHECK_NE(initial_size, all_sessions_.size());
818 }
819 DCHECK(all_sessions_.empty());
820 // TODO(crbug.com/347984574): Remove before/after counts once we identified
821 // the cause.
822 net_log_.AddEvent(NetLogEventType::QUIC_SESSION_POOL_CLOSE_ALL_SESSIONS, [&] {
823 base::Value::Dict dict;
824 dict.Set("net_error", error);
825 dict.Set("quic_error", quic::QuicErrorCodeToString(quic_error));
826 dict.Set("before_active_sessions_size",
827 static_cast<int>(before_active_sessions_size));
828 dict.Set("before_all_sessions_size",
829 static_cast<int>(before_all_sessions_size));
830 dict.Set("after_active_sessions_size",
831 static_cast<int>(active_sessions_.size()));
832 dict.Set("after_all_sessions_size", static_cast<int>(all_sessions_.size()));
833 return dict;
834 });
835 }
836
QuicSessionPoolInfoToValue() const837 base::Value QuicSessionPool::QuicSessionPoolInfoToValue() const {
838 base::Value::List list;
839
840 for (const auto& active_session : active_sessions_) {
841 const quic::QuicServerId& server_id = active_session.first.server_id();
842 QuicChromiumClientSession* session = active_session.second;
843 const AliasSet& aliases = session_aliases_.find(session)->second;
844 // Only add a session to the list once.
845 if (server_id == aliases.begin()->server_id()) {
846 std::set<HostPortPair> hosts;
847 for (const auto& alias : aliases) {
848 hosts.insert(
849 HostPortPair(alias.server_id().host(), alias.server_id().port()));
850 }
851 list.Append(session->GetInfoAsValue(hosts));
852 }
853 }
854 return base::Value(std::move(list));
855 }
856
ClearCachedStatesInCryptoConfig(const base::RepeatingCallback<bool (const GURL &)> & origin_filter)857 void QuicSessionPool::ClearCachedStatesInCryptoConfig(
858 const base::RepeatingCallback<bool(const GURL&)>& origin_filter) {
859 ServerIdOriginFilter filter(origin_filter);
860 for (const auto& crypto_config : active_crypto_config_map_) {
861 crypto_config.second->config()->ClearCachedStates(filter);
862 }
863
864 for (const auto& crypto_config : recent_crypto_config_map_) {
865 crypto_config.second->config()->ClearCachedStates(filter);
866 }
867 }
868
ConnectAndConfigureSocket(CompletionOnceCallback callback,DatagramClientSocket * socket,IPEndPoint addr,handles::NetworkHandle network,const SocketTag & socket_tag)869 void QuicSessionPool::ConnectAndConfigureSocket(CompletionOnceCallback callback,
870 DatagramClientSocket* socket,
871 IPEndPoint addr,
872 handles::NetworkHandle network,
873 const SocketTag& socket_tag) {
874 socket->UseNonBlockingIO();
875
876 int rv;
877 auto split_callback = base::SplitOnceCallback(std::move(callback));
878 CompletionOnceCallback connect_callback =
879 base::BindOnce(&QuicSessionPool::FinishConnectAndConfigureSocket,
880 weak_factory_.GetWeakPtr(),
881 std::move(split_callback.first), socket, socket_tag);
882 if (!params_.migrate_sessions_on_network_change_v2) {
883 rv = socket->ConnectAsync(addr, std::move(connect_callback));
884 } else if (network == handles::kInvalidNetworkHandle) {
885 // If caller leaves network unspecified, use current default network.
886 rv = socket->ConnectUsingDefaultNetworkAsync(addr,
887 std::move(connect_callback));
888 } else {
889 rv = socket->ConnectUsingNetworkAsync(network, addr,
890 std::move(connect_callback));
891 }
892 // Both callbacks within `split_callback` will always be run asynchronously,
893 // even if a Connect call returns synchronously. Therefore we always return
894 // ERR_IO_PENDING.
895 if (rv != ERR_IO_PENDING) {
896 FinishConnectAndConfigureSocket(std::move(split_callback.second), socket,
897 socket_tag, rv);
898 }
899 }
900
FinishConnectAndConfigureSocket(CompletionOnceCallback callback,DatagramClientSocket * socket,const SocketTag & socket_tag,int rv)901 void QuicSessionPool::FinishConnectAndConfigureSocket(
902 CompletionOnceCallback callback,
903 DatagramClientSocket* socket,
904 const SocketTag& socket_tag,
905 int rv) {
906 if (rv != OK) {
907 OnFinishConnectAndConfigureSocketError(
908 std::move(callback), CREATION_ERROR_CONNECTING_SOCKET, rv);
909 return;
910 }
911
912 socket->ApplySocketTag(socket_tag);
913
914 rv = socket->SetReceiveBufferSize(kQuicSocketReceiveBufferSize);
915 if (rv != OK) {
916 OnFinishConnectAndConfigureSocketError(
917 std::move(callback), CREATION_ERROR_SETTING_RECEIVE_BUFFER, rv);
918 return;
919 }
920
921 rv = socket->SetDoNotFragment();
922 // SetDoNotFragment is not implemented on all platforms, so ignore errors.
923 if (rv != OK && rv != ERR_NOT_IMPLEMENTED) {
924 OnFinishConnectAndConfigureSocketError(
925 std::move(callback), CREATION_ERROR_SETTING_DO_NOT_FRAGMENT, rv);
926 return;
927 }
928
929 if (report_ecn_) {
930 rv = socket->SetRecvTos();
931 if (rv != OK) {
932 OnFinishConnectAndConfigureSocketError(
933 std::move(callback), CREATION_ERROR_SETTING_RECEIVE_ECN, rv);
934 return;
935 }
936 }
937
938 // Set a buffer large enough to contain the initial CWND's worth of packet
939 // to work around the problem with CHLO packets being sent out with the
940 // wrong encryption level, when the send buffer is full.
941 rv = socket->SetSendBufferSize(quic::kMaxOutgoingPacketSize * 20);
942 if (rv != OK) {
943 OnFinishConnectAndConfigureSocketError(
944 std::move(callback), CREATION_ERROR_SETTING_SEND_BUFFER, rv);
945 return;
946 }
947
948 if (params_.ios_network_service_type > 0) {
949 socket->SetIOSNetworkServiceType(params_.ios_network_service_type);
950 }
951
952 socket->GetLocalAddress(&local_address_);
953 if (need_to_check_persisted_supports_quic_) {
954 need_to_check_persisted_supports_quic_ = false;
955 if (http_server_properties_->WasLastLocalAddressWhenQuicWorked(
956 local_address_.address())) {
957 has_quic_ever_worked_on_current_network_ = true;
958 // Clear the persisted IP address, in case the network no longer supports
959 // QUIC so the next restart will require confirmation. It will be
960 // re-persisted when the first job completes successfully.
961 http_server_properties_->ClearLastLocalAddressWhenQuicWorked();
962 }
963 }
964
965 base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
966 FROM_HERE,
967 base::BindOnce(&QuicSessionPool::DoCallback, weak_factory_.GetWeakPtr(),
968 std::move(callback), rv));
969 }
970
CanWaiveIpMatching(const url::SchemeHostPort & destination,QuicChromiumClientSession * session) const971 bool QuicSessionPool::CanWaiveIpMatching(
972 const url::SchemeHostPort& destination,
973 QuicChromiumClientSession* session) const {
974 // Checks if `destination` matches the alias key of `session`.
975 if (destination == session->session_alias_key().destination()) {
976 return true;
977 }
978
979 if (ignore_ip_matching_when_finding_existing_sessions_ &&
980 session->config()->HasReceivedConnectionOptions() &&
981 quic::ContainsQuicTag(session->config()->ReceivedConnectionOptions(),
982 quic::kNOIP)) {
983 return true;
984 }
985
986 // Check received origins.
987 if (skip_dns_with_origin_frame_ &&
988 session->received_origins().contains(destination)) {
989 return true;
990 }
991 return false;
992 }
993
OnFinishConnectAndConfigureSocketError(CompletionOnceCallback callback,enum CreateSessionFailure error,int rv)994 void QuicSessionPool::OnFinishConnectAndConfigureSocketError(
995 CompletionOnceCallback callback,
996 enum CreateSessionFailure error,
997 int rv) {
998 DCHECK(callback);
999 HistogramCreateSessionFailure(error);
1000 base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
1001 FROM_HERE,
1002 base::BindOnce(&QuicSessionPool::DoCallback, weak_factory_.GetWeakPtr(),
1003 std::move(callback), rv));
1004 }
1005
DoCallback(CompletionOnceCallback callback,int rv)1006 void QuicSessionPool::DoCallback(CompletionOnceCallback callback, int rv) {
1007 std::move(callback).Run(rv);
1008 }
1009
ConfigureSocket(DatagramClientSocket * socket,IPEndPoint addr,handles::NetworkHandle network,const SocketTag & socket_tag)1010 int QuicSessionPool::ConfigureSocket(DatagramClientSocket* socket,
1011 IPEndPoint addr,
1012 handles::NetworkHandle network,
1013 const SocketTag& socket_tag) {
1014 socket->UseNonBlockingIO();
1015
1016 int rv;
1017 if (!params_.migrate_sessions_on_network_change_v2) {
1018 rv = socket->Connect(addr);
1019 } else if (network == handles::kInvalidNetworkHandle) {
1020 // If caller leaves network unspecified, use current default network.
1021 rv = socket->ConnectUsingDefaultNetwork(addr);
1022 } else {
1023 rv = socket->ConnectUsingNetwork(network, addr);
1024 }
1025 if (rv != OK) {
1026 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET);
1027 return rv;
1028 }
1029
1030 socket->ApplySocketTag(socket_tag);
1031
1032 rv = socket->SetReceiveBufferSize(kQuicSocketReceiveBufferSize);
1033 if (rv != OK) {
1034 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER);
1035 return rv;
1036 }
1037
1038 rv = socket->SetDoNotFragment();
1039 // SetDoNotFragment is not implemented on all platforms, so ignore errors.
1040 if (rv != OK && rv != ERR_NOT_IMPLEMENTED) {
1041 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_DO_NOT_FRAGMENT);
1042 return rv;
1043 }
1044
1045 if (report_ecn_) {
1046 rv = socket->SetRecvTos();
1047 if (rv != OK) {
1048 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_ECN);
1049 return rv;
1050 }
1051 }
1052
1053 // Set a buffer large enough to contain the initial CWND's worth of packet
1054 // to work around the problem with CHLO packets being sent out with the
1055 // wrong encryption level, when the send buffer is full.
1056 rv = socket->SetSendBufferSize(quic::kMaxOutgoingPacketSize * 20);
1057 if (rv != OK) {
1058 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER);
1059 return rv;
1060 }
1061
1062 if (params_.ios_network_service_type > 0) {
1063 socket->SetIOSNetworkServiceType(params_.ios_network_service_type);
1064 }
1065
1066 socket->GetLocalAddress(&local_address_);
1067 if (need_to_check_persisted_supports_quic_) {
1068 need_to_check_persisted_supports_quic_ = false;
1069 if (http_server_properties_->WasLastLocalAddressWhenQuicWorked(
1070 local_address_.address())) {
1071 has_quic_ever_worked_on_current_network_ = true;
1072 // Clear the persisted IP address, in case the network no longer supports
1073 // QUIC so the next restart will require confirmation. It will be
1074 // re-persisted when the first job completes successfully.
1075 http_server_properties_->ClearLastLocalAddressWhenQuicWorked();
1076 }
1077 }
1078
1079 return OK;
1080 }
1081
FindAlternateNetwork(handles::NetworkHandle old_network)1082 handles::NetworkHandle QuicSessionPool::FindAlternateNetwork(
1083 handles::NetworkHandle old_network) {
1084 // Find a new network that sessions bound to |old_network| can be migrated to.
1085 NetworkChangeNotifier::NetworkList network_list;
1086 NetworkChangeNotifier::GetConnectedNetworks(&network_list);
1087 for (handles::NetworkHandle new_network : network_list) {
1088 if (new_network != old_network) {
1089 return new_network;
1090 }
1091 }
1092 return handles::kInvalidNetworkHandle;
1093 }
1094
CreateSocket(NetLog * net_log,const NetLogSource & source)1095 std::unique_ptr<DatagramClientSocket> QuicSessionPool::CreateSocket(
1096 NetLog* net_log,
1097 const NetLogSource& source) {
1098 auto socket = client_socket_factory_->CreateDatagramClientSocket(
1099 DatagramSocket::DEFAULT_BIND, net_log, source);
1100 if (params_.enable_socket_recv_optimization) {
1101 socket->EnableRecvOptimization();
1102 }
1103 return socket;
1104 }
1105
OnIPAddressChanged()1106 void QuicSessionPool::OnIPAddressChanged() {
1107 net_log_.AddEvent(NetLogEventType::QUIC_SESSION_POOL_ON_IP_ADDRESS_CHANGED);
1108 CollectDataOnPlatformNotification(NETWORK_IP_ADDRESS_CHANGED,
1109 handles::kInvalidNetworkHandle);
1110 // Do nothing if connection migration is turned on.
1111 if (params_.migrate_sessions_on_network_change_v2) {
1112 return;
1113 }
1114
1115 connectivity_monitor_.OnIPAddressChanged();
1116
1117 set_has_quic_ever_worked_on_current_network(false);
1118 if (params_.close_sessions_on_ip_change) {
1119 CloseAllSessions(ERR_NETWORK_CHANGED, quic::QUIC_IP_ADDRESS_CHANGED);
1120 } else {
1121 DCHECK(params_.goaway_sessions_on_ip_change);
1122 MarkAllActiveSessionsGoingAway(kIPAddressChanged);
1123 }
1124 }
1125
OnNetworkConnected(handles::NetworkHandle network)1126 void QuicSessionPool::OnNetworkConnected(handles::NetworkHandle network) {
1127 CollectDataOnPlatformNotification(NETWORK_CONNECTED, network);
1128 if (params_.migrate_sessions_on_network_change_v2) {
1129 net_log_.AddEvent(NetLogEventType::QUIC_SESSION_POOL_PLATFORM_NOTIFICATION,
1130 [&] {
1131 base::Value::Dict dict;
1132 dict.Set("signal", "OnNetworkConnected");
1133 dict.Set("network", base::NumberToString(network));
1134 return dict;
1135 });
1136 }
1137 // Broadcast network connected to all sessions.
1138 // If migration is not turned on, session will not migrate but collect data.
1139 auto it = all_sessions_.begin();
1140 // Sessions may be deleted while iterating through the set.
1141 while (it != all_sessions_.end()) {
1142 QuicChromiumClientSession* session = it->get();
1143 ++it;
1144 session->OnNetworkConnected(network);
1145 }
1146 }
1147
OnNetworkDisconnected(handles::NetworkHandle network)1148 void QuicSessionPool::OnNetworkDisconnected(handles::NetworkHandle network) {
1149 CollectDataOnPlatformNotification(NETWORK_DISCONNECTED, network);
1150 if (params_.migrate_sessions_on_network_change_v2) {
1151 net_log_.AddEvent(NetLogEventType::QUIC_SESSION_POOL_PLATFORM_NOTIFICATION,
1152 [&] {
1153 base::Value::Dict dict;
1154 dict.Set("signal", "OnNetworkDisconnected");
1155 dict.Set("network", base::NumberToString(network));
1156 return dict;
1157 });
1158 }
1159 // Broadcast network disconnected to all sessions.
1160 // If migration is not turned on, session will not migrate but collect data.
1161 auto it = all_sessions_.begin();
1162 // Sessions may be deleted while iterating through the set.
1163 while (it != all_sessions_.end()) {
1164 QuicChromiumClientSession* session = it->get();
1165 ++it;
1166 session->OnNetworkDisconnectedV2(/*disconnected_network*/ network);
1167 }
1168 }
1169
1170 // This method is expected to only be called when migrating from Cellular to
1171 // WiFi on Android, and should always be preceded by OnNetworkMadeDefault().
OnNetworkSoonToDisconnect(handles::NetworkHandle network)1172 void QuicSessionPool::OnNetworkSoonToDisconnect(
1173 handles::NetworkHandle network) {
1174 CollectDataOnPlatformNotification(NETWORK_SOON_TO_DISCONNECT, network);
1175 }
1176
OnNetworkMadeDefault(handles::NetworkHandle network)1177 void QuicSessionPool::OnNetworkMadeDefault(handles::NetworkHandle network) {
1178 CollectDataOnPlatformNotification(NETWORK_MADE_DEFAULT, network);
1179 connectivity_monitor_.OnDefaultNetworkUpdated(network);
1180
1181 // Clear alternative services that were marked as broken until default network
1182 // changes.
1183 if (params_.retry_on_alternate_network_before_handshake &&
1184 default_network_ != handles::kInvalidNetworkHandle &&
1185 network != default_network_) {
1186 http_server_properties_->OnDefaultNetworkChanged();
1187 }
1188
1189 DCHECK_NE(handles::kInvalidNetworkHandle, network);
1190 default_network_ = network;
1191
1192 if (params_.migrate_sessions_on_network_change_v2) {
1193 net_log_.AddEvent(NetLogEventType::QUIC_SESSION_POOL_PLATFORM_NOTIFICATION,
1194 [&] {
1195 base::Value::Dict dict;
1196 dict.Set("signal", "OnNetworkMadeDefault");
1197 dict.Set("network", base::NumberToString(network));
1198 return dict;
1199 });
1200 }
1201
1202 auto it = all_sessions_.begin();
1203 // Sessions may be deleted while iterating through the set.
1204 while (it != all_sessions_.end()) {
1205 QuicChromiumClientSession* session = it->get();
1206 ++it;
1207 session->OnNetworkMadeDefault(network);
1208 }
1209 if (params_.migrate_sessions_on_network_change_v2) {
1210 set_has_quic_ever_worked_on_current_network(false);
1211 }
1212 }
1213
OnTrustStoreChanged()1214 void QuicSessionPool::OnTrustStoreChanged() {
1215 // We should flush the sessions if we removed trust from a
1216 // cert, because a previously trusted server may have become
1217 // untrusted.
1218 //
1219 // We should not flush the sessions if we added trust to a cert.
1220 //
1221 // Since the OnTrustStoreChanged method doesn't tell us what
1222 // kind of change it is, we have to flush the socket
1223 // pools to be safe.
1224 MarkAllActiveSessionsGoingAway(kCertDBChanged);
1225 }
1226
OnCertVerifierChanged()1227 void QuicSessionPool::OnCertVerifierChanged() {
1228 // Flush sessions if the CertCerifier configuration has changed.
1229 MarkAllActiveSessionsGoingAway(kCertVerifierChanged);
1230 }
1231
set_has_quic_ever_worked_on_current_network(bool has_quic_ever_worked_on_current_network)1232 void QuicSessionPool::set_has_quic_ever_worked_on_current_network(
1233 bool has_quic_ever_worked_on_current_network) {
1234 has_quic_ever_worked_on_current_network_ =
1235 has_quic_ever_worked_on_current_network;
1236 if (!(local_address_ == IPEndPoint())) {
1237 if (has_quic_ever_worked_on_current_network_) {
1238 http_server_properties_->SetLastLocalAddressWhenQuicWorked(
1239 local_address_.address());
1240 } else {
1241 http_server_properties_->ClearLastLocalAddressWhenQuicWorked();
1242 }
1243 }
1244 }
1245
GetTimeDelayForWaitingJob(const QuicSessionKey & session_key)1246 base::TimeDelta QuicSessionPool::GetTimeDelayForWaitingJob(
1247 const QuicSessionKey& session_key) {
1248 if (time_delay_for_waiting_job_for_testing_.has_value()) {
1249 return *time_delay_for_waiting_job_for_testing_;
1250 }
1251
1252 // If |is_quic_known_to_work_on_current_network_| is false, then one of the
1253 // following is true:
1254 // 1) This is startup and QuicSessionPool::CreateSession() and
1255 // ConfigureSocket() have yet to be called, and it is not yet known
1256 // if the current network is the last one where QUIC worked.
1257 // 2) Startup has been completed, and QUIC has not been used
1258 // successfully since startup, or on this network before.
1259 if (!has_quic_ever_worked_on_current_network_) {
1260 // If |need_to_check_persisted_supports_quic_| is false, this is case 1)
1261 // above. If HasLastLocalAddressWhenQuicWorked() is also true, then there's
1262 // a chance the current network is the last one on which QUIC worked. So
1263 // only delay the request if there's no chance that is the case.
1264 if (!need_to_check_persisted_supports_quic_ ||
1265 !http_server_properties_->HasLastLocalAddressWhenQuicWorked()) {
1266 return base::TimeDelta();
1267 }
1268 }
1269
1270 // QUIC was recently broken. Do not delay the main job.
1271 if (WasQuicRecentlyBroken(session_key)) {
1272 return base::TimeDelta();
1273 }
1274
1275 int64_t srtt = 1.5 * GetServerNetworkStatsSmoothedRttInMicroseconds(
1276 session_key.server_id(),
1277 session_key.network_anonymization_key());
1278 // Picked 300ms based on mean time from
1279 // Net.QuicSession.HostResolution.HandshakeConfirmedTime histogram.
1280 const int kDefaultRTT = 300 * quic::kNumMicrosPerMilli;
1281 if (!srtt) {
1282 srtt = kDefaultRTT;
1283 }
1284 return base::Microseconds(srtt);
1285 }
1286
GetDnsAliasesForSessionKey(const QuicSessionKey & key) const1287 const std::set<std::string>& QuicSessionPool::GetDnsAliasesForSessionKey(
1288 const QuicSessionKey& key) const {
1289 auto it = dns_aliases_by_session_key_.find(key);
1290
1291 if (it == dns_aliases_by_session_key_.end()) {
1292 static const base::NoDestructor<std::set<std::string>> emptyvector_result;
1293 return *emptyvector_result;
1294 }
1295
1296 return it->second;
1297 }
1298
ActivateSessionForTesting(std::unique_ptr<QuicChromiumClientSession> new_session)1299 void QuicSessionPool::ActivateSessionForTesting(
1300 std::unique_ptr<QuicChromiumClientSession> new_session) {
1301 QuicChromiumClientSession* session = new_session.get();
1302 all_sessions_.insert(std::move(new_session));
1303 ActivateSession(session->session_alias_key(), session,
1304 std::set<std::string>());
1305 }
1306
DeactivateSessionForTesting(QuicChromiumClientSession * session)1307 void QuicSessionPool::DeactivateSessionForTesting(
1308 QuicChromiumClientSession* session) {
1309 OnSessionGoingAway(session);
1310 auto it = all_sessions_.find(session);
1311 CHECK(it != all_sessions_.end());
1312 all_sessions_.erase(it);
1313 }
1314
SetTimeDelayForWaitingJobForTesting(base::TimeDelta delay)1315 void QuicSessionPool::SetTimeDelayForWaitingJobForTesting(
1316 base::TimeDelta delay) {
1317 time_delay_for_waiting_job_for_testing_ = delay;
1318 }
1319
SelectQuicVersion(const quic::ParsedQuicVersion & known_quic_version,const ConnectionEndpointMetadata & metadata,bool svcb_optional) const1320 quic::ParsedQuicVersion QuicSessionPool::SelectQuicVersion(
1321 const quic::ParsedQuicVersion& known_quic_version,
1322 const ConnectionEndpointMetadata& metadata,
1323 bool svcb_optional) const {
1324 if (metadata.supported_protocol_alpns.empty()) {
1325 // `metadata` doesn't contain QUIC ALPN. If we know the QUIC ALPN to use
1326 // externally, i.e. via Alt-Svc, use it in SVCB-optional mode. Otherwise,
1327 // the endpoint associated with `metadata` is not eligible for QUIC.
1328 return svcb_optional ? known_quic_version
1329 : quic::ParsedQuicVersion::Unsupported();
1330 }
1331
1332 // Otherwise, `metadata` came from an HTTPS/SVCB record. We can use
1333 // QUIC if a suitable match is found in the record's ALPN list.
1334 // Additionally, if this connection attempt came from Alt-Svc, the DNS
1335 // result must be consistent with it. See
1336 // https://datatracker.ietf.org/doc/html/rfc9460#name-interaction-with-alt-svc
1337 if (known_quic_version.IsKnown()) {
1338 std::string expected_alpn = quic::AlpnForVersion(known_quic_version);
1339 if (base::Contains(metadata.supported_protocol_alpns,
1340 quic::AlpnForVersion(known_quic_version))) {
1341 return known_quic_version;
1342 }
1343 return quic::ParsedQuicVersion::Unsupported();
1344 }
1345
1346 for (const auto& alpn : metadata.supported_protocol_alpns) {
1347 for (const auto& supported_version : supported_versions()) {
1348 if (alpn == AlpnForVersion(supported_version)) {
1349 return supported_version;
1350 }
1351 }
1352 }
1353
1354 return quic::ParsedQuicVersion::Unsupported();
1355 }
1356
1357 // static
LogConnectionIpPooling(bool pooled)1358 void QuicSessionPool::LogConnectionIpPooling(bool pooled) {
1359 base::UmaHistogramBoolean("Net.QuicSession.ConnectionIpPooled", pooled);
1360 }
1361
HasMatchingIpSession(const QuicSessionAliasKey & key,const std::vector<IPEndPoint> & ip_endpoints,const std::set<std::string> & aliases,bool use_dns_aliases)1362 bool QuicSessionPool::HasMatchingIpSession(
1363 const QuicSessionAliasKey& key,
1364 const std::vector<IPEndPoint>& ip_endpoints,
1365 const std::set<std::string>& aliases,
1366 bool use_dns_aliases) {
1367 const quic::QuicServerId& server_id(key.server_id());
1368 DCHECK(!HasActiveSession(key.session_key()));
1369 for (const auto& address : ip_endpoints) {
1370 if (!base::Contains(ip_aliases_, address)) {
1371 continue;
1372 }
1373
1374 const SessionSet& sessions = ip_aliases_[address];
1375 for (QuicChromiumClientSession* session : sessions) {
1376 if (!session->CanPool(server_id.host(), key.session_key())) {
1377 continue;
1378 }
1379 std::set<std::string> dns_aliases;
1380 if (use_dns_aliases) {
1381 dns_aliases = aliases;
1382 }
1383 ActivateAndMapSessionToAliasKey(session, key, std::move(dns_aliases));
1384 LogFindMatchingIpSessionResult(net_log_, MATCHING_IP_SESSION_FOUND,
1385 session, key.destination());
1386 return true;
1387 }
1388 }
1389
1390 bool can_pool = false;
1391 static constexpr uint32_t kMaxLoopCount = 200;
1392 uint32_t loop_count = 0;
1393 for (const auto& entry : active_sessions_) {
1394 ++loop_count;
1395 if (loop_count >= kMaxLoopCount) {
1396 break;
1397 }
1398 QuicChromiumClientSession* session = entry.second;
1399 if (!session->CanPool(server_id.host(), key.session_key())) {
1400 continue;
1401 }
1402 can_pool = true;
1403 // TODO(fayang): consider to use CanWaiveIpMatching().
1404 if (session->received_origins().contains(key.destination()) ||
1405 (ignore_ip_matching_when_finding_existing_sessions_ &&
1406 session->config()->HasReceivedConnectionOptions() &&
1407 quic::ContainsQuicTag(session->config()->ReceivedConnectionOptions(),
1408 quic::kNOIP))) {
1409 std::set<std::string> dns_aliases;
1410 if (use_dns_aliases) {
1411 dns_aliases = aliases;
1412 }
1413 ActivateAndMapSessionToAliasKey(session, key, std::move(dns_aliases));
1414 LogFindMatchingIpSessionResult(net_log_, POOLED_WITH_DIFFERENT_IP_SESSION,
1415 session, key.destination());
1416 return true;
1417 }
1418 }
1419 if (can_pool) {
1420 LogFindMatchingIpSessionResult(net_log_, CAN_POOL_BUT_DIFFERENT_IP,
1421 /*session=*/nullptr, key.destination());
1422 } else {
1423 LogFindMatchingIpSessionResult(net_log_, CANNOT_POOL_WITH_EXISTING_SESSIONS,
1424 /*session=*/nullptr, key.destination());
1425 }
1426 return false;
1427 }
1428
OnJobComplete(Job * job,std::optional<base::TimeTicks> proxy_connect_start_time,int rv)1429 void QuicSessionPool::OnJobComplete(
1430 Job* job,
1431 std::optional<base::TimeTicks> proxy_connect_start_time,
1432 int rv) {
1433 auto iter = active_jobs_.find(job->key().session_key());
1434 if (proxy_connect_start_time) {
1435 HttpProxyConnectJob::EmitConnectLatency(
1436 NextProto::kProtoQUIC, ProxyServer::Scheme::SCHEME_QUIC,
1437 rv == 0 ? HttpProxyConnectJob::HttpConnectResult::kSuccess
1438 : HttpProxyConnectJob::HttpConnectResult::kError,
1439 base::TimeTicks::Now() - *proxy_connect_start_time);
1440 }
1441
1442 CHECK(iter != active_jobs_.end(), base::NotFatalUntil::M130);
1443 if (rv == OK) {
1444 if (!has_quic_ever_worked_on_current_network_) {
1445 set_has_quic_ever_worked_on_current_network(true);
1446 }
1447
1448 auto session_it = active_sessions_.find(job->key().session_key());
1449 CHECK(session_it != active_sessions_.end());
1450 QuicChromiumClientSession* session = session_it->second;
1451 for (QuicSessionRequest* request : iter->second->requests()) {
1452 // Do not notify |request| yet.
1453 request->SetSession(session->CreateHandle(job->key().destination()));
1454 }
1455 }
1456
1457 for (QuicSessionRequest* request : iter->second->requests()) {
1458 // Even though we're invoking callbacks here, we don't need to worry
1459 // about |this| being deleted, because the pool is owned by the
1460 // profile which can not be deleted via callbacks.
1461 if (rv < 0) {
1462 job->PopulateNetErrorDetails(request->net_error_details());
1463 }
1464 request->OnRequestComplete(rv);
1465 }
1466 active_jobs_.erase(iter);
1467 }
1468
HasActiveSession(const QuicSessionKey & session_key) const1469 bool QuicSessionPool::HasActiveSession(
1470 const QuicSessionKey& session_key) const {
1471 return base::Contains(active_sessions_, session_key);
1472 }
1473
HasActiveJob(const QuicSessionKey & session_key) const1474 bool QuicSessionPool::HasActiveJob(const QuicSessionKey& session_key) const {
1475 return base::Contains(active_jobs_, session_key);
1476 }
1477
CreateSessionSync(QuicSessionAliasKey key,quic::ParsedQuicVersion quic_version,int cert_verify_flags,bool require_confirmation,IPEndPoint peer_address,ConnectionEndpointMetadata metadata,base::TimeTicks dns_resolution_start_time,base::TimeTicks dns_resolution_end_time,const NetLogWithSource & net_log,raw_ptr<QuicChromiumClientSession> * session,handles::NetworkHandle * network,MultiplexedSessionCreationInitiator session_creation_initiator)1478 int QuicSessionPool::CreateSessionSync(
1479 QuicSessionAliasKey key,
1480 quic::ParsedQuicVersion quic_version,
1481 int cert_verify_flags,
1482 bool require_confirmation,
1483 IPEndPoint peer_address,
1484 ConnectionEndpointMetadata metadata,
1485 base::TimeTicks dns_resolution_start_time,
1486 base::TimeTicks dns_resolution_end_time,
1487 const NetLogWithSource& net_log,
1488 raw_ptr<QuicChromiumClientSession>* session,
1489 handles::NetworkHandle* network,
1490 MultiplexedSessionCreationInitiator session_creation_initiator) {
1491 *session = nullptr;
1492 // TODO(crbug.com/40256842): This logic only knows how to try one IP
1493 // endpoint.
1494 std::unique_ptr<DatagramClientSocket> socket(
1495 CreateSocket(net_log.net_log(), net_log.source()));
1496
1497 // If migrate_sessions_on_network_change_v2 is on, passing in
1498 // handles::kInvalidNetworkHandle will bind the socket to the default network.
1499 int rv = ConfigureSocket(socket.get(), peer_address, *network,
1500 key.session_key().socket_tag());
1501 if (rv != OK) {
1502 return rv;
1503 }
1504 base::expected<QuicSessionAttempt::CreateSessionResult, int> result =
1505 CreateSessionHelper(std::move(key), quic_version, cert_verify_flags,
1506 require_confirmation, std::move(peer_address),
1507 std::move(metadata), dns_resolution_start_time,
1508 dns_resolution_end_time,
1509 /*session_max_packet_length=*/0, net_log, *network,
1510 std::move(socket), session_creation_initiator);
1511 if (!result.has_value()) {
1512 return result.error();
1513 }
1514
1515 *session = result->session;
1516 *network = result->network;
1517 return OK;
1518 }
1519
CreateSessionAsync(CreateSessionCallback callback,QuicSessionAliasKey key,quic::ParsedQuicVersion quic_version,int cert_verify_flags,bool require_confirmation,IPEndPoint peer_address,ConnectionEndpointMetadata metadata,base::TimeTicks dns_resolution_start_time,base::TimeTicks dns_resolution_end_time,const NetLogWithSource & net_log,handles::NetworkHandle network,MultiplexedSessionCreationInitiator session_creation_initiator)1520 int QuicSessionPool::CreateSessionAsync(
1521 CreateSessionCallback callback,
1522 QuicSessionAliasKey key,
1523 quic::ParsedQuicVersion quic_version,
1524 int cert_verify_flags,
1525 bool require_confirmation,
1526 IPEndPoint peer_address,
1527 ConnectionEndpointMetadata metadata,
1528 base::TimeTicks dns_resolution_start_time,
1529 base::TimeTicks dns_resolution_end_time,
1530 const NetLogWithSource& net_log,
1531 handles::NetworkHandle network,
1532 MultiplexedSessionCreationInitiator session_creation_initiator) {
1533 // TODO(crbug.com/40256842): This logic only knows how to try one IP
1534 // endpoint.
1535 std::unique_ptr<DatagramClientSocket> socket(
1536 CreateSocket(net_log.net_log(), net_log.source()));
1537 DatagramClientSocket* socket_ptr = socket.get();
1538 CompletionOnceCallback connect_and_configure_callback = base::BindOnce(
1539 &QuicSessionPool::FinishCreateSession, weak_factory_.GetWeakPtr(),
1540 std::move(callback), std::move(key), quic_version, cert_verify_flags,
1541 require_confirmation, peer_address, std::move(metadata),
1542 dns_resolution_start_time, dns_resolution_end_time,
1543 /*session_max_packet_length=*/0, net_log, network, std::move(socket),
1544 session_creation_initiator);
1545
1546 // If migrate_sessions_on_network_change_v2 is on, passing in
1547 // handles::kInvalidNetworkHandle will bind the socket to the default network.
1548 ConnectAndConfigureSocket(std::move(connect_and_configure_callback),
1549 socket_ptr, std::move(peer_address), network,
1550 key.session_key().socket_tag());
1551 return ERR_IO_PENDING;
1552 }
1553
CreateSessionOnProxyStream(CreateSessionCallback callback,QuicSessionAliasKey key,quic::ParsedQuicVersion quic_version,int cert_verify_flags,bool require_confirmation,IPEndPoint local_address,IPEndPoint proxy_peer_address,std::unique_ptr<QuicChromiumClientStream::Handle> proxy_stream,std::string user_agent,const NetLogWithSource & net_log,handles::NetworkHandle network)1554 int QuicSessionPool::CreateSessionOnProxyStream(
1555 CreateSessionCallback callback,
1556 QuicSessionAliasKey key,
1557 quic::ParsedQuicVersion quic_version,
1558 int cert_verify_flags,
1559 bool require_confirmation,
1560 IPEndPoint local_address,
1561 IPEndPoint proxy_peer_address,
1562 std::unique_ptr<QuicChromiumClientStream::Handle> proxy_stream,
1563 std::string user_agent,
1564 const NetLogWithSource& net_log,
1565 handles::NetworkHandle network) {
1566 // Use the host and port from the proxy server along with the example URI
1567 // template in https://datatracker.ietf.org/doc/html/rfc9298#section-2.
1568 const ProxyChain& proxy_chain = key.session_key().proxy_chain();
1569 const ProxyServer& last_proxy = proxy_chain.Last();
1570 const quic::QuicServerId& server_id = key.server_id();
1571 const std::string encocded_host =
1572 base::EscapeQueryParamValue(last_proxy.GetHost().c_str(), false);
1573 GURL url(base::StringPrintf("https://%s:%d/.well-known/masque/udp/%s/%d/",
1574 last_proxy.GetHost().c_str(),
1575 last_proxy.GetPort(), server_id.host().c_str(),
1576 server_id.port()));
1577
1578 auto socket = std::make_unique<QuicProxyDatagramClientSocket>(
1579 url, key.session_key().proxy_chain(), user_agent, net_log,
1580 proxy_delegate_);
1581 QuicProxyDatagramClientSocket* socket_ptr = socket.get();
1582
1583 socket->ApplySocketTag(key.session_key().socket_tag());
1584
1585 // No host resolution took place, so pass an empty metadata,
1586 // pretend resolution started and ended right now, and pass an
1587 // invalid network handle. Connections on an invalid network will
1588 // not be migrated due to network changes.
1589 ConnectionEndpointMetadata metadata;
1590 auto dns_resolution_time = base::TimeTicks::Now();
1591
1592 // Maximum packet length for the session inside this stream is limited
1593 // by the largest message payload allowed, accounting for the quarter-stream
1594 // ID (up to 8 bytes) and the context ID (1 byte). If we cannot determine the
1595 // max payload size for the stream, or there is no room for the overhead, use
1596 // 0 as a sentinel value to use the default packet size.
1597 quic::QuicPacketLength quarter_stream_id_length =
1598 quiche::QuicheDataWriter::GetVarInt62Len(proxy_stream->id() / 4);
1599 constexpr quic::QuicPacketLength context_id_length = 1;
1600 quic::QuicPacketLength guaranteed_largest_message_payload =
1601 proxy_stream->GetGuaranteedLargestMessagePayload();
1602 quic::QuicPacketLength overhead =
1603 quarter_stream_id_length + context_id_length;
1604 quic::QuicPacketLength session_max_packet_length =
1605 guaranteed_largest_message_payload > overhead
1606 ? guaranteed_largest_message_payload - overhead
1607 : 0;
1608
1609 auto [on_connected_via_stream_async, on_connected_via_stream_sync] =
1610 base::SplitOnceCallback(base::BindOnce(
1611 &QuicSessionPool::FinishCreateSession, weak_factory_.GetWeakPtr(),
1612 std::move(callback), std::move(key), quic_version, cert_verify_flags,
1613 require_confirmation, proxy_peer_address, std::move(metadata),
1614 dns_resolution_time, dns_resolution_time, session_max_packet_length,
1615 net_log, network, std::move(socket),
1616 MultiplexedSessionCreationInitiator::kUnknown));
1617
1618 int rv = socket_ptr->ConnectViaStream(
1619 std::move(local_address), std::move(proxy_peer_address),
1620 std::move(proxy_stream), std::move(on_connected_via_stream_async));
1621 if (rv != ERR_IO_PENDING) {
1622 base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
1623 FROM_HERE, base::BindOnce([](CompletionOnceCallback callback,
1624 int rv) { std::move(callback).Run(rv); },
1625 std::move(on_connected_via_stream_sync), rv));
1626 }
1627
1628 return ERR_IO_PENDING;
1629 }
1630
FinishCreateSession(CreateSessionCallback callback,QuicSessionAliasKey key,quic::ParsedQuicVersion quic_version,int cert_verify_flags,bool require_confirmation,IPEndPoint peer_address,ConnectionEndpointMetadata metadata,base::TimeTicks dns_resolution_start_time,base::TimeTicks dns_resolution_end_time,quic::QuicPacketLength session_max_packet_length,const NetLogWithSource & net_log,handles::NetworkHandle network,std::unique_ptr<DatagramClientSocket> socket,MultiplexedSessionCreationInitiator session_creation_initiator,int rv)1631 void QuicSessionPool::FinishCreateSession(
1632 CreateSessionCallback callback,
1633 QuicSessionAliasKey key,
1634 quic::ParsedQuicVersion quic_version,
1635 int cert_verify_flags,
1636 bool require_confirmation,
1637 IPEndPoint peer_address,
1638 ConnectionEndpointMetadata metadata,
1639 base::TimeTicks dns_resolution_start_time,
1640 base::TimeTicks dns_resolution_end_time,
1641 quic::QuicPacketLength session_max_packet_length,
1642 const NetLogWithSource& net_log,
1643 handles::NetworkHandle network,
1644 std::unique_ptr<DatagramClientSocket> socket,
1645 MultiplexedSessionCreationInitiator session_creation_initiator,
1646 int rv) {
1647 if (rv != OK) {
1648 std::move(callback).Run(base::unexpected(rv));
1649 return;
1650 }
1651 base::expected<QuicSessionAttempt::CreateSessionResult, int> result =
1652 CreateSessionHelper(std::move(key), quic_version, cert_verify_flags,
1653 require_confirmation, std::move(peer_address),
1654 std::move(metadata), dns_resolution_start_time,
1655 dns_resolution_end_time, session_max_packet_length,
1656 net_log, network, std::move(socket),
1657 session_creation_initiator);
1658 std::move(callback).Run(std::move(result));
1659 }
1660
1661 base::expected<QuicSessionAttempt::CreateSessionResult, int>
CreateSessionHelper(QuicSessionAliasKey key,quic::ParsedQuicVersion quic_version,int cert_verify_flags,bool require_confirmation,IPEndPoint peer_address,ConnectionEndpointMetadata metadata,base::TimeTicks dns_resolution_start_time,base::TimeTicks dns_resolution_end_time,quic::QuicPacketLength session_max_packet_length,const NetLogWithSource & net_log,handles::NetworkHandle network,std::unique_ptr<DatagramClientSocket> socket,MultiplexedSessionCreationInitiator session_creation_initiator)1662 QuicSessionPool::CreateSessionHelper(
1663 QuicSessionAliasKey key,
1664 quic::ParsedQuicVersion quic_version,
1665 int cert_verify_flags,
1666 bool require_confirmation,
1667 IPEndPoint peer_address,
1668 ConnectionEndpointMetadata metadata,
1669 base::TimeTicks dns_resolution_start_time,
1670 base::TimeTicks dns_resolution_end_time,
1671 quic::QuicPacketLength session_max_packet_length,
1672 const NetLogWithSource& net_log,
1673 handles::NetworkHandle network,
1674 std::unique_ptr<DatagramClientSocket> socket,
1675 MultiplexedSessionCreationInitiator session_creation_initiator) {
1676 const quic::QuicServerId& server_id = key.server_id();
1677
1678 if (params_.migrate_sessions_on_network_change_v2 &&
1679 network == handles::kInvalidNetworkHandle) {
1680 network = socket->GetBoundNetwork();
1681 if (default_network_ == handles::kInvalidNetworkHandle) {
1682 // QuicSessionPool may miss the default network signal before its
1683 // creation, update |default_network_| when the first socket is bound
1684 // to the default network.
1685 default_network_ = network;
1686 connectivity_monitor_.SetInitialDefaultNetwork(default_network_);
1687 } else {
1688 UMA_HISTOGRAM_BOOLEAN("Net.QuicStreamFactory.DefaultNetworkMatch",
1689 default_network_ == network);
1690 }
1691 }
1692
1693 if (!helper_.get()) {
1694 helper_ = std::make_unique<QuicChromiumConnectionHelper>(clock_,
1695 random_generator_);
1696 }
1697
1698 if (!alarm_factory_.get()) {
1699 alarm_factory_ = std::make_unique<QuicChromiumAlarmFactory>(
1700 base::SingleThreadTaskRunner::GetCurrentDefault().get(), clock_);
1701 }
1702
1703 quic::QuicConnectionId connection_id =
1704 quic::QuicUtils::CreateRandomConnectionId(random_generator_);
1705 std::unique_ptr<QuicServerInfo> server_info;
1706 if (params_.max_server_configs_stored_in_properties > 0) {
1707 server_info = std::make_unique<PropertiesBasedQuicServerInfo>(
1708 server_id, key.session_key().privacy_mode(),
1709 key.session_key().network_anonymization_key(), http_server_properties_);
1710 }
1711 std::unique_ptr<CryptoClientConfigHandle> crypto_config_handle =
1712 CreateCryptoConfigHandle(key.session_key().network_anonymization_key());
1713 InitializeCachedStateInCryptoConfig(*crypto_config_handle, server_id,
1714 server_info);
1715
1716 QuicChromiumPacketWriter* writer =
1717 new QuicChromiumPacketWriter(socket.get(), task_runner_.get());
1718 quic::QuicConnection* connection = new quic::QuicConnection(
1719 connection_id, quic::QuicSocketAddress(),
1720 ToQuicSocketAddress(peer_address), helper_.get(), alarm_factory_.get(),
1721 writer, true /* owns_writer */, quic::Perspective::IS_CLIENT,
1722 {quic_version}, connection_id_generator_);
1723 connection->set_keep_alive_ping_timeout(ping_timeout_);
1724
1725 // Calculate the max packet length for this connection. If the session is
1726 // carrying proxy traffic, add the `additional_proxy_packet_length`.
1727 size_t max_packet_length = params_.max_packet_length;
1728 if (key.session_key().session_usage() == SessionUsage::kProxy) {
1729 max_packet_length += params_.additional_proxy_packet_length;
1730 }
1731 // Restrict that length by the session maximum, if given.
1732 if (session_max_packet_length > 0) {
1733 max_packet_length = std::min(static_cast<size_t>(session_max_packet_length),
1734 max_packet_length);
1735 }
1736 DVLOG(1) << "Session to " << key.destination().Serialize()
1737 << " has max packet length " << max_packet_length;
1738 connection->SetMaxPacketLength(max_packet_length);
1739
1740 quic::QuicConfig config = config_;
1741 ConfigureInitialRttEstimate(
1742 server_id, key.session_key().network_anonymization_key(), &config);
1743
1744 // Use the factory to create a new socket performance watcher, and pass the
1745 // ownership to QuicChromiumClientSession.
1746 std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher;
1747 if (socket_performance_watcher_factory_) {
1748 socket_performance_watcher =
1749 socket_performance_watcher_factory_->CreateSocketPerformanceWatcher(
1750 SocketPerformanceWatcherFactory::PROTOCOL_QUIC,
1751 peer_address.address());
1752 }
1753
1754 // Wait for handshake confirmation before allowing streams to be created if
1755 // either this session or the pool require confirmation.
1756 if (!has_quic_ever_worked_on_current_network_) {
1757 require_confirmation = true;
1758 }
1759
1760 auto new_session = std::make_unique<QuicChromiumClientSession>(
1761 connection, std::move(socket), this, quic_crypto_client_stream_factory_,
1762 clock_, transport_security_state_, ssl_config_service_,
1763 std::move(server_info), std::move(key), require_confirmation,
1764 params_.migrate_sessions_early_v2,
1765 params_.migrate_sessions_on_network_change_v2, default_network_,
1766 retransmittable_on_wire_timeout_, params_.migrate_idle_sessions,
1767 params_.allow_port_migration, params_.idle_session_migration_period,
1768 params_.multi_port_probing_interval,
1769 params_.max_time_on_non_default_network,
1770 params_.max_migrations_to_non_default_network_on_write_error,
1771 params_.max_migrations_to_non_default_network_on_path_degrading,
1772 yield_after_packets_, yield_after_duration_, cert_verify_flags, config,
1773 std::move(crypto_config_handle),
1774 network_connection_.connection_description(), dns_resolution_start_time,
1775 dns_resolution_end_time, tick_clock_, task_runner_.get(),
1776 std::move(socket_performance_watcher), metadata, params_.report_ecn,
1777 params_.enable_origin_frame, params_.allow_server_migration,
1778 session_creation_initiator, net_log);
1779 QuicChromiumClientSession* session = new_session.get();
1780
1781 all_sessions_.insert(std::move(new_session));
1782 writer->set_delegate(session);
1783 session->AddConnectivityObserver(&connectivity_monitor_);
1784
1785 net_log.AddEventReferencingSource(
1786 NetLogEventType::QUIC_SESSION_POOL_JOB_RESULT,
1787 session->net_log().source());
1788
1789 session->Initialize();
1790 bool closed_during_initialize = !base::Contains(all_sessions_, session) ||
1791 !session->connection()->connected();
1792 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedDuringInitializeSession",
1793 closed_during_initialize);
1794 if (closed_during_initialize) {
1795 DLOG(DFATAL) << "Session closed during initialize";
1796 return base::unexpected(ERR_CONNECTION_CLOSED);
1797 }
1798 return QuicSessionAttempt::CreateSessionResult{session, network};
1799 }
1800
ActivateSession(const QuicSessionAliasKey & key,QuicChromiumClientSession * session,std::set<std::string> dns_aliases)1801 void QuicSessionPool::ActivateSession(const QuicSessionAliasKey& key,
1802 QuicChromiumClientSession* session,
1803 std::set<std::string> dns_aliases) {
1804 DCHECK(!HasActiveSession(key.session_key()));
1805 UMA_HISTOGRAM_COUNTS_1M("Net.QuicActiveSessions", active_sessions_.size());
1806 ActivateAndMapSessionToAliasKey(session, key, std::move(dns_aliases));
1807 const IPEndPoint peer_address =
1808 ToIPEndPoint(session->connection()->peer_address());
1809 DCHECK(!base::Contains(ip_aliases_[peer_address], session));
1810 ip_aliases_[peer_address].insert(session);
1811 DCHECK(!base::Contains(session_peer_ip_, session));
1812 session_peer_ip_[session] = peer_address;
1813 }
1814
MarkAllActiveSessionsGoingAway(AllActiveSessionsGoingAwayReason reason)1815 void QuicSessionPool::MarkAllActiveSessionsGoingAway(
1816 AllActiveSessionsGoingAwayReason reason) {
1817 net_log_.AddEvent(
1818 NetLogEventType::QUIC_SESSION_POOL_MARK_ALL_ACTIVE_SESSIONS_GOING_AWAY);
1819 base::UmaHistogramCounts10000(
1820 std::string("Net.QuicActiveSessionCount.") +
1821 AllActiveSessionsGoingAwayReasonToString(reason),
1822 active_sessions_.size());
1823 while (!active_sessions_.empty()) {
1824 QuicChromiumClientSession* session = active_sessions_.begin()->second;
1825 // If IP address change is detected, disable session's connectivity
1826 // monitoring by remove the Delegate.
1827 if (reason == kIPAddressChanged) {
1828 connectivity_monitor_.OnSessionGoingAwayOnIPAddressChange(session);
1829 }
1830 OnSessionGoingAway(session);
1831 }
1832 }
1833
ConfigureInitialRttEstimate(const quic::QuicServerId & server_id,const NetworkAnonymizationKey & network_anonymization_key,quic::QuicConfig * config)1834 void QuicSessionPool::ConfigureInitialRttEstimate(
1835 const quic::QuicServerId& server_id,
1836 const NetworkAnonymizationKey& network_anonymization_key,
1837 quic::QuicConfig* config) {
1838 const base::TimeDelta* srtt =
1839 GetServerNetworkStatsSmoothedRtt(server_id, network_anonymization_key);
1840 // Sometimes *srtt is negative. See https://crbug.com/1225616.
1841 // TODO(ricea): When the root cause of the negative value is fixed, change the
1842 // non-negative assertion to a DCHECK.
1843 if (srtt && srtt->is_positive()) {
1844 SetInitialRttEstimate(*srtt, INITIAL_RTT_CACHED, config);
1845 return;
1846 }
1847
1848 NetworkChangeNotifier::ConnectionType type =
1849 network_connection_.connection_type();
1850 if (type == NetworkChangeNotifier::CONNECTION_2G) {
1851 SetInitialRttEstimate(base::Milliseconds(1200), INITIAL_RTT_CACHED, config);
1852 return;
1853 }
1854
1855 if (type == NetworkChangeNotifier::CONNECTION_3G) {
1856 SetInitialRttEstimate(base::Milliseconds(400), INITIAL_RTT_CACHED, config);
1857 return;
1858 }
1859
1860 if (params_.initial_rtt_for_handshake.is_positive()) {
1861 SetInitialRttEstimate(
1862 base::Microseconds(params_.initial_rtt_for_handshake.InMicroseconds()),
1863 INITIAL_RTT_DEFAULT, config);
1864 return;
1865 }
1866
1867 SetInitialRttEstimate(base::TimeDelta(), INITIAL_RTT_DEFAULT, config);
1868 }
1869
GetServerNetworkStatsSmoothedRttInMicroseconds(const quic::QuicServerId & server_id,const NetworkAnonymizationKey & network_anonymization_key) const1870 int64_t QuicSessionPool::GetServerNetworkStatsSmoothedRttInMicroseconds(
1871 const quic::QuicServerId& server_id,
1872 const NetworkAnonymizationKey& network_anonymization_key) const {
1873 const base::TimeDelta* srtt =
1874 GetServerNetworkStatsSmoothedRtt(server_id, network_anonymization_key);
1875 return srtt == nullptr ? 0 : srtt->InMicroseconds();
1876 }
1877
GetServerNetworkStatsSmoothedRtt(const quic::QuicServerId & server_id,const NetworkAnonymizationKey & network_anonymization_key) const1878 const base::TimeDelta* QuicSessionPool::GetServerNetworkStatsSmoothedRtt(
1879 const quic::QuicServerId& server_id,
1880 const NetworkAnonymizationKey& network_anonymization_key) const {
1881 url::SchemeHostPort server("https", server_id.host(), server_id.port());
1882 const ServerNetworkStats* stats =
1883 http_server_properties_->GetServerNetworkStats(server,
1884 network_anonymization_key);
1885 if (stats == nullptr) {
1886 return nullptr;
1887 }
1888 return &(stats->srtt);
1889 }
1890
WasQuicRecentlyBroken(const QuicSessionKey & session_key) const1891 bool QuicSessionPool::WasQuicRecentlyBroken(
1892 const QuicSessionKey& session_key) const {
1893 const AlternativeService alternative_service(
1894 kProtoQUIC, HostPortPair(session_key.server_id().host(),
1895 session_key.server_id().port()));
1896 return http_server_properties_->WasAlternativeServiceRecentlyBroken(
1897 alternative_service, session_key.network_anonymization_key());
1898 }
1899
InitializeMigrationOptions()1900 void QuicSessionPool::InitializeMigrationOptions() {
1901 // The following list of options cannot be set immediately until
1902 // prerequisites are met. Cache the initial setting in local variables and
1903 // reset them in |params_|.
1904 bool migrate_sessions_on_network_change =
1905 params_.migrate_sessions_on_network_change_v2;
1906 bool migrate_sessions_early = params_.migrate_sessions_early_v2;
1907 bool retry_on_alternate_network_before_handshake =
1908 params_.retry_on_alternate_network_before_handshake;
1909 bool migrate_idle_sessions = params_.migrate_idle_sessions;
1910 bool allow_port_migration = params_.allow_port_migration;
1911 params_.migrate_sessions_on_network_change_v2 = false;
1912 params_.migrate_sessions_early_v2 = false;
1913 params_.allow_port_migration = false;
1914 params_.retry_on_alternate_network_before_handshake = false;
1915 params_.migrate_idle_sessions = false;
1916
1917 // TODO(zhongyi): deprecate |goaway_sessions_on_ip_change| if the experiment
1918 // is no longer needed.
1919 // goaway_sessions_on_ip_change and close_sessions_on_ip_change should never
1920 // be simultaneously set to true.
1921 DCHECK(!(params_.close_sessions_on_ip_change &&
1922 params_.goaway_sessions_on_ip_change));
1923
1924 bool handle_ip_change = params_.close_sessions_on_ip_change ||
1925 params_.goaway_sessions_on_ip_change;
1926 // If IP address changes are handled explicitly, connection migration should
1927 // not be set.
1928 DCHECK(!(handle_ip_change && migrate_sessions_on_network_change));
1929
1930 if (handle_ip_change) {
1931 NetworkChangeNotifier::AddIPAddressObserver(this);
1932 }
1933
1934 if (allow_port_migration) {
1935 params_.allow_port_migration = true;
1936 if (migrate_idle_sessions) {
1937 params_.migrate_idle_sessions = true;
1938 }
1939 }
1940
1941 if (!NetworkChangeNotifier::AreNetworkHandlesSupported()) {
1942 return;
1943 }
1944
1945 NetworkChangeNotifier::AddNetworkObserver(this);
1946 // Perform checks on the connection migration options.
1947 if (!migrate_sessions_on_network_change) {
1948 DCHECK(!migrate_sessions_early);
1949 return;
1950 }
1951
1952 // Enable migration on platform notifications.
1953 params_.migrate_sessions_on_network_change_v2 = true;
1954
1955 if (!migrate_sessions_early) {
1956 DCHECK(!retry_on_alternate_network_before_handshake);
1957 return;
1958 }
1959
1960 // Enable migration on path degrading.
1961 params_.migrate_sessions_early_v2 = true;
1962 // Set retransmittable on wire timeout for migration on path degrading if no
1963 // value is specified.
1964 if (retransmittable_on_wire_timeout_.IsZero()) {
1965 retransmittable_on_wire_timeout_ = quic::QuicTime::Delta::FromMicroseconds(
1966 kDefaultRetransmittableOnWireTimeout.InMicroseconds());
1967 }
1968
1969 // Enable retry on alternate network before handshake.
1970 if (retry_on_alternate_network_before_handshake) {
1971 params_.retry_on_alternate_network_before_handshake = true;
1972 }
1973
1974 // Enable migration for idle sessions.
1975 if (migrate_idle_sessions) {
1976 params_.migrate_idle_sessions = true;
1977 }
1978 }
1979
InitializeCachedStateInCryptoConfig(const CryptoClientConfigHandle & crypto_config_handle,const quic::QuicServerId & server_id,const std::unique_ptr<QuicServerInfo> & server_info)1980 void QuicSessionPool::InitializeCachedStateInCryptoConfig(
1981 const CryptoClientConfigHandle& crypto_config_handle,
1982 const quic::QuicServerId& server_id,
1983 const std::unique_ptr<QuicServerInfo>& server_info) {
1984 quic::QuicCryptoClientConfig::CachedState* cached =
1985 crypto_config_handle.GetConfig()->LookupOrCreate(server_id);
1986
1987 if (!cached->IsEmpty()) {
1988 return;
1989 }
1990
1991 if (!server_info || !server_info->Load()) {
1992 return;
1993 }
1994
1995 cached->Initialize(server_info->state().server_config,
1996 server_info->state().source_address_token,
1997 server_info->state().certs, server_info->state().cert_sct,
1998 server_info->state().chlo_hash,
1999 server_info->state().server_config_sig, clock_->WallNow(),
2000 quic::QuicWallTime::Zero());
2001 }
2002
ProcessGoingAwaySession(QuicChromiumClientSession * session,const quic::QuicServerId & server_id,bool session_was_active)2003 void QuicSessionPool::ProcessGoingAwaySession(
2004 QuicChromiumClientSession* session,
2005 const quic::QuicServerId& server_id,
2006 bool session_was_active) {
2007 if (!http_server_properties_) {
2008 return;
2009 }
2010
2011 const quic::QuicConnectionStats& stats = session->connection()->GetStats();
2012 const AlternativeService alternative_service(
2013 kProtoQUIC, HostPortPair(server_id.host(), server_id.port()));
2014
2015 url::SchemeHostPort server("https", server_id.host(), server_id.port());
2016 // Do nothing if QUIC is currently marked as broken.
2017 if (http_server_properties_->IsAlternativeServiceBroken(
2018 alternative_service,
2019 session->quic_session_key().network_anonymization_key())) {
2020 return;
2021 }
2022
2023 if (session->OneRttKeysAvailable()) {
2024 http_server_properties_->ConfirmAlternativeService(
2025 alternative_service,
2026 session->quic_session_key().network_anonymization_key());
2027 ServerNetworkStats network_stats;
2028 network_stats.srtt = base::Microseconds(stats.srtt_us);
2029 network_stats.bandwidth_estimate = stats.estimated_bandwidth;
2030 http_server_properties_->SetServerNetworkStats(
2031 server, session->quic_session_key().network_anonymization_key(),
2032 network_stats);
2033 return;
2034 }
2035
2036 http_server_properties_->ClearServerNetworkStats(
2037 server, session->quic_session_key().network_anonymization_key());
2038
2039 UMA_HISTOGRAM_COUNTS_1M("Net.QuicHandshakeNotConfirmedNumPacketsReceived",
2040 stats.packets_received);
2041
2042 if (!session_was_active) {
2043 return;
2044 }
2045
2046 // TODO(rch): In the special case where the session has received no packets
2047 // from the peer, we should consider blocking this differently so that we
2048 // still race TCP but we don't consider the session connected until the
2049 // handshake has been confirmed.
2050 HistogramBrokenAlternateProtocolLocation(
2051 BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_SESSION_POOL);
2052
2053 // Since the session was active, there's no longer an HttpStreamFactory::Job
2054 // running which can mark it broken, unless the TCP job also fails. So to
2055 // avoid not using QUIC when we otherwise could, we mark it as recently
2056 // broken, which means that 0-RTT will be disabled but we'll still race.
2057 http_server_properties_->MarkAlternativeServiceRecentlyBroken(
2058 alternative_service,
2059 session->quic_session_key().network_anonymization_key());
2060 }
2061
ActivateAndMapSessionToAliasKey(QuicChromiumClientSession * session,QuicSessionAliasKey key,std::set<std::string> dns_aliases)2062 void QuicSessionPool::ActivateAndMapSessionToAliasKey(
2063 QuicChromiumClientSession* session,
2064 QuicSessionAliasKey key,
2065 std::set<std::string> dns_aliases) {
2066 active_sessions_[key.session_key()] = session;
2067 dns_aliases_by_session_key_[key.session_key()] = std::move(dns_aliases);
2068 session_aliases_[session].insert(std::move(key));
2069 }
2070
UnmapSessionFromSessionAliases(QuicChromiumClientSession * session)2071 void QuicSessionPool::UnmapSessionFromSessionAliases(
2072 QuicChromiumClientSession* session) {
2073 for (const auto& key : session_aliases_[session]) {
2074 dns_aliases_by_session_key_.erase(key.session_key());
2075 }
2076 session_aliases_.erase(session);
2077 }
2078
2079 std::unique_ptr<QuicSessionPool::CryptoClientConfigHandle>
CreateCryptoConfigHandle(const NetworkAnonymizationKey & network_anonymization_key)2080 QuicSessionPool::CreateCryptoConfigHandle(
2081 const NetworkAnonymizationKey& network_anonymization_key) {
2082 NetworkAnonymizationKey actual_network_anonymization_key =
2083 use_network_anonymization_key_for_crypto_configs_
2084 ? network_anonymization_key
2085 : NetworkAnonymizationKey();
2086
2087 // If there's a matching entry in |active_crypto_config_map_|, create a
2088 // CryptoClientConfigHandle for it.
2089 auto map_iterator =
2090 active_crypto_config_map_.find(actual_network_anonymization_key);
2091 if (map_iterator != active_crypto_config_map_.end()) {
2092 DCHECK_GT(map_iterator->second->num_refs(), 0);
2093
2094 // If there's an active matching crypto config, there shouldn't also be an
2095 // inactive matching crypto config.
2096 DCHECK(recent_crypto_config_map_.Peek(actual_network_anonymization_key) ==
2097 recent_crypto_config_map_.end());
2098
2099 return std::make_unique<CryptoClientConfigHandle>(map_iterator);
2100 }
2101
2102 // If there's a matching entry in |recent_crypto_config_map_|, move it to
2103 // |active_crypto_config_map_| and create a CryptoClientConfigHandle for it.
2104 auto mru_iterator =
2105 recent_crypto_config_map_.Peek(actual_network_anonymization_key);
2106 if (mru_iterator != recent_crypto_config_map_.end()) {
2107 DCHECK_EQ(mru_iterator->second->num_refs(), 0);
2108
2109 map_iterator = active_crypto_config_map_
2110 .emplace(actual_network_anonymization_key,
2111 std::move(mru_iterator->second))
2112 .first;
2113 recent_crypto_config_map_.Erase(mru_iterator);
2114 return std::make_unique<CryptoClientConfigHandle>(map_iterator);
2115 }
2116
2117 // Otherwise, create a new QuicCryptoClientConfigOwner and add it to
2118 // |active_crypto_config_map_|.
2119 std::unique_ptr<QuicCryptoClientConfigOwner> crypto_config_owner =
2120 std::make_unique<QuicCryptoClientConfigOwner>(
2121 std::make_unique<ProofVerifierChromium>(
2122 cert_verifier_, transport_security_state_, sct_auditing_delegate_,
2123 HostsFromOrigins(params_.origins_to_force_quic_on),
2124 actual_network_anonymization_key),
2125 std::make_unique<quic::QuicClientSessionCache>(), this);
2126
2127 quic::QuicCryptoClientConfig* crypto_config = crypto_config_owner->config();
2128 crypto_config->AddCanonicalSuffix(".c.youtube.com");
2129 crypto_config->AddCanonicalSuffix(".ggpht.com");
2130 crypto_config->AddCanonicalSuffix(".googlevideo.com");
2131 crypto_config->AddCanonicalSuffix(".googleusercontent.com");
2132 crypto_config->AddCanonicalSuffix(".gvt1.com");
2133 crypto_config->set_alps_use_new_codepoint(params_.use_new_alps_codepoint);
2134
2135 ConfigureQuicCryptoClientConfig(*crypto_config);
2136
2137 if (!prefer_aes_gcm_recorded_) {
2138 bool prefer_aes_gcm =
2139 !crypto_config->aead.empty() && (crypto_config->aead[0] == quic::kAESG);
2140 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.PreferAesGcm", prefer_aes_gcm);
2141 prefer_aes_gcm_recorded_ = true;
2142 }
2143
2144 map_iterator = active_crypto_config_map_
2145 .emplace(actual_network_anonymization_key,
2146 std::move(crypto_config_owner))
2147 .first;
2148 return std::make_unique<CryptoClientConfigHandle>(map_iterator);
2149 }
2150
OnAllCryptoClientRefReleased(QuicCryptoClientConfigMap::iterator & map_iterator)2151 void QuicSessionPool::OnAllCryptoClientRefReleased(
2152 QuicCryptoClientConfigMap::iterator& map_iterator) {
2153 DCHECK_EQ(0, map_iterator->second->num_refs());
2154 recent_crypto_config_map_.Put(map_iterator->first,
2155 std::move(map_iterator->second));
2156 active_crypto_config_map_.erase(map_iterator);
2157 }
2158
CollectDataOnPlatformNotification(enum QuicPlatformNotification notification,handles::NetworkHandle affected_network) const2159 void QuicSessionPool::CollectDataOnPlatformNotification(
2160 enum QuicPlatformNotification notification,
2161 handles::NetworkHandle affected_network) const {
2162 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.PlatformNotification",
2163 notification, NETWORK_NOTIFICATION_MAX);
2164 connectivity_monitor_.RecordConnectivityStatsToHistograms(
2165 QuicPlatformNotificationToString(notification), affected_network);
2166 }
2167
2168 std::unique_ptr<QuicCryptoClientConfigHandle>
GetCryptoConfigForTesting(const NetworkAnonymizationKey & network_anonymization_key)2169 QuicSessionPool::GetCryptoConfigForTesting(
2170 const NetworkAnonymizationKey& network_anonymization_key) {
2171 return CreateCryptoConfigHandle(network_anonymization_key);
2172 }
2173
CryptoConfigCacheIsEmptyForTesting(const quic::QuicServerId & server_id,const NetworkAnonymizationKey & network_anonymization_key)2174 bool QuicSessionPool::CryptoConfigCacheIsEmptyForTesting(
2175 const quic::QuicServerId& server_id,
2176 const NetworkAnonymizationKey& network_anonymization_key) {
2177 quic::QuicCryptoClientConfig::CachedState* cached = nullptr;
2178 NetworkAnonymizationKey actual_network_anonymization_key =
2179 use_network_anonymization_key_for_crypto_configs_
2180 ? network_anonymization_key
2181 : NetworkAnonymizationKey();
2182 auto map_iterator =
2183 active_crypto_config_map_.find(actual_network_anonymization_key);
2184 if (map_iterator != active_crypto_config_map_.end()) {
2185 cached = map_iterator->second->config()->LookupOrCreate(server_id);
2186 } else {
2187 auto mru_iterator =
2188 recent_crypto_config_map_.Peek(actual_network_anonymization_key);
2189 if (mru_iterator != recent_crypto_config_map_.end()) {
2190 cached = mru_iterator->second->config()->LookupOrCreate(server_id);
2191 }
2192 }
2193 return !cached || cached->IsEmpty();
2194 }
2195
2196 } // namespace net
2197