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_chromium_client_session.h"
6
7 #include <memory>
8 #include <set>
9 #include <string_view>
10 #include <utility>
11
12 #include "base/containers/contains.h"
13 #include "base/functional/bind.h"
14 #include "base/functional/callback_helpers.h"
15 #include "base/location.h"
16 #include "base/logging.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/metrics/histogram_functions.h"
19 #include "base/metrics/histogram_macros.h"
20 #include "base/metrics/sparse_histogram.h"
21 #include "base/no_destructor.h"
22 #include "base/observer_list.h"
23 #include "base/ranges/algorithm.h"
24 #include "base/strings/string_number_conversions.h"
25 #include "base/strings/stringprintf.h"
26 #include "base/task/sequenced_task_runner.h"
27 #include "base/task/single_thread_task_runner.h"
28 #include "base/time/tick_clock.h"
29 #include "base/trace_event/memory_usage_estimator.h"
30 #include "base/values.h"
31 #include "net/base/connection_endpoint_metadata.h"
32 #include "net/base/features.h"
33 #include "net/base/io_buffer.h"
34 #include "net/base/net_errors.h"
35 #include "net/base/network_activity_monitor.h"
36 #include "net/base/network_anonymization_key.h"
37 #include "net/base/privacy_mode.h"
38 #include "net/base/session_usage.h"
39 #include "net/base/url_util.h"
40 #include "net/cert/signed_certificate_timestamp_and_status.h"
41 #include "net/dns/public/secure_dns_policy.h"
42 #include "net/http/transport_security_state.h"
43 #include "net/log/net_log_event_type.h"
44 #include "net/log/net_log_source_type.h"
45 #include "net/log/net_log_values.h"
46 #include "net/quic/address_utils.h"
47 #include "net/quic/crypto/proof_verifier_chromium.h"
48 #include "net/quic/quic_chromium_connection_helper.h"
49 #include "net/quic/quic_chromium_packet_writer.h"
50 #include "net/quic/quic_crypto_client_stream_factory.h"
51 #include "net/quic/quic_server_info.h"
52 #include "net/quic/quic_session_pool.h"
53 #include "net/socket/datagram_client_socket.h"
54 #include "net/spdy/spdy_http_utils.h"
55 #include "net/spdy/spdy_log_util.h"
56 #include "net/spdy/spdy_session.h"
57 #include "net/ssl/ssl_connection_status_flags.h"
58 #include "net/ssl/ssl_info.h"
59 #include "net/third_party/quiche/src/quiche/quic/core/quic_stream_priority.h"
60 #include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
61 #include "net/third_party/quiche/src/quiche/quic/platform/api/quic_flags.h"
62 #include "net/traffic_annotation/network_traffic_annotation.h"
63 #include "net/websockets/websocket_quic_spdy_stream.h"
64 #include "third_party/boringssl/src/include/openssl/ssl.h"
65 #include "url/origin.h"
66 #include "url/scheme_host_port.h"
67
68 namespace net {
69
70 namespace features {
71
72 BASE_FEATURE(kQuicMigrationIgnoreDisconnectSignalDuringProbing,
73 "kQuicMigrationIgnoreDisconnectSignalDuringProbing",
74 base::FEATURE_DISABLED_BY_DEFAULT);
75
76 } // namespace features
77
78 namespace {
79
MidMigrationCallbackForTesting()80 base::OnceClosure& MidMigrationCallbackForTesting() {
81 static base::NoDestructor<base::OnceClosure> callback;
82 return *callback;
83 }
84
85 // IPv6 packets have an additional 20 bytes of overhead than IPv4 packets.
86 const size_t kAdditionalOverheadForIPv6 = 20;
87
88 // Maximum number of Readers that are created for any session due to
89 // connection migration. A new Reader is created every time this endpoint's
90 // IP address changes.
91 const size_t kMaxReadersPerQuicSession = 5;
92
93 // Time to wait (in seconds) when no networks are available and
94 // migrating sessions need to wait for a new network to connect.
95 const size_t kWaitTimeForNewNetworkSecs = 10;
96
97 const size_t kMinRetryTimeForDefaultNetworkSecs = 1;
98
99 // These values are persisted to logs. Entries should not be renumbered,
100 // and numeric values should never be reused.
101 enum class AcceptChEntries {
102 kNoEntries = 0,
103 kOnlyValidEntries = 1,
104 kOnlyInvalidEntries = 2,
105 kBothValidAndInvalidEntries = 3,
106 kMaxValue = kBothValidAndInvalidEntries,
107 };
108
LogAcceptChFrameReceivedHistogram(bool has_valid_entry,bool has_invalid_entry)109 void LogAcceptChFrameReceivedHistogram(bool has_valid_entry,
110 bool has_invalid_entry) {
111 AcceptChEntries value;
112 if (has_valid_entry) {
113 if (has_invalid_entry) {
114 value = AcceptChEntries::kBothValidAndInvalidEntries;
115 } else {
116 value = AcceptChEntries::kOnlyValidEntries;
117 }
118 } else {
119 if (has_invalid_entry) {
120 value = AcceptChEntries::kOnlyInvalidEntries;
121 } else {
122 value = AcceptChEntries::kNoEntries;
123 }
124 }
125 base::UmaHistogramEnumeration("Net.QuicSession.AcceptChFrameReceivedViaAlps",
126 value);
127 }
128
LogAcceptChForOriginHistogram(bool value)129 void LogAcceptChForOriginHistogram(bool value) {
130 base::UmaHistogramBoolean("Net.QuicSession.AcceptChForOrigin", value);
131 }
132
RecordConnectionCloseErrorCodeImpl(const std::string & histogram,uint64_t error,bool is_google_host,bool handshake_confirmed,bool has_ech_config_list)133 void RecordConnectionCloseErrorCodeImpl(const std::string& histogram,
134 uint64_t error,
135 bool is_google_host,
136 bool handshake_confirmed,
137 bool has_ech_config_list) {
138 base::UmaHistogramSparse(histogram, error);
139
140 if (handshake_confirmed) {
141 base::UmaHistogramSparse(histogram + ".HandshakeConfirmed", error);
142 } else {
143 base::UmaHistogramSparse(histogram + ".HandshakeNotConfirmed", error);
144 }
145
146 if (is_google_host) {
147 base::UmaHistogramSparse(histogram + "Google", error);
148
149 if (handshake_confirmed) {
150 base::UmaHistogramSparse(histogram + "Google.HandshakeConfirmed", error);
151 } else {
152 base::UmaHistogramSparse(histogram + "Google.HandshakeNotConfirmed",
153 error);
154 }
155 }
156
157 // Record a set of metrics based on whether ECH was advertised in DNS. The ECH
158 // experiment does not change DNS behavior, so this measures the same servers
159 // in both experiment and control groups.
160 if (has_ech_config_list) {
161 base::UmaHistogramSparse(histogram + "ECH", error);
162
163 if (handshake_confirmed) {
164 base::UmaHistogramSparse(histogram + "ECH.HandshakeConfirmed", error);
165 } else {
166 base::UmaHistogramSparse(histogram + "ECH.HandshakeNotConfirmed", error);
167 }
168 }
169 }
170
LogMigrateToSocketStatus(bool success)171 void LogMigrateToSocketStatus(bool success) {
172 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.MigrateToSocketSuccess", success);
173 }
174
RecordConnectionCloseErrorCode(const quic::QuicConnectionCloseFrame & frame,quic::ConnectionCloseSource source,std::string_view hostname,bool handshake_confirmed,bool has_ech_config_list)175 void RecordConnectionCloseErrorCode(const quic::QuicConnectionCloseFrame& frame,
176 quic::ConnectionCloseSource source,
177 std::string_view hostname,
178 bool handshake_confirmed,
179 bool has_ech_config_list) {
180 bool is_google_host = IsGoogleHost(hostname);
181 std::string histogram = "Net.QuicSession.ConnectionCloseErrorCode";
182
183 if (source == quic::ConnectionCloseSource::FROM_SELF) {
184 // When sending a CONNECTION_CLOSE frame, it is sufficient to record
185 // |quic_error_code|.
186 histogram += "Client";
187 RecordConnectionCloseErrorCodeImpl(histogram, frame.quic_error_code,
188 is_google_host, handshake_confirmed,
189 has_ech_config_list);
190 return;
191 }
192
193 histogram += "Server";
194
195 // Record |quic_error_code|. Note that when using IETF QUIC, this is
196 // extracted from the CONNECTION_CLOSE frame reason phrase, and might be
197 // QUIC_IETF_GQUIC_ERROR_MISSING.
198 RecordConnectionCloseErrorCodeImpl(histogram, frame.quic_error_code,
199 is_google_host, handshake_confirmed,
200 has_ech_config_list);
201
202 // For IETF QUIC frames, also record the error code received on the wire.
203 if (frame.close_type == quic::IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) {
204 histogram += "IetfTransport";
205 RecordConnectionCloseErrorCodeImpl(histogram, frame.wire_error_code,
206 is_google_host, handshake_confirmed,
207 has_ech_config_list);
208 if (frame.quic_error_code == quic::QUIC_IETF_GQUIC_ERROR_MISSING) {
209 histogram += "GQuicErrorMissing";
210 RecordConnectionCloseErrorCodeImpl(histogram, frame.wire_error_code,
211 is_google_host, handshake_confirmed,
212 has_ech_config_list);
213 }
214 } else if (frame.close_type == quic::IETF_QUIC_APPLICATION_CONNECTION_CLOSE) {
215 histogram += "IetfApplication";
216 RecordConnectionCloseErrorCodeImpl(histogram, frame.wire_error_code,
217 is_google_host, handshake_confirmed,
218 has_ech_config_list);
219 if (frame.quic_error_code == quic::QUIC_IETF_GQUIC_ERROR_MISSING) {
220 histogram += "GQuicErrorMissing";
221 RecordConnectionCloseErrorCodeImpl(histogram, frame.wire_error_code,
222 is_google_host, handshake_confirmed,
223 has_ech_config_list);
224 }
225 }
226 }
227
NetLogQuicMigrationFailureParams(quic::QuicConnectionId connection_id,std::string_view reason)228 base::Value::Dict NetLogQuicMigrationFailureParams(
229 quic::QuicConnectionId connection_id,
230 std::string_view reason) {
231 return base::Value::Dict()
232 .Set("connection_id", connection_id.ToString())
233 .Set("reason", reason);
234 }
235
NetLogQuicMigrationSuccessParams(quic::QuicConnectionId connection_id)236 base::Value::Dict NetLogQuicMigrationSuccessParams(
237 quic::QuicConnectionId connection_id) {
238 return base::Value::Dict().Set("connection_id", connection_id.ToString());
239 }
240
NetLogProbingResultParams(handles::NetworkHandle network,const quic::QuicSocketAddress * peer_address,bool is_success)241 base::Value::Dict NetLogProbingResultParams(
242 handles::NetworkHandle network,
243 const quic::QuicSocketAddress* peer_address,
244 bool is_success) {
245 return base::Value::Dict()
246 .Set("network", base::NumberToString(network))
247 .Set("peer address", peer_address->ToString())
248 .Set("is_success", is_success);
249 }
250
NetLogAcceptChFrameReceivedParams(spdy::AcceptChOriginValuePair entry)251 base::Value::Dict NetLogAcceptChFrameReceivedParams(
252 spdy::AcceptChOriginValuePair entry) {
253 return base::Value::Dict()
254 .Set("origin", entry.origin)
255 .Set("accept_ch", entry.value);
256 }
257
258 // Histogram for recording the different reasons that a QUIC session is unable
259 // to complete the handshake.
260 enum HandshakeFailureReason {
261 HANDSHAKE_FAILURE_UNKNOWN = 0,
262 HANDSHAKE_FAILURE_BLACK_HOLE = 1,
263 HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
264 NUM_HANDSHAKE_FAILURE_REASONS = 3,
265 };
266
RecordHandshakeFailureReason(HandshakeFailureReason reason)267 void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
268 UMA_HISTOGRAM_ENUMERATION(
269 "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason", reason,
270 NUM_HANDSHAKE_FAILURE_REASONS);
271 }
272
273 // Note: these values must be kept in sync with the corresponding values in:
274 // tools/metrics/histograms/histograms.xml
275 enum HandshakeState {
276 STATE_STARTED = 0,
277 STATE_ENCRYPTION_ESTABLISHED = 1,
278 STATE_HANDSHAKE_CONFIRMED = 2,
279 STATE_FAILED = 3,
280 NUM_HANDSHAKE_STATES = 4
281 };
282
283 enum class ZeroRttState {
284 kAttemptedAndSucceeded = 0,
285 kAttemptedAndRejected = 1,
286 kNotAttempted = 2,
287 kMaxValue = kNotAttempted,
288 };
289
RecordHandshakeState(HandshakeState state)290 void RecordHandshakeState(HandshakeState state) {
291 UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
292 NUM_HANDSHAKE_STATES);
293 }
294
MigrationCauseToString(MigrationCause cause)295 std::string MigrationCauseToString(MigrationCause cause) {
296 switch (cause) {
297 case UNKNOWN_CAUSE:
298 return "Unknown";
299 case ON_NETWORK_CONNECTED:
300 return "OnNetworkConnected";
301 case ON_NETWORK_DISCONNECTED:
302 return "OnNetworkDisconnected";
303 case ON_WRITE_ERROR:
304 return "OnWriteError";
305 case ON_NETWORK_MADE_DEFAULT:
306 return "OnNetworkMadeDefault";
307 case ON_MIGRATE_BACK_TO_DEFAULT_NETWORK:
308 return "OnMigrateBackToDefaultNetwork";
309 case CHANGE_NETWORK_ON_PATH_DEGRADING:
310 return "OnPathDegrading";
311 case CHANGE_PORT_ON_PATH_DEGRADING:
312 return "ChangePortOnPathDegrading";
313 case NEW_NETWORK_CONNECTED_POST_PATH_DEGRADING:
314 return "NewNetworkConnectedPostPathDegrading";
315 case ON_SERVER_PREFERRED_ADDRESS_AVAILABLE:
316 return "OnServerPreferredAddressAvailable";
317 default:
318 QUICHE_NOTREACHED();
319 break;
320 }
321 return "InvalidCause";
322 }
323
NetLogQuicClientSessionParams(const NetLogWithSource & net_log,const QuicSessionKey * session_key,const quic::QuicConnectionId & connection_id,const quic::QuicConnectionId & client_connection_id,const quic::ParsedQuicVersionVector & supported_versions,int cert_verify_flags,bool require_confirmation,base::span<const uint8_t> ech_config_list)324 base::Value::Dict NetLogQuicClientSessionParams(
325 const NetLogWithSource& net_log,
326 const QuicSessionKey* session_key,
327 const quic::QuicConnectionId& connection_id,
328 const quic::QuicConnectionId& client_connection_id,
329 const quic::ParsedQuicVersionVector& supported_versions,
330 int cert_verify_flags,
331 bool require_confirmation,
332 base::span<const uint8_t> ech_config_list) {
333 auto dict =
334 base::Value::Dict()
335 .Set("host", session_key->server_id().host())
336 .Set("port", session_key->server_id().port())
337 .Set("connection_id", connection_id.ToString())
338 .Set("versions", ParsedQuicVersionVectorToString(supported_versions))
339 .Set("require_confirmation", require_confirmation)
340 .Set("cert_verify_flags", cert_verify_flags)
341 .Set("server_id_privacy_mode",
342 session_key->server_id().privacy_mode_enabled())
343 .Set("privacy_mode",
344 PrivacyModeToDebugString(session_key->privacy_mode()))
345 .Set("proxy_chain", session_key->proxy_chain().ToDebugString())
346 .Set("session_usage",
347 session_key->session_usage() == SessionUsage::kDestination
348 ? "destination"
349 : "proxy")
350 .Set("network_anonymization_key",
351 session_key->network_anonymization_key().ToDebugString())
352 .Set("secure_dns_policy",
353 SecureDnsPolicyToDebugString(session_key->secure_dns_policy()))
354 .Set("require_dns_https_alpn", session_key->require_dns_https_alpn());
355 if (!client_connection_id.IsEmpty()) {
356 dict.Set("client_connection_id", client_connection_id.ToString());
357 }
358 if (!ech_config_list.empty()) {
359 dict.Set("ech_config_list", NetLogBinaryValue(ech_config_list));
360 }
361 net_log.source().AddToEventParameters(dict);
362 return dict;
363 }
364
365 // TODO(fayang): Remove this when necessary data is collected.
LogProbeResultToHistogram(MigrationCause cause,bool success)366 void LogProbeResultToHistogram(MigrationCause cause, bool success) {
367 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.PathValidationSuccess", success);
368 const std::string histogram_name =
369 "Net.QuicSession.PathValidationSuccess." + MigrationCauseToString(cause);
370 STATIC_HISTOGRAM_POINTER_GROUP(
371 histogram_name, cause, MIGRATION_CAUSE_MAX, AddBoolean(success),
372 base::BooleanHistogram::FactoryGet(
373 histogram_name, base::HistogramBase::kUmaTargetedHistogramFlag));
374 }
375
376 } // namespace
377
378 // static
SetMidMigrationCallbackForTesting(base::OnceClosure callback)379 void QuicChromiumClientSession::SetMidMigrationCallbackForTesting(
380 base::OnceClosure callback) {
381 MidMigrationCallbackForTesting() = std::move(callback); // IN-TEST
382 }
383
Handle(const base::WeakPtr<QuicChromiumClientSession> & session,url::SchemeHostPort destination)384 QuicChromiumClientSession::Handle::Handle(
385 const base::WeakPtr<QuicChromiumClientSession>& session,
386 url::SchemeHostPort destination)
387 : MultiplexedSessionHandle(session),
388 session_(session),
389 destination_(std::move(destination)),
390 net_log_(session_->net_log()),
391 was_handshake_confirmed_(session->OneRttKeysAvailable()),
392 server_id_(session_->server_id()),
393 quic_version_(session->connection()->version()) {
394 DCHECK(session_);
395 session_->AddHandle(this);
396 }
397
~Handle()398 QuicChromiumClientSession::Handle::~Handle() {
399 if (session_) {
400 session_->RemoveHandle(this);
401 }
402 }
403
OnCryptoHandshakeConfirmed()404 void QuicChromiumClientSession::Handle::OnCryptoHandshakeConfirmed() {
405 was_handshake_confirmed_ = true;
406 }
407
OnSessionClosed(quic::ParsedQuicVersion quic_version,int net_error,quic::QuicErrorCode quic_error,bool port_migration_detected,bool quic_connection_migration_attempted,bool quic_connection_migration_successful,LoadTimingInfo::ConnectTiming connect_timing,bool was_ever_used)408 void QuicChromiumClientSession::Handle::OnSessionClosed(
409 quic::ParsedQuicVersion quic_version,
410 int net_error,
411 quic::QuicErrorCode quic_error,
412 bool port_migration_detected,
413 bool quic_connection_migration_attempted,
414 bool quic_connection_migration_successful,
415 LoadTimingInfo::ConnectTiming connect_timing,
416 bool was_ever_used) {
417 session_ = nullptr;
418 port_migration_detected_ = port_migration_detected;
419 quic_connection_migration_attempted_ = quic_connection_migration_attempted;
420 quic_connection_migration_successful_ = quic_connection_migration_successful;
421 net_error_ = net_error;
422 quic_error_ = quic_error;
423 quic_version_ = quic_version;
424 connect_timing_ = connect_timing;
425 was_ever_used_ = was_ever_used;
426 }
427
IsConnected() const428 bool QuicChromiumClientSession::Handle::IsConnected() const {
429 return session_ != nullptr;
430 }
431
OneRttKeysAvailable() const432 bool QuicChromiumClientSession::Handle::OneRttKeysAvailable() const {
433 return was_handshake_confirmed_;
434 }
435
436 const LoadTimingInfo::ConnectTiming&
GetConnectTiming()437 QuicChromiumClientSession::Handle::GetConnectTiming() {
438 if (!session_) {
439 return connect_timing_;
440 }
441
442 return session_->GetConnectTiming();
443 }
444
PopulateNetErrorDetails(NetErrorDetails * details) const445 void QuicChromiumClientSession::Handle::PopulateNetErrorDetails(
446 NetErrorDetails* details) const {
447 if (session_) {
448 session_->PopulateNetErrorDetails(details);
449 } else {
450 details->quic_port_migration_detected = port_migration_detected_;
451 details->quic_connection_error = quic_error_;
452 details->quic_connection_migration_attempted =
453 quic_connection_migration_attempted_;
454 details->quic_connection_migration_successful =
455 quic_connection_migration_successful_;
456 }
457 }
458
GetQuicVersion() const459 quic::ParsedQuicVersion QuicChromiumClientSession::Handle::GetQuicVersion()
460 const {
461 if (!session_) {
462 return quic_version_;
463 }
464
465 return session_->GetQuicVersion();
466 }
467
468 std::unique_ptr<quic::QuicConnection::ScopedPacketFlusher>
CreatePacketBundler()469 QuicChromiumClientSession::Handle::CreatePacketBundler() {
470 if (!session_) {
471 return nullptr;
472 }
473
474 return std::make_unique<quic::QuicConnection::ScopedPacketFlusher>(
475 session_->connection());
476 }
477
SharesSameSession(const Handle & other) const478 bool QuicChromiumClientSession::Handle::SharesSameSession(
479 const Handle& other) const {
480 return session_.get() == other.session_.get();
481 }
482
RequestStream(bool requires_confirmation,CompletionOnceCallback callback,const NetworkTrafficAnnotationTag & traffic_annotation)483 int QuicChromiumClientSession::Handle::RequestStream(
484 bool requires_confirmation,
485 CompletionOnceCallback callback,
486 const NetworkTrafficAnnotationTag& traffic_annotation) {
487 DCHECK(!stream_request_);
488
489 // TODO(crbug.com/41491379): Add a regression test.
490 if (!session_ || session_->going_away_) {
491 return ERR_CONNECTION_CLOSED;
492 }
493
494 requires_confirmation |= session_->gquic_zero_rtt_disabled();
495
496 // std::make_unique does not work because the StreamRequest constructor
497 // is private.
498 stream_request_ = base::WrapUnique(
499 new StreamRequest(this, requires_confirmation, traffic_annotation));
500 return stream_request_->StartRequest(std::move(callback));
501 }
502
503 std::unique_ptr<QuicChromiumClientStream::Handle>
ReleaseStream()504 QuicChromiumClientSession::Handle::ReleaseStream() {
505 DCHECK(stream_request_);
506
507 auto handle = stream_request_->ReleaseStream();
508 stream_request_.reset();
509 return handle;
510 }
511
WaitForHandshakeConfirmation(CompletionOnceCallback callback)512 int QuicChromiumClientSession::Handle::WaitForHandshakeConfirmation(
513 CompletionOnceCallback callback) {
514 if (!session_) {
515 return ERR_CONNECTION_CLOSED;
516 }
517
518 return session_->WaitForHandshakeConfirmation(std::move(callback));
519 }
520
CancelRequest(StreamRequest * request)521 void QuicChromiumClientSession::Handle::CancelRequest(StreamRequest* request) {
522 if (session_) {
523 session_->CancelRequest(request);
524 }
525 }
526
TryCreateStream(StreamRequest * request)527 int QuicChromiumClientSession::Handle::TryCreateStream(StreamRequest* request) {
528 if (!session_) {
529 return ERR_CONNECTION_CLOSED;
530 }
531
532 return session_->TryCreateStream(request);
533 }
534
GetPeerAddress(IPEndPoint * address) const535 int QuicChromiumClientSession::Handle::GetPeerAddress(
536 IPEndPoint* address) const {
537 if (!session_) {
538 return ERR_CONNECTION_CLOSED;
539 }
540
541 *address = ToIPEndPoint(session_->peer_address());
542 return OK;
543 }
544
GetSelfAddress(IPEndPoint * address) const545 int QuicChromiumClientSession::Handle::GetSelfAddress(
546 IPEndPoint* address) const {
547 if (!session_) {
548 return ERR_CONNECTION_CLOSED;
549 }
550
551 *address = ToIPEndPoint(session_->self_address());
552 return OK;
553 }
554
WasEverUsed() const555 bool QuicChromiumClientSession::Handle::WasEverUsed() const {
556 if (!session_) {
557 return was_ever_used_;
558 }
559
560 return session_->WasConnectionEverUsed();
561 }
562
563 const std::set<std::string>&
GetDnsAliasesForSessionKey(const QuicSessionKey & key) const564 QuicChromiumClientSession::Handle::GetDnsAliasesForSessionKey(
565 const QuicSessionKey& key) const {
566 static const base::NoDestructor<std::set<std::string>> emptyset_result;
567 return session_ ? session_->GetDnsAliasesForSessionKey(key)
568 : *emptyset_result;
569 }
570
571 #if BUILDFLAG(ENABLE_WEBSOCKETS)
572 std::unique_ptr<WebSocketQuicStreamAdapter>
CreateWebSocketQuicStreamAdapter(WebSocketQuicStreamAdapter::Delegate * delegate,base::OnceCallback<void (std::unique_ptr<WebSocketQuicStreamAdapter>)> callback,const NetworkTrafficAnnotationTag & traffic_annotation)573 QuicChromiumClientSession::Handle::CreateWebSocketQuicStreamAdapter(
574 WebSocketQuicStreamAdapter::Delegate* delegate,
575 base::OnceCallback<void(std::unique_ptr<WebSocketQuicStreamAdapter>)>
576 callback,
577 const NetworkTrafficAnnotationTag& traffic_annotation) {
578 DCHECK(!stream_request_);
579 // std::make_unique does not work because the StreamRequest constructor
580 // is private.
581 stream_request_ = base::WrapUnique(new StreamRequest(
582 this, /*requires_confirmation=*/false, traffic_annotation));
583 return session_->CreateWebSocketQuicStreamAdapter(
584 delegate, std::move(callback), stream_request_.get());
585 }
586 #endif // BUILDFLAG(ENABLE_WEBSOCKETS)
587
StreamRequest(QuicChromiumClientSession::Handle * session,bool requires_confirmation,const NetworkTrafficAnnotationTag & traffic_annotation)588 QuicChromiumClientSession::StreamRequest::StreamRequest(
589 QuicChromiumClientSession::Handle* session,
590 bool requires_confirmation,
591 const NetworkTrafficAnnotationTag& traffic_annotation)
592 : session_(session),
593 requires_confirmation_(requires_confirmation),
594 traffic_annotation_(traffic_annotation) {}
595
~StreamRequest()596 QuicChromiumClientSession::StreamRequest::~StreamRequest() {
597 if (stream_) {
598 stream_->Reset(quic::QUIC_STREAM_CANCELLED);
599 }
600
601 if (session_) {
602 session_->CancelRequest(this);
603 }
604 }
605
StartRequest(CompletionOnceCallback callback)606 int QuicChromiumClientSession::StreamRequest::StartRequest(
607 CompletionOnceCallback callback) {
608 if (!session_->IsConnected()) {
609 return ERR_CONNECTION_CLOSED;
610 }
611
612 next_state_ = STATE_WAIT_FOR_CONFIRMATION;
613 int rv = DoLoop(OK);
614 if (rv == ERR_IO_PENDING) {
615 callback_ = std::move(callback);
616 }
617
618 return rv;
619 }
620
621 std::unique_ptr<QuicChromiumClientStream::Handle>
ReleaseStream()622 QuicChromiumClientSession::StreamRequest::ReleaseStream() {
623 DCHECK(stream_);
624 return std::move(stream_);
625 }
626
OnRequestCompleteSuccess(std::unique_ptr<QuicChromiumClientStream::Handle> stream)627 void QuicChromiumClientSession::StreamRequest::OnRequestCompleteSuccess(
628 std::unique_ptr<QuicChromiumClientStream::Handle> stream) {
629 DCHECK_EQ(STATE_REQUEST_STREAM_COMPLETE, next_state_);
630
631 stream_ = std::move(stream);
632 // This method is called even when the request completes synchronously.
633 if (callback_) {
634 DoCallback(OK);
635 }
636 }
637
OnRequestCompleteFailure(int rv)638 void QuicChromiumClientSession::StreamRequest::OnRequestCompleteFailure(
639 int rv) {
640 DCHECK_EQ(STATE_REQUEST_STREAM_COMPLETE, next_state_);
641 // This method is called even when the request completes synchronously.
642 if (callback_) {
643 // Avoid re-entrancy if the callback calls into the session.
644 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
645 FROM_HERE,
646 base::BindOnce(&QuicChromiumClientSession::StreamRequest::DoCallback,
647 weak_factory_.GetWeakPtr(), rv));
648 }
649 }
650
OnIOComplete(int rv)651 void QuicChromiumClientSession::StreamRequest::OnIOComplete(int rv) {
652 rv = DoLoop(rv);
653
654 if (rv != ERR_IO_PENDING && !callback_.is_null()) {
655 DoCallback(rv);
656 }
657 }
658
DoCallback(int rv)659 void QuicChromiumClientSession::StreamRequest::DoCallback(int rv) {
660 CHECK_NE(rv, ERR_IO_PENDING);
661 CHECK(!callback_.is_null());
662
663 // The client callback can do anything, including destroying this class,
664 // so any pending callback must be issued after everything else is done.
665 std::move(callback_).Run(rv);
666 }
667
DoLoop(int rv)668 int QuicChromiumClientSession::StreamRequest::DoLoop(int rv) {
669 do {
670 State state = next_state_;
671 next_state_ = STATE_NONE;
672 switch (state) {
673 case STATE_WAIT_FOR_CONFIRMATION:
674 CHECK_EQ(OK, rv);
675 rv = DoWaitForConfirmation();
676 break;
677 case STATE_WAIT_FOR_CONFIRMATION_COMPLETE:
678 rv = DoWaitForConfirmationComplete(rv);
679 break;
680 case STATE_REQUEST_STREAM:
681 CHECK_EQ(OK, rv);
682 rv = DoRequestStream();
683 break;
684 case STATE_REQUEST_STREAM_COMPLETE:
685 rv = DoRequestStreamComplete(rv);
686 break;
687 default:
688 NOTREACHED() << "next_state_: " << next_state_;
689 break;
690 }
691 } while (next_state_ != STATE_NONE && next_state_ && rv != ERR_IO_PENDING);
692
693 return rv;
694 }
695
DoWaitForConfirmation()696 int QuicChromiumClientSession::StreamRequest::DoWaitForConfirmation() {
697 next_state_ = STATE_WAIT_FOR_CONFIRMATION_COMPLETE;
698 if (requires_confirmation_) {
699 return session_->WaitForHandshakeConfirmation(
700 base::BindOnce(&QuicChromiumClientSession::StreamRequest::OnIOComplete,
701 weak_factory_.GetWeakPtr()));
702 }
703
704 return OK;
705 }
706
DoWaitForConfirmationComplete(int rv)707 int QuicChromiumClientSession::StreamRequest::DoWaitForConfirmationComplete(
708 int rv) {
709 DCHECK_NE(ERR_IO_PENDING, rv);
710 if (rv < 0) {
711 return rv;
712 }
713
714 next_state_ = STATE_REQUEST_STREAM;
715 return OK;
716 }
717
DoRequestStream()718 int QuicChromiumClientSession::StreamRequest::DoRequestStream() {
719 next_state_ = STATE_REQUEST_STREAM_COMPLETE;
720
721 return session_->TryCreateStream(this);
722 }
723
DoRequestStreamComplete(int rv)724 int QuicChromiumClientSession::StreamRequest::DoRequestStreamComplete(int rv) {
725 DCHECK(rv == OK || !stream_);
726
727 return rv;
728 }
729
730 QuicChromiumClientSession::QuicChromiumPathValidationContext::
QuicChromiumPathValidationContext(const quic::QuicSocketAddress & self_address,const quic::QuicSocketAddress & peer_address,handles::NetworkHandle network,std::unique_ptr<QuicChromiumPacketWriter> writer,std::unique_ptr<QuicChromiumPacketReader> reader)731 QuicChromiumPathValidationContext(
732 const quic::QuicSocketAddress& self_address,
733 const quic::QuicSocketAddress& peer_address,
734 handles::NetworkHandle network,
735 std::unique_ptr<QuicChromiumPacketWriter> writer,
736 std::unique_ptr<QuicChromiumPacketReader> reader)
737 : QuicPathValidationContext(self_address, peer_address),
738 network_handle_(network),
739 writer_(std::move(writer)),
740 reader_(std::move(reader)) {}
741
742 QuicChromiumClientSession::QuicChromiumPathValidationContext::
743 ~QuicChromiumPathValidationContext() = default;
744
745 handles::NetworkHandle
network()746 QuicChromiumClientSession::QuicChromiumPathValidationContext::network() {
747 return network_handle_;
748 }
749 quic::QuicPacketWriter*
WriterToUse()750 QuicChromiumClientSession::QuicChromiumPathValidationContext::WriterToUse() {
751 return writer_.get();
752 }
753 std::unique_ptr<QuicChromiumPacketWriter>
ReleaseWriter()754 QuicChromiumClientSession::QuicChromiumPathValidationContext::ReleaseWriter() {
755 return std::move(writer_);
756 }
757 std::unique_ptr<QuicChromiumPacketReader>
ReleaseReader()758 QuicChromiumClientSession::QuicChromiumPathValidationContext::ReleaseReader() {
759 return std::move(reader_);
760 }
761
762 QuicChromiumClientSession::ConnectionMigrationValidationResultDelegate::
ConnectionMigrationValidationResultDelegate(QuicChromiumClientSession * session)763 ConnectionMigrationValidationResultDelegate(
764 QuicChromiumClientSession* session)
765 : session_(session) {}
766
767 void QuicChromiumClientSession::ConnectionMigrationValidationResultDelegate::
OnPathValidationSuccess(std::unique_ptr<quic::QuicPathValidationContext> context,quic::QuicTime start_time)768 OnPathValidationSuccess(
769 std::unique_ptr<quic::QuicPathValidationContext> context,
770 quic::QuicTime start_time) {
771 auto* chrome_context =
772 static_cast<QuicChromiumPathValidationContext*>(context.get());
773 session_->OnConnectionMigrationProbeSucceeded(
774 chrome_context->network(), chrome_context->peer_address(),
775 chrome_context->self_address(), chrome_context->ReleaseWriter(),
776 chrome_context->ReleaseReader());
777 }
778
779 void QuicChromiumClientSession::ConnectionMigrationValidationResultDelegate::
OnPathValidationFailure(std::unique_ptr<quic::QuicPathValidationContext> context)780 OnPathValidationFailure(
781 std::unique_ptr<quic::QuicPathValidationContext> context) {
782 session_->connection()->OnPathValidationFailureAtClient(
783 /*is_multi_port=*/false, *context);
784 // Note that socket, packet writer, and packet reader in |context| will be
785 // discarded.
786 auto* chrome_context =
787 static_cast<QuicChromiumPathValidationContext*>(context.get());
788 session_->OnProbeFailed(chrome_context->network(),
789 chrome_context->peer_address());
790 }
791
792 QuicChromiumClientSession::PortMigrationValidationResultDelegate::
PortMigrationValidationResultDelegate(QuicChromiumClientSession * session)793 PortMigrationValidationResultDelegate(QuicChromiumClientSession* session)
794 : session_(session) {}
795
796 void QuicChromiumClientSession::PortMigrationValidationResultDelegate::
OnPathValidationSuccess(std::unique_ptr<quic::QuicPathValidationContext> context,quic::QuicTime start_time)797 OnPathValidationSuccess(
798 std::unique_ptr<quic::QuicPathValidationContext> context,
799 quic::QuicTime start_time) {
800 auto* chrome_context =
801 static_cast<QuicChromiumPathValidationContext*>(context.get());
802 session_->OnPortMigrationProbeSucceeded(
803 chrome_context->network(), chrome_context->peer_address(),
804 chrome_context->self_address(), chrome_context->ReleaseWriter(),
805 chrome_context->ReleaseReader());
806 }
807
808 void QuicChromiumClientSession::PortMigrationValidationResultDelegate::
OnPathValidationFailure(std::unique_ptr<quic::QuicPathValidationContext> context)809 OnPathValidationFailure(
810 std::unique_ptr<quic::QuicPathValidationContext> context) {
811 session_->connection()->OnPathValidationFailureAtClient(
812 /*is_multi_port=*/false, *context);
813 // Note that socket, packet writer, and packet reader in |context| will be
814 // discarded.
815 auto* chrome_context =
816 static_cast<QuicChromiumPathValidationContext*>(context.get());
817 session_->OnProbeFailed(chrome_context->network(),
818 chrome_context->peer_address());
819 }
820
821 QuicChromiumClientSession::ServerPreferredAddressValidationResultDelegate::
ServerPreferredAddressValidationResultDelegate(QuicChromiumClientSession * session)822 ServerPreferredAddressValidationResultDelegate(
823 QuicChromiumClientSession* session)
824 : session_(session) {}
825
826 void QuicChromiumClientSession::ServerPreferredAddressValidationResultDelegate::
OnPathValidationSuccess(std::unique_ptr<quic::QuicPathValidationContext> context,quic::QuicTime start_time)827 OnPathValidationSuccess(
828 std::unique_ptr<quic::QuicPathValidationContext> context,
829 quic::QuicTime start_time) {
830 auto* chrome_context =
831 static_cast<QuicChromiumPathValidationContext*>(context.get());
832 session_->OnServerPreferredAddressProbeSucceeded(
833 chrome_context->network(), chrome_context->peer_address(),
834 chrome_context->self_address(), chrome_context->ReleaseWriter(),
835 chrome_context->ReleaseReader());
836 }
837
838 void QuicChromiumClientSession::ServerPreferredAddressValidationResultDelegate::
OnPathValidationFailure(std::unique_ptr<quic::QuicPathValidationContext> context)839 OnPathValidationFailure(
840 std::unique_ptr<quic::QuicPathValidationContext> context) {
841 session_->connection()->OnPathValidationFailureAtClient(
842 /*is_multi_port=*/false, *context);
843 // Note that socket, packet writer, and packet reader in |context| will be
844 // discarded.
845 auto* chrome_context =
846 static_cast<QuicChromiumPathValidationContext*>(context.get());
847 session_->OnProbeFailed(chrome_context->network(),
848 chrome_context->peer_address());
849 }
850
851 QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
QuicChromiumPathValidationWriterDelegate(QuicChromiumClientSession * session,base::SequencedTaskRunner * task_runner)852 QuicChromiumPathValidationWriterDelegate(
853 QuicChromiumClientSession* session,
854 base::SequencedTaskRunner* task_runner)
855 : session_(session),
856 task_runner_(task_runner),
857 network_(handles::kInvalidNetworkHandle) {}
858
859 QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
860 ~QuicChromiumPathValidationWriterDelegate() = default;
861
862 int QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
HandleWriteError(int error_code,scoped_refptr<QuicChromiumPacketWriter::ReusableIOBuffer> last_packet)863 HandleWriteError(
864 int error_code,
865 scoped_refptr<QuicChromiumPacketWriter::ReusableIOBuffer> last_packet) {
866 // Write error on the probing network is not recoverable.
867 DVLOG(1) << "Probing packet encounters write error " << error_code;
868 // Post a task to notify |session_| that this probe failed and cancel
869 // undergoing probing, which will delete the packet writer.
870 task_runner_->PostTask(
871 FROM_HERE,
872 base::BindOnce(
873 &QuicChromiumPathValidationWriterDelegate::NotifySessionProbeFailed,
874 weak_factory_.GetWeakPtr(), network_));
875 return error_code;
876 }
877
878 void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
OnWriteError(int error_code)879 OnWriteError(int error_code) {
880 NotifySessionProbeFailed(network_);
881 }
882 void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
OnWriteUnblocked()883 OnWriteUnblocked() {}
884
885 void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
NotifySessionProbeFailed(handles::NetworkHandle network)886 NotifySessionProbeFailed(handles::NetworkHandle network) {
887 session_->OnProbeFailed(network, peer_address_);
888 }
889
890 void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
set_peer_address(const quic::QuicSocketAddress & peer_address)891 set_peer_address(const quic::QuicSocketAddress& peer_address) {
892 peer_address_ = peer_address;
893 }
894
895 void QuicChromiumClientSession::QuicChromiumPathValidationWriterDelegate::
set_network(handles::NetworkHandle network)896 set_network(handles::NetworkHandle network) {
897 network_ = network;
898 }
899
QuicChromiumClientSession(quic::QuicConnection * connection,std::unique_ptr<DatagramClientSocket> socket,QuicSessionPool * session_pool,QuicCryptoClientStreamFactory * crypto_client_stream_factory,const quic::QuicClock * clock,TransportSecurityState * transport_security_state,SSLConfigService * ssl_config_service,std::unique_ptr<QuicServerInfo> server_info,const QuicSessionKey & session_key,bool require_confirmation,bool migrate_session_early_v2,bool migrate_sessions_on_network_change_v2,handles::NetworkHandle default_network,quic::QuicTime::Delta retransmittable_on_wire_timeout,bool migrate_idle_session,bool allow_port_migration,base::TimeDelta idle_migration_period,int multi_port_probing_interval,base::TimeDelta max_time_on_non_default_network,int max_migrations_to_non_default_network_on_write_error,int max_migrations_to_non_default_network_on_path_degrading,int yield_after_packets,quic::QuicTime::Delta yield_after_duration,int cert_verify_flags,const quic::QuicConfig & config,std::unique_ptr<QuicCryptoClientConfigHandle> crypto_config,const char * const connection_description,base::TimeTicks dns_resolution_start_time,base::TimeTicks dns_resolution_end_time,const base::TickClock * tick_clock,base::SequencedTaskRunner * task_runner,std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,const ConnectionEndpointMetadata & metadata,const NetLogWithSource & net_log)900 QuicChromiumClientSession::QuicChromiumClientSession(
901 quic::QuicConnection* connection,
902 std::unique_ptr<DatagramClientSocket> socket,
903 QuicSessionPool* session_pool,
904 QuicCryptoClientStreamFactory* crypto_client_stream_factory,
905 const quic::QuicClock* clock,
906 TransportSecurityState* transport_security_state,
907 SSLConfigService* ssl_config_service,
908 std::unique_ptr<QuicServerInfo> server_info,
909 const QuicSessionKey& session_key,
910 bool require_confirmation,
911 bool migrate_session_early_v2,
912 bool migrate_sessions_on_network_change_v2,
913 handles::NetworkHandle default_network,
914 quic::QuicTime::Delta retransmittable_on_wire_timeout,
915 bool migrate_idle_session,
916 bool allow_port_migration,
917 base::TimeDelta idle_migration_period,
918 int multi_port_probing_interval,
919 base::TimeDelta max_time_on_non_default_network,
920 int max_migrations_to_non_default_network_on_write_error,
921 int max_migrations_to_non_default_network_on_path_degrading,
922 int yield_after_packets,
923 quic::QuicTime::Delta yield_after_duration,
924 int cert_verify_flags,
925 const quic::QuicConfig& config,
926 std::unique_ptr<QuicCryptoClientConfigHandle> crypto_config,
927 const char* const connection_description,
928 base::TimeTicks dns_resolution_start_time,
929 base::TimeTicks dns_resolution_end_time,
930 const base::TickClock* tick_clock,
931 base::SequencedTaskRunner* task_runner,
932 std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
933 const ConnectionEndpointMetadata& metadata,
934 const NetLogWithSource& net_log)
935 : quic::QuicSpdyClientSessionBase(connection,
936 /*visitor=*/nullptr,
937 config,
938 connection->supported_versions()),
939 session_key_(session_key),
940 require_confirmation_(require_confirmation),
941 migrate_session_early_v2_(migrate_session_early_v2),
942 migrate_session_on_network_change_v2_(
943 migrate_sessions_on_network_change_v2),
944 migrate_idle_session_(migrate_idle_session),
945 allow_port_migration_(allow_port_migration),
946 idle_migration_period_(idle_migration_period),
947 max_time_on_non_default_network_(max_time_on_non_default_network),
948 max_migrations_to_non_default_network_on_write_error_(
949 max_migrations_to_non_default_network_on_write_error),
950 max_migrations_to_non_default_network_on_path_degrading_(
951 max_migrations_to_non_default_network_on_path_degrading),
952 clock_(clock),
953 yield_after_packets_(yield_after_packets),
954 yield_after_duration_(yield_after_duration),
955 most_recent_path_degrading_timestamp_(base::TimeTicks()),
956 most_recent_network_disconnected_timestamp_(base::TimeTicks()),
957 tick_clock_(tick_clock),
958 most_recent_stream_close_time_(tick_clock_->NowTicks()),
959 most_recent_write_error_timestamp_(base::TimeTicks()),
960 crypto_config_(std::move(crypto_config)),
961 session_pool_(session_pool),
962 transport_security_state_(transport_security_state),
963 ssl_config_service_(ssl_config_service),
964 server_info_(std::move(server_info)),
965 task_runner_(task_runner),
966 net_log_(NetLogWithSource::Make(net_log.net_log(),
967 NetLogSourceType::QUIC_SESSION)),
968 logger_(std::make_unique<QuicConnectionLogger>(
969 this,
970 connection_description,
971 std::move(socket_performance_watcher),
972 net_log_)),
973 http3_logger_(std::make_unique<QuicHttp3Logger>(net_log_)),
974 path_validation_writer_delegate_(this, task_runner_),
975 ech_config_list_(metadata.ech_config_list) {
976 default_network_ = default_network;
977 auto* socket_raw = socket.get();
978 packet_readers_.push_back(std::make_unique<QuicChromiumPacketReader>(
979 std::move(socket), clock, this, yield_after_packets, yield_after_duration,
980 net_log_));
981 crypto_stream_ = crypto_client_stream_factory->CreateQuicCryptoClientStream(
982 session_key.server_id(), this,
983 std::make_unique<ProofVerifyContextChromium>(cert_verify_flags, net_log_),
984 crypto_config_->GetConfig());
985 set_debug_visitor(http3_logger_.get());
986 connection->set_debug_visitor(logger_.get());
987 connection->set_creator_debug_delegate(logger_.get());
988 migrate_back_to_default_timer_.SetTaskRunner(task_runner_.get());
989 net_log_.BeginEvent(NetLogEventType::QUIC_SESSION, [&] {
990 return NetLogQuicClientSessionParams(
991 net_log, &session_key, connection_id(),
992 connection->client_connection_id(), supported_versions(),
993 cert_verify_flags, require_confirmation_, ech_config_list_);
994 });
995 // Associate the owned NetLog with the parent NetLog.
996 net_log.AddEventReferencingSource(NetLogEventType::QUIC_SESSION_CREATED,
997 net_log_.source());
998
999 IPEndPoint address;
1000 if (socket_raw && socket_raw->GetLocalAddress(&address) == OK &&
1001 address.GetFamily() == ADDRESS_FAMILY_IPV6) {
1002 connection->SetMaxPacketLength(connection->max_packet_length() -
1003 kAdditionalOverheadForIPv6);
1004 }
1005 if (multi_port_probing_interval > 0) {
1006 connection->SetMultiPortProbingInterval(
1007 quic::QuicTime::Delta::FromSeconds(multi_port_probing_interval));
1008 }
1009 connect_timing_.domain_lookup_start = dns_resolution_start_time;
1010 connect_timing_.domain_lookup_end = dns_resolution_end_time;
1011 if (!retransmittable_on_wire_timeout.IsZero()) {
1012 connection->set_initial_retransmittable_on_wire_timeout(
1013 retransmittable_on_wire_timeout);
1014 }
1015 }
1016
~QuicChromiumClientSession()1017 QuicChromiumClientSession::~QuicChromiumClientSession() {
1018 DCHECK(callback_.is_null());
1019
1020 for (auto& observer : connectivity_observer_list_) {
1021 observer.OnSessionRemoved(this);
1022 }
1023
1024 net_log_.EndEvent(NetLogEventType::QUIC_SESSION);
1025 DCHECK(waiting_for_confirmation_callbacks_.empty());
1026 DCHECK(!HasActiveRequestStreams());
1027 DCHECK(handles_.empty());
1028 if (!stream_requests_.empty()) {
1029 // The session must be closed before it is destroyed.
1030 CancelAllRequests(ERR_UNEXPECTED);
1031 }
1032 connection()->set_debug_visitor(nullptr);
1033
1034 if (connection()->connected()) {
1035 // Ensure that the connection is closed by the time the session is
1036 // destroyed.
1037 connection()->CloseConnection(quic::QUIC_PEER_GOING_AWAY,
1038 "session torn down",
1039 quic::ConnectionCloseBehavior::SILENT_CLOSE);
1040 }
1041
1042 if (IsEncryptionEstablished()) {
1043 RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
1044 }
1045 if (OneRttKeysAvailable()) {
1046 RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
1047 } else {
1048 RecordHandshakeState(STATE_FAILED);
1049 }
1050
1051 UMA_HISTOGRAM_ENUMERATION(
1052 "Net.QuicSession.EcnMarksObserved",
1053 static_cast<EcnPermutations>(observed_incoming_ecn_));
1054 UMA_HISTOGRAM_COUNTS_10M(
1055 "Net.QuicSession.PacketsBeforeEcnTransition",
1056 observed_ecn_transition_ ? incoming_packets_before_ecn_transition_ : 0);
1057 UMA_HISTOGRAM_COUNTS_1M("Net.QuicSession.NumTotalStreams",
1058 num_total_streams_);
1059
1060 if (!OneRttKeysAvailable()) {
1061 return;
1062 }
1063
1064 // Sending one client_hello means we had zero handshake-round-trips.
1065 int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
1066
1067 SSLInfo ssl_info;
1068 // QUIC supports only secure urls.
1069 if (GetSSLInfo(&ssl_info) && ssl_info.cert.get()) {
1070 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
1071 round_trip_handshakes, 1, 3, 4);
1072 if (require_confirmation_) {
1073 UMA_HISTOGRAM_CUSTOM_COUNTS(
1074 "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
1075 round_trip_handshakes, 1, 3, 4);
1076 }
1077 }
1078
1079 const quic::QuicConnectionStats stats = connection()->GetStats();
1080
1081 // The MTU used by QUIC is limited to a fairly small set of predefined values
1082 // (initial values and MTU discovery values), but does not fare well when
1083 // bucketed. Because of that, a sparse histogram is used here.
1084 base::UmaHistogramSparse("Net.QuicSession.ClientSideMtu", stats.egress_mtu);
1085 base::UmaHistogramSparse("Net.QuicSession.ServerSideMtu", stats.ingress_mtu);
1086
1087 UMA_HISTOGRAM_COUNTS_1M("Net.QuicSession.MtuProbesSent",
1088 connection()->mtu_probe_count());
1089
1090 if (stats.packets_sent >= 100) {
1091 // Used to monitor for regressions that effect large uploads.
1092 UMA_HISTOGRAM_COUNTS_1000(
1093 "Net.QuicSession.PacketRetransmitsPerMille",
1094 1000 * stats.packets_retransmitted / stats.packets_sent);
1095 }
1096
1097 if (stats.max_sequence_reordering == 0) {
1098 return;
1099 }
1100 const base::HistogramBase::Sample kMaxReordering = 100;
1101 base::HistogramBase::Sample reordering = kMaxReordering;
1102 if (stats.min_rtt_us > 0) {
1103 reordering = static_cast<base::HistogramBase::Sample>(
1104 100 * stats.max_time_reordering_us / stats.min_rtt_us);
1105 }
1106 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime", reordering,
1107 1, kMaxReordering, 50);
1108 if (stats.min_rtt_us > 100 * 1000) {
1109 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
1110 reordering, 1, kMaxReordering, 50);
1111 }
1112 UMA_HISTOGRAM_COUNTS_1M(
1113 "Net.QuicSession.MaxReordering",
1114 static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
1115 }
1116
Initialize()1117 void QuicChromiumClientSession::Initialize() {
1118 set_max_inbound_header_list_size(kQuicMaxHeaderListSize);
1119 quic::QuicSpdyClientSessionBase::Initialize();
1120 }
1121
WriteHeadersOnHeadersStream(quic::QuicStreamId id,spdy::Http2HeaderBlock headers,bool fin,const spdy::SpdyStreamPrecedence & precedence,quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface> ack_listener)1122 size_t QuicChromiumClientSession::WriteHeadersOnHeadersStream(
1123 quic::QuicStreamId id,
1124 spdy::Http2HeaderBlock headers,
1125 bool fin,
1126 const spdy::SpdyStreamPrecedence& precedence,
1127 quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface>
1128 ack_listener) {
1129 const int weight =
1130 spdy::Spdy3PriorityToHttp2Weight(precedence.spdy3_priority());
1131 return WriteHeadersOnHeadersStreamImpl(id, std::move(headers), fin,
1132 /* parent_stream_id = */ 0, weight,
1133 /* exclusive = */ false,
1134 std::move(ack_listener));
1135 }
1136
OnHttp3GoAway(uint64_t id)1137 void QuicChromiumClientSession::OnHttp3GoAway(uint64_t id) {
1138 quic::QuicSpdySession::OnHttp3GoAway(id);
1139 NotifyFactoryOfSessionGoingAway();
1140
1141 PerformActionOnActiveStreams([id](quic::QuicStream* stream) {
1142 if (stream->id() >= id) {
1143 static_cast<QuicChromiumClientStream*>(stream)->OnError(
1144 ERR_QUIC_GOAWAY_REQUEST_CAN_BE_RETRIED);
1145 }
1146 return true;
1147 });
1148 }
1149
OnAcceptChFrameReceivedViaAlps(const quic::AcceptChFrame & frame)1150 void QuicChromiumClientSession::OnAcceptChFrameReceivedViaAlps(
1151 const quic::AcceptChFrame& frame) {
1152 bool has_valid_entry = false;
1153 bool has_invalid_entry = false;
1154 for (const auto& entry : frame.entries) {
1155 const url::SchemeHostPort scheme_host_port(GURL(entry.origin));
1156 // |entry.origin| must be a valid SchemeHostPort.
1157 std::string serialized = scheme_host_port.Serialize();
1158 if (serialized.empty() || entry.origin != serialized) {
1159 has_invalid_entry = true;
1160 continue;
1161 }
1162 has_valid_entry = true;
1163 accept_ch_entries_received_via_alps_.emplace(std::move(scheme_host_port),
1164 entry.value);
1165
1166 net_log_.AddEvent(NetLogEventType::QUIC_ACCEPT_CH_FRAME_RECEIVED,
1167 [&] { return NetLogAcceptChFrameReceivedParams(entry); });
1168 }
1169 LogAcceptChFrameReceivedHistogram(has_valid_entry, has_invalid_entry);
1170 }
1171
AddHandle(Handle * handle)1172 void QuicChromiumClientSession::AddHandle(Handle* handle) {
1173 if (going_away_) {
1174 handle->OnSessionClosed(connection()->version(), ERR_UNEXPECTED, error(),
1175 port_migration_detected_,
1176 quic_connection_migration_attempted_,
1177 quic_connection_migration_successful_,
1178 GetConnectTiming(), WasConnectionEverUsed());
1179 return;
1180 }
1181
1182 DCHECK(!base::Contains(handles_, handle));
1183 handles_.insert(handle);
1184 }
1185
RemoveHandle(Handle * handle)1186 void QuicChromiumClientSession::RemoveHandle(Handle* handle) {
1187 DCHECK(base::Contains(handles_, handle));
1188 handles_.erase(handle);
1189 }
1190
AddConnectivityObserver(ConnectivityObserver * observer)1191 void QuicChromiumClientSession::AddConnectivityObserver(
1192 ConnectivityObserver* observer) {
1193 connectivity_observer_list_.AddObserver(observer);
1194 observer->OnSessionRegistered(this, GetCurrentNetwork());
1195 }
1196
RemoveConnectivityObserver(ConnectivityObserver * observer)1197 void QuicChromiumClientSession::RemoveConnectivityObserver(
1198 ConnectivityObserver* observer) {
1199 connectivity_observer_list_.RemoveObserver(observer);
1200 }
1201
1202 // TODO(zhongyi): replace migration_session_* booleans with
1203 // ConnectionMigrationMode.
connection_migration_mode() const1204 ConnectionMigrationMode QuicChromiumClientSession::connection_migration_mode()
1205 const {
1206 if (migrate_session_early_v2_) {
1207 return ConnectionMigrationMode::FULL_MIGRATION_V2;
1208 }
1209
1210 if (migrate_session_on_network_change_v2_) {
1211 return ConnectionMigrationMode::NO_MIGRATION_ON_PATH_DEGRADING_V2;
1212 }
1213
1214 return ConnectionMigrationMode::NO_MIGRATION;
1215 }
1216
WaitForHandshakeConfirmation(CompletionOnceCallback callback)1217 int QuicChromiumClientSession::WaitForHandshakeConfirmation(
1218 CompletionOnceCallback callback) {
1219 if (!connection()->connected()) {
1220 return ERR_CONNECTION_CLOSED;
1221 }
1222
1223 if (OneRttKeysAvailable()) {
1224 return OK;
1225 }
1226
1227 waiting_for_confirmation_callbacks_.push_back(std::move(callback));
1228 return ERR_IO_PENDING;
1229 }
1230
TryCreateStream(StreamRequest * request)1231 int QuicChromiumClientSession::TryCreateStream(StreamRequest* request) {
1232 if (goaway_received()) {
1233 DVLOG(1) << "Going away.";
1234 return ERR_CONNECTION_CLOSED;
1235 }
1236
1237 if (!connection()->connected()) {
1238 DVLOG(1) << "Already closed.";
1239 return ERR_CONNECTION_CLOSED;
1240 }
1241
1242 if (going_away_) {
1243 return ERR_CONNECTION_CLOSED;
1244 }
1245
1246 bool can_open_next = CanOpenNextOutgoingBidirectionalStream();
1247 if (can_open_next) {
1248 request->stream_ =
1249 CreateOutgoingReliableStreamImpl(request->traffic_annotation())
1250 ->CreateHandle();
1251 return OK;
1252 }
1253
1254 // Calling CanOpenNextOutgoingBidirectionalStream() could close the
1255 // connection.
1256 if (!connection()->connected()) {
1257 return ERR_CONNECTION_CLOSED;
1258 }
1259
1260 request->pending_start_time_ = tick_clock_->NowTicks();
1261 stream_requests_.push_back(request);
1262 UMA_HISTOGRAM_COUNTS_1000("Net.QuicSession.NumPendingStreamRequests",
1263 stream_requests_.size());
1264 return ERR_IO_PENDING;
1265 }
1266
CancelRequest(StreamRequest * request)1267 void QuicChromiumClientSession::CancelRequest(StreamRequest* request) {
1268 // Remove |request| from the queue while preserving the order of the
1269 // other elements.
1270 auto it = base::ranges::find(stream_requests_, request);
1271 if (it != stream_requests_.end()) {
1272 it = stream_requests_.erase(it);
1273 }
1274 }
1275
ShouldCreateOutgoingBidirectionalStream()1276 bool QuicChromiumClientSession::ShouldCreateOutgoingBidirectionalStream() {
1277 if (!crypto_stream_->encryption_established()) {
1278 DVLOG(1) << "Encryption not active so no outgoing stream created.";
1279 return false;
1280 }
1281 if (!CanOpenNextOutgoingBidirectionalStream()) {
1282 DVLOG(1) << "Failed to create a new outgoing stream. " << "Already "
1283 << GetNumActiveStreams() << " open.";
1284 return false;
1285 }
1286 if (goaway_received()) {
1287 DVLOG(1) << "Failed to create a new outgoing stream. "
1288 << "Already received goaway.";
1289 return false;
1290 }
1291 if (going_away_) {
1292 return false;
1293 }
1294 return true;
1295 }
1296
ShouldCreateOutgoingUnidirectionalStream()1297 bool QuicChromiumClientSession::ShouldCreateOutgoingUnidirectionalStream() {
1298 NOTREACHED() << "Try to create outgoing unidirectional streams";
1299 return false;
1300 }
1301
WasConnectionEverUsed()1302 bool QuicChromiumClientSession::WasConnectionEverUsed() {
1303 const quic::QuicConnectionStats& stats = connection()->GetStats();
1304 return stats.bytes_sent > 0 || stats.bytes_received > 0;
1305 }
1306
1307 QuicChromiumClientStream*
CreateOutgoingBidirectionalStream()1308 QuicChromiumClientSession::CreateOutgoingBidirectionalStream() {
1309 NOTREACHED() << "CreateOutgoingReliableStreamImpl should be called directly";
1310 return nullptr;
1311 }
1312
1313 QuicChromiumClientStream*
CreateOutgoingUnidirectionalStream()1314 QuicChromiumClientSession::CreateOutgoingUnidirectionalStream() {
1315 NOTREACHED() << "Try to create outgoing unidirectional stream";
1316 return nullptr;
1317 }
1318
1319 QuicChromiumClientStream*
CreateOutgoingReliableStreamImpl(const NetworkTrafficAnnotationTag & traffic_annotation)1320 QuicChromiumClientSession::CreateOutgoingReliableStreamImpl(
1321 const NetworkTrafficAnnotationTag& traffic_annotation) {
1322 DCHECK(connection()->connected());
1323 QuicChromiumClientStream* stream = new QuicChromiumClientStream(
1324 GetNextOutgoingBidirectionalStreamId(), this, quic::BIDIRECTIONAL,
1325 net_log_, traffic_annotation);
1326 ActivateStream(base::WrapUnique(stream));
1327 ++num_total_streams_;
1328 UMA_HISTOGRAM_COUNTS_1M("Net.QuicSession.NumOpenStreams",
1329 GetNumActiveStreams());
1330 // The previous histogram puts 100 in a bucket betweeen 86-113 which does
1331 // not shed light on if chrome ever things it has more than 100 streams open.
1332 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.TooManyOpenStreams",
1333 GetNumActiveStreams() > 100);
1334 return stream;
1335 }
1336
1337 quic::QuicCryptoClientStream*
GetMutableCryptoStream()1338 QuicChromiumClientSession::GetMutableCryptoStream() {
1339 return crypto_stream_.get();
1340 }
1341
GetCryptoStream() const1342 const quic::QuicCryptoClientStream* QuicChromiumClientSession::GetCryptoStream()
1343 const {
1344 return crypto_stream_.get();
1345 }
1346
GetRemoteEndpoint(IPEndPoint * endpoint)1347 int QuicChromiumClientSession::GetRemoteEndpoint(IPEndPoint* endpoint) {
1348 *endpoint = ToIPEndPoint(peer_address());
1349 return OK;
1350 }
1351
1352 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
1353 // we learn about SSL info (sync vs async vs cached).
GetSSLInfo(SSLInfo * ssl_info) const1354 bool QuicChromiumClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
1355 ssl_info->Reset();
1356 if (!cert_verify_result_) {
1357 return false;
1358 }
1359
1360 ssl_info->cert_status = cert_verify_result_->cert_status;
1361 ssl_info->cert = cert_verify_result_->verified_cert;
1362
1363 ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
1364 ssl_info->is_issued_by_known_root =
1365 cert_verify_result_->is_issued_by_known_root;
1366 ssl_info->pkp_bypassed = pkp_bypassed_;
1367
1368 ssl_info->client_cert_sent = false;
1369 ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
1370 ssl_info->is_fatal_cert_error = is_fatal_cert_error_;
1371
1372 ssl_info->signed_certificate_timestamps = cert_verify_result_->scts;
1373 ssl_info->ct_policy_compliance = cert_verify_result_->policy_compliance;
1374
1375 DCHECK(connection()->version().UsesTls());
1376 const auto& crypto_params = crypto_stream_->crypto_negotiated_params();
1377 uint16_t cipher_suite = crypto_params.cipher_suite;
1378 int ssl_connection_status = 0;
1379 SSLConnectionStatusSetCipherSuite(cipher_suite, &ssl_connection_status);
1380 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_QUIC,
1381 &ssl_connection_status);
1382 ssl_info->connection_status = ssl_connection_status;
1383
1384 ssl_info->key_exchange_group = crypto_params.key_exchange_group;
1385 ssl_info->peer_signature_algorithm = crypto_params.peer_signature_algorithm;
1386 ssl_info->encrypted_client_hello = crypto_params.encrypted_client_hello;
1387 return true;
1388 }
1389
GetAcceptChViaAlps(const url::SchemeHostPort & scheme_host_port) const1390 std::string_view QuicChromiumClientSession::GetAcceptChViaAlps(
1391 const url::SchemeHostPort& scheme_host_port) const {
1392 auto it = accept_ch_entries_received_via_alps_.find(scheme_host_port);
1393 if (it == accept_ch_entries_received_via_alps_.end()) {
1394 LogAcceptChForOriginHistogram(false);
1395 return {};
1396 } else {
1397 LogAcceptChForOriginHistogram(true);
1398 return it->second;
1399 }
1400 }
1401
CryptoConnect(CompletionOnceCallback callback)1402 int QuicChromiumClientSession::CryptoConnect(CompletionOnceCallback callback) {
1403 connect_timing_.connect_start = tick_clock_->NowTicks();
1404 RecordHandshakeState(STATE_STARTED);
1405 DCHECK(flow_controller());
1406
1407 if (!crypto_stream_->CryptoConnect()) {
1408 return ERR_QUIC_HANDSHAKE_FAILED;
1409 }
1410
1411 if (OneRttKeysAvailable()) {
1412 connect_timing_.connect_end = tick_clock_->NowTicks();
1413 return OK;
1414 }
1415
1416 // Unless we require handshake confirmation, activate the session if
1417 // we have established initial encryption.
1418 if (!require_confirmation_ && IsEncryptionEstablished()) {
1419 return OK;
1420 }
1421
1422 callback_ = std::move(callback);
1423 return ERR_IO_PENDING;
1424 }
1425
GetNumSentClientHellos() const1426 int QuicChromiumClientSession::GetNumSentClientHellos() const {
1427 return crypto_stream_->num_sent_client_hellos();
1428 }
1429
CanPool(std::string_view hostname,const QuicSessionKey & other_session_key) const1430 bool QuicChromiumClientSession::CanPool(
1431 std::string_view hostname,
1432 const QuicSessionKey& other_session_key) const {
1433 DCHECK(connection()->connected());
1434 if (!session_key_.CanUseForAliasing(other_session_key)) {
1435 return false;
1436 }
1437 SSLInfo ssl_info;
1438 if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
1439 NOTREACHED() << "QUIC should always have certificates.";
1440 return false;
1441 }
1442
1443 return SpdySession::CanPool(transport_security_state_, ssl_info,
1444 *ssl_config_service_, session_key_.host(),
1445 hostname);
1446 }
1447
ShouldCreateIncomingStream(quic::QuicStreamId id)1448 bool QuicChromiumClientSession::ShouldCreateIncomingStream(
1449 quic::QuicStreamId id) {
1450 if (!connection()->connected()) {
1451 LOG(DFATAL) << "ShouldCreateIncomingStream called when disconnected";
1452 return false;
1453 }
1454 if (goaway_received()) {
1455 DVLOG(1) << "Cannot create a new outgoing stream. "
1456 << "Already received goaway.";
1457 return false;
1458 }
1459 if (going_away_) {
1460 return false;
1461 }
1462 if (quic::QuicUtils::IsClientInitiatedStreamId(
1463 connection()->transport_version(), id) ||
1464 quic::QuicUtils::IsBidirectionalStreamId(id, connection()->version())) {
1465 LOG(WARNING) << "Received invalid push stream id " << id;
1466 connection()->CloseConnection(
1467 quic::QUIC_INVALID_STREAM_ID,
1468 "Server created non write unidirectional stream",
1469 quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1470 return false;
1471 }
1472 return true;
1473 }
1474
CreateIncomingStream(quic::QuicStreamId id)1475 QuicChromiumClientStream* QuicChromiumClientSession::CreateIncomingStream(
1476 quic::QuicStreamId id) {
1477 if (!ShouldCreateIncomingStream(id)) {
1478 return nullptr;
1479 }
1480 net::NetworkTrafficAnnotationTag traffic_annotation =
1481 net::DefineNetworkTrafficAnnotation("quic_chromium_incoming_session", R"(
1482 semantics {
1483 sender: "Quic Chromium Client Session"
1484 description:
1485 "When a web server needs to push a response to a client, an incoming "
1486 "stream is created to reply the client with pushed message instead "
1487 "of a message from the network."
1488 trigger:
1489 "A request by a server to push a response to the client."
1490 data: "None."
1491 destination: OTHER
1492 destination_other:
1493 "This stream is not used for sending data."
1494 }
1495 policy {
1496 cookies_allowed: NO
1497 setting: "This feature cannot be disabled in settings."
1498 policy_exception_justification:
1499 "Essential for network access."
1500 }
1501 )");
1502 return CreateIncomingReliableStreamImpl(id, traffic_annotation);
1503 }
1504
CreateIncomingStream(quic::PendingStream * pending)1505 QuicChromiumClientStream* QuicChromiumClientSession::CreateIncomingStream(
1506 quic::PendingStream* pending) {
1507 net::NetworkTrafficAnnotationTag traffic_annotation =
1508 net::DefineNetworkTrafficAnnotation(
1509 "quic_chromium_incoming_pending_session", R"(
1510 semantics {
1511 sender: "Quic Chromium Client Session Pending Stream"
1512 description:
1513 "When a web server needs to push a response to a client, an incoming "
1514 "stream is created to reply to the client with pushed message instead "
1515 "of a message from the network."
1516 trigger:
1517 "A request by a server to push a response to the client."
1518 data: "This stream is only used to receive data from the server."
1519 destination: OTHER
1520 destination_other:
1521 "The web server pushing the response."
1522 }
1523 policy {
1524 cookies_allowed: NO
1525 setting: "This feature cannot be disabled in settings."
1526 policy_exception_justification:
1527 "Essential for network access."
1528 }
1529 )");
1530 return CreateIncomingReliableStreamImpl(pending, traffic_annotation);
1531 }
1532
1533 QuicChromiumClientStream*
CreateIncomingReliableStreamImpl(quic::QuicStreamId id,const NetworkTrafficAnnotationTag & traffic_annotation)1534 QuicChromiumClientSession::CreateIncomingReliableStreamImpl(
1535 quic::QuicStreamId id,
1536 const NetworkTrafficAnnotationTag& traffic_annotation) {
1537 DCHECK(connection()->connected());
1538
1539 QuicChromiumClientStream* stream = new QuicChromiumClientStream(
1540 id, this, quic::READ_UNIDIRECTIONAL, net_log_, traffic_annotation);
1541 ActivateStream(base::WrapUnique(stream));
1542 ++num_total_streams_;
1543 return stream;
1544 }
1545
1546 QuicChromiumClientStream*
CreateIncomingReliableStreamImpl(quic::PendingStream * pending,const NetworkTrafficAnnotationTag & traffic_annotation)1547 QuicChromiumClientSession::CreateIncomingReliableStreamImpl(
1548 quic::PendingStream* pending,
1549 const NetworkTrafficAnnotationTag& traffic_annotation) {
1550 DCHECK(connection()->connected());
1551
1552 QuicChromiumClientStream* stream =
1553 new QuicChromiumClientStream(pending, this, net_log_, traffic_annotation);
1554 ActivateStream(base::WrapUnique(stream));
1555 ++num_total_streams_;
1556 return stream;
1557 }
1558
OnStreamClosed(quic::QuicStreamId stream_id)1559 void QuicChromiumClientSession::OnStreamClosed(quic::QuicStreamId stream_id) {
1560 most_recent_stream_close_time_ = tick_clock_->NowTicks();
1561 quic::QuicStream* stream = GetActiveStream(stream_id);
1562 if (stream != nullptr) {
1563 logger_->UpdateReceivedFrameCounts(stream_id, stream->num_frames_received(),
1564 stream->num_duplicate_frames_received());
1565 }
1566 quic::QuicSpdyClientSessionBase::OnStreamClosed(stream_id);
1567 }
1568
OnCanCreateNewOutgoingStream(bool unidirectional)1569 void QuicChromiumClientSession::OnCanCreateNewOutgoingStream(
1570 bool unidirectional) {
1571 while (CanOpenNextOutgoingBidirectionalStream() &&
1572 !stream_requests_.empty() &&
1573 crypto_stream_->encryption_established() && !goaway_received() &&
1574 !going_away_ && connection()->connected()) {
1575 StreamRequest* request = stream_requests_.front();
1576 // TODO(ckrasic) - analyze data and then add logic to mark QUIC
1577 // broken if wait times are excessive.
1578 UMA_HISTOGRAM_TIMES("Net.QuicSession.PendingStreamsWaitTime",
1579 tick_clock_->NowTicks() - request->pending_start_time_);
1580 stream_requests_.pop_front();
1581
1582 #if BUILDFLAG(ENABLE_WEBSOCKETS)
1583 if (request->for_websockets_) {
1584 std::unique_ptr<WebSocketQuicStreamAdapter> adapter =
1585 CreateWebSocketQuicStreamAdapterImpl(
1586 request->websocket_adapter_delegate_);
1587 request->websocket_adapter_delegate_ = nullptr;
1588 std::move(request->start_websocket_callback_).Run(std::move(adapter));
1589 continue;
1590 }
1591 #endif // BUILDFLAG(ENABLE_WEBSOCKETS)
1592
1593 request->OnRequestCompleteSuccess(
1594 CreateOutgoingReliableStreamImpl(request->traffic_annotation())
1595 ->CreateHandle());
1596 }
1597 }
1598
GetSSLConfig() const1599 quic::QuicSSLConfig QuicChromiumClientSession::GetSSLConfig() const {
1600 quic::QuicSSLConfig config = quic::QuicSpdyClientSessionBase::GetSSLConfig();
1601 if (ssl_config_service_->GetSSLContextConfig().ech_enabled) {
1602 config.ech_grease_enabled = true;
1603 config.ech_config_list.assign(ech_config_list_.begin(),
1604 ech_config_list_.end());
1605 }
1606 return config;
1607 }
1608
OnConfigNegotiated()1609 void QuicChromiumClientSession::OnConfigNegotiated() {
1610 quic::QuicSpdyClientSessionBase::OnConfigNegotiated();
1611 if (!session_pool_ || !session_pool_->allow_server_migration()) {
1612 return;
1613 }
1614 if (!config()->HasReceivedPreferredAddressConnectionIdAndToken()) {
1615 return;
1616 }
1617
1618 // Server has sent an alternate address to connect to.
1619 IPEndPoint old_address;
1620 GetDefaultSocket()->GetPeerAddress(&old_address);
1621
1622 // Migrate only if address families match.
1623 IPEndPoint new_address;
1624 if (old_address.GetFamily() == ADDRESS_FAMILY_IPV6) {
1625 if (!config()->HasReceivedIPv6AlternateServerAddress()) {
1626 return;
1627 }
1628 new_address = ToIPEndPoint(config()->ReceivedIPv6AlternateServerAddress());
1629 } else if (old_address.GetFamily() == ADDRESS_FAMILY_IPV4) {
1630 if (!config()->HasReceivedIPv4AlternateServerAddress()) {
1631 return;
1632 }
1633 new_address = ToIPEndPoint(config()->ReceivedIPv4AlternateServerAddress());
1634 }
1635 DCHECK_EQ(new_address.GetFamily(), old_address.GetFamily());
1636
1637 // Specifying handles::kInvalidNetworkHandle for the |network| parameter
1638 // causes the session to use the default network for the new socket.
1639 // DoNothingAs is passed in as `migration_callback` because OnConfigNegotiated
1640 // does not need to do anything directly with the migration result.
1641 Migrate(handles::kInvalidNetworkHandle, new_address,
1642 /*close_session_on_error=*/true,
1643 base::DoNothingAs<void(MigrationResult)>());
1644 }
1645
SetDefaultEncryptionLevel(quic::EncryptionLevel level)1646 void QuicChromiumClientSession::SetDefaultEncryptionLevel(
1647 quic::EncryptionLevel level) {
1648 if (!callback_.is_null() &&
1649 (!require_confirmation_ || level == quic::ENCRYPTION_FORWARD_SECURE ||
1650 level == quic::ENCRYPTION_ZERO_RTT)) {
1651 // Currently for all CryptoHandshakeEvent events, callback_
1652 // could be called because there are no error events in CryptoHandshakeEvent
1653 // enum. If error events are added to CryptoHandshakeEvent, then the
1654 // following code needs to changed.
1655 std::move(callback_).Run(OK);
1656 }
1657 if (level == quic::ENCRYPTION_FORWARD_SECURE) {
1658 OnCryptoHandshakeComplete();
1659 LogZeroRttStats();
1660 }
1661 if (level == quic::ENCRYPTION_ZERO_RTT) {
1662 attempted_zero_rtt_ = true;
1663 }
1664 quic::QuicSpdySession::SetDefaultEncryptionLevel(level);
1665 }
1666
OnTlsHandshakeComplete()1667 void QuicChromiumClientSession::OnTlsHandshakeComplete() {
1668 if (!callback_.is_null()) {
1669 // Currently for all CryptoHandshakeEvent events, callback_
1670 // could be called because there are no error events in CryptoHandshakeEvent
1671 // enum. If error events are added to CryptoHandshakeEvent, then the
1672 // following code needs to changed.
1673 std::move(callback_).Run(OK);
1674 }
1675
1676 OnCryptoHandshakeComplete();
1677 LogZeroRttStats();
1678 quic::QuicSpdySession::OnTlsHandshakeComplete();
1679 }
1680
OnNewEncryptionKeyAvailable(quic::EncryptionLevel level,std::unique_ptr<quic::QuicEncrypter> encrypter)1681 void QuicChromiumClientSession::OnNewEncryptionKeyAvailable(
1682 quic::EncryptionLevel level,
1683 std::unique_ptr<quic::QuicEncrypter> encrypter) {
1684 if (!attempted_zero_rtt_ && (level == quic::ENCRYPTION_ZERO_RTT ||
1685 level == quic::ENCRYPTION_FORWARD_SECURE)) {
1686 base::TimeTicks now = tick_clock_->NowTicks();
1687 DCHECK_LE(connect_timing_.connect_start, now);
1688 UMA_HISTOGRAM_TIMES("Net.QuicSession.EncryptionEstablishedTime",
1689 now - connect_timing_.connect_start);
1690 }
1691 if (level == quic::ENCRYPTION_ZERO_RTT) {
1692 attempted_zero_rtt_ = true;
1693 }
1694 QuicSpdySession::OnNewEncryptionKeyAvailable(level, std::move(encrypter));
1695
1696 if (!callback_.is_null() &&
1697 (!require_confirmation_ && level == quic::ENCRYPTION_ZERO_RTT)) {
1698 // Currently for all CryptoHandshakeEvent events, callback_
1699 // could be called because there are no error events in CryptoHandshakeEvent
1700 // enum. If error events are added to CryptoHandshakeEvent, then the
1701 // following code needs to changed.
1702 std::move(callback_).Run(OK);
1703 }
1704 }
1705
LogZeroRttStats()1706 void QuicChromiumClientSession::LogZeroRttStats() {
1707 DCHECK(OneRttKeysAvailable());
1708
1709 ZeroRttState state;
1710
1711 ssl_early_data_reason_t early_data_reason = crypto_stream_->EarlyDataReason();
1712 if (early_data_reason == ssl_early_data_accepted) {
1713 state = ZeroRttState::kAttemptedAndSucceeded;
1714 } else if (early_data_reason == ssl_early_data_peer_declined ||
1715 early_data_reason == ssl_early_data_session_not_resumed ||
1716 early_data_reason == ssl_early_data_hello_retry_request) {
1717 state = ZeroRttState::kAttemptedAndRejected;
1718 } else {
1719 state = ZeroRttState::kNotAttempted;
1720 }
1721 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ZeroRttState", state);
1722 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ZeroRttReason", early_data_reason,
1723 ssl_early_data_reason_max_value + 1);
1724 if (IsGoogleHost(session_key_.host())) {
1725 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ZeroRttReasonGoogle",
1726 early_data_reason,
1727 ssl_early_data_reason_max_value + 1);
1728 } else {
1729 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ZeroRttReasonNonGoogle",
1730 early_data_reason,
1731 ssl_early_data_reason_max_value + 1);
1732 }
1733 }
1734
OnCryptoHandshakeMessageSent(const quic::CryptoHandshakeMessage & message)1735 void QuicChromiumClientSession::OnCryptoHandshakeMessageSent(
1736 const quic::CryptoHandshakeMessage& message) {
1737 logger_->OnCryptoHandshakeMessageSent(message);
1738 }
1739
OnCryptoHandshakeMessageReceived(const quic::CryptoHandshakeMessage & message)1740 void QuicChromiumClientSession::OnCryptoHandshakeMessageReceived(
1741 const quic::CryptoHandshakeMessage& message) {
1742 logger_->OnCryptoHandshakeMessageReceived(message);
1743 if (message.tag() == quic::kREJ) {
1744 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.RejectLength",
1745 message.GetSerialized().length(), 1000, 10000,
1746 50);
1747 std::string_view proof;
1748 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.RejectHasProof",
1749 message.GetStringPiece(quic::kPROF, &proof));
1750 }
1751 }
1752
OnGoAway(const quic::QuicGoAwayFrame & frame)1753 void QuicChromiumClientSession::OnGoAway(const quic::QuicGoAwayFrame& frame) {
1754 quic::QuicSession::OnGoAway(frame);
1755 NotifyFactoryOfSessionGoingAway();
1756 port_migration_detected_ =
1757 frame.error_code == quic::QUIC_ERROR_MIGRATING_PORT;
1758 }
1759
OnConnectionClosed(const quic::QuicConnectionCloseFrame & frame,quic::ConnectionCloseSource source)1760 void QuicChromiumClientSession::OnConnectionClosed(
1761 const quic::QuicConnectionCloseFrame& frame,
1762 quic::ConnectionCloseSource source) {
1763 DCHECK(!connection()->connected());
1764 logger_->OnConnectionClosed(frame, source);
1765
1766 UMA_HISTOGRAM_COUNTS_1000("Net.QuicSession.NumDefaultPathDegrading",
1767 connection()->GetStats().num_path_degrading);
1768 if (connection()->GetStats().num_path_degrading > 0) {
1769 UMA_HISTOGRAM_COUNTS_1000(
1770 "Net.QuicSession.NumForwardProgressMadeAfterPathDegrading",
1771 connection()->GetStats().num_forward_progress_after_path_degrading);
1772 }
1773 if (const quic::QuicConnection::MultiPortStats* multi_port_stats =
1774 connection()->multi_port_stats()) {
1775 UMA_HISTOGRAM_COUNTS_1000("Net.QuicMultiPort.NumProbeAttempts",
1776 multi_port_stats->num_client_probing_attempts);
1777 UMA_HISTOGRAM_COUNTS_1000("Net.QuicMultiPort.NumSuccessfulProbes",
1778 multi_port_stats->num_successful_probes);
1779 UMA_HISTOGRAM_COUNTS_1000(
1780 "Net.QuicMultiPort.NumMultiPortFailureWhenPathNotDegrading",
1781 multi_port_stats
1782 ->num_multi_port_probe_failures_when_path_not_degrading);
1783 size_t total_multi_port_probe_failures =
1784 multi_port_stats
1785 ->num_multi_port_probe_failures_when_path_not_degrading +
1786 multi_port_stats->num_multi_port_probe_failures_when_path_degrading;
1787 uint64_t srtt_ms =
1788 multi_port_stats->rtt_stats.smoothed_rtt().ToMilliseconds();
1789 if (connection()->GetStats().num_path_degrading > 0 &&
1790 total_multi_port_probe_failures > 0 && srtt_ms > 0) {
1791 base::UmaHistogramSparse(
1792 "Net.QuicMultiPort.AltPortRttWhenPathDegradingVsGeneral",
1793 static_cast<int>(
1794 multi_port_stats->rtt_stats_when_default_path_degrading
1795 .smoothed_rtt()
1796 .ToMilliseconds() *
1797 100 / srtt_ms));
1798 UMA_HISTOGRAM_COUNTS_1000(
1799 "Net.QuicMultiPort.NumMultiPortFailureWhenPathDegrading",
1800 multi_port_stats->num_multi_port_probe_failures_when_path_degrading);
1801 base::UmaHistogramPercentage(
1802 "Net.QuicMultiPort.AltPortFailureWhenPathDegradingVsGeneral",
1803 static_cast<int>(
1804 multi_port_stats
1805 ->num_multi_port_probe_failures_when_path_degrading *
1806 100 / total_multi_port_probe_failures));
1807 }
1808 }
1809
1810 RecordConnectionCloseErrorCode(frame, source, session_key_.host(),
1811 OneRttKeysAvailable(),
1812 !ech_config_list_.empty());
1813 if (OneRttKeysAvailable()) {
1814 handles::NetworkHandle current_network = GetCurrentNetwork();
1815 for (auto& observer : connectivity_observer_list_) {
1816 observer.OnSessionClosedAfterHandshake(this, current_network, source,
1817 frame.quic_error_code);
1818 }
1819 }
1820
1821 const quic::QuicErrorCode error = frame.quic_error_code;
1822 const std::string& error_details = frame.error_details;
1823
1824 if (source == quic::ConnectionCloseSource::FROM_SELF &&
1825 error == quic::QUIC_NETWORK_IDLE_TIMEOUT && ShouldKeepConnectionAlive()) {
1826 quic::QuicStreamCount streams_waiting_to_write = 0;
1827 PerformActionOnActiveStreams(
1828 [&streams_waiting_to_write](quic::QuicStream* stream) {
1829 if (stream->HasBufferedData()) {
1830 ++streams_waiting_to_write;
1831 }
1832 return true;
1833 });
1834
1835 UMA_HISTOGRAM_COUNTS_100(
1836 "Net.QuicSession.NumStreamsWaitingToWriteOnIdleTimeout",
1837 streams_waiting_to_write);
1838 UMA_HISTOGRAM_COUNTS_100("Net.QuicSession.NumActiveStreamsOnIdleTimeout",
1839 GetNumActiveStreams());
1840 }
1841
1842 if (source == quic::ConnectionCloseSource::FROM_PEER) {
1843 if (error == quic::QUIC_PUBLIC_RESET) {
1844 // is_from_google_server will be true if the received EPID is
1845 // kEPIDGoogleFrontEnd or kEPIDGoogleFrontEnd0.
1846 const bool is_from_google_server =
1847 error_details.find(base::StringPrintf(
1848 "From %s", quic::kEPIDGoogleFrontEnd)) != std::string::npos;
1849
1850 if (OneRttKeysAvailable()) {
1851 UMA_HISTOGRAM_BOOLEAN(
1852 "Net.QuicSession.ClosedByPublicReset.HandshakeConfirmed",
1853 is_from_google_server);
1854 } else {
1855 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedByPublicReset",
1856 is_from_google_server);
1857 }
1858
1859 if (is_from_google_server) {
1860 UMA_HISTOGRAM_COUNTS_100(
1861 "Net.QuicSession.NumMigrationsExercisedBeforePublicReset",
1862 packet_readers_.size() - 1);
1863 }
1864
1865 base::UmaHistogramSparse(
1866 "Net.QuicSession.LastSentPacketContentBeforePublicReset",
1867 connection()
1868 ->sent_packet_manager()
1869 .unacked_packets()
1870 .GetLastPacketContent());
1871
1872 const quic::QuicTime last_in_flight_packet_sent_time =
1873 connection()
1874 ->sent_packet_manager()
1875 .unacked_packets()
1876 .GetLastInFlightPacketSentTime();
1877 const quic::QuicTime handshake_completion_time =
1878 connection()->GetStats().handshake_completion_time;
1879 if (last_in_flight_packet_sent_time.IsInitialized() &&
1880 handshake_completion_time.IsInitialized() &&
1881 last_in_flight_packet_sent_time >= handshake_completion_time) {
1882 const quic::QuicTime::Delta delay =
1883 last_in_flight_packet_sent_time - handshake_completion_time;
1884 UMA_HISTOGRAM_LONG_TIMES_100(
1885 "Net.QuicSession."
1886 "LastInFlightPacketSentTimeFromHandshakeCompletionWithPublicReset",
1887 base::Milliseconds(delay.ToMilliseconds()));
1888 }
1889
1890 UMA_HISTOGRAM_LONG_TIMES_100(
1891 "Net.QuicSession.ConnectionDurationWithPublicReset",
1892 tick_clock_->NowTicks() - connect_timing_.connect_end);
1893 }
1894 if (OneRttKeysAvailable()) {
1895 base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
1896 "Net.QuicSession.StreamCloseErrorCodeServer.HandshakeConfirmed",
1897 base::HistogramBase::kUmaTargetedHistogramFlag);
1898 size_t num_streams = GetNumActiveStreams();
1899 if (num_streams > 0) {
1900 histogram->AddCount(error, num_streams);
1901 }
1902 }
1903 } else {
1904 if (OneRttKeysAvailable()) {
1905 base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
1906 "Net.QuicSession.StreamCloseErrorCodeClient.HandshakeConfirmed",
1907 base::HistogramBase::kUmaTargetedHistogramFlag);
1908 size_t num_streams = GetNumActiveStreams();
1909 if (num_streams > 0) {
1910 histogram->AddCount(error, num_streams);
1911 }
1912 } else {
1913 if (error == quic::QUIC_HANDSHAKE_TIMEOUT) {
1914 UMA_HISTOGRAM_BOOLEAN(
1915 "Net.QuicSession.HandshakeTimeout.PathDegradingDetected",
1916 connection()->IsPathDegrading());
1917 }
1918 }
1919 if (error == quic::QUIC_TOO_MANY_RTOS) {
1920 UMA_HISTOGRAM_COUNTS_1000(
1921 "Net.QuicSession.ClosedByRtoAtClient.ReceivedPacketCount",
1922 connection()->GetStats().packets_received);
1923 UMA_HISTOGRAM_COUNTS_1000(
1924 "Net.QuicSession.ClosedByRtoAtClient.SentPacketCount",
1925 connection()->GetStats().packets_sent);
1926 UMA_HISTOGRAM_COUNTS_100(
1927 "Net.QuicSession."
1928 "MaxConsecutiveRtoWithForwardProgressAndBlackholeDetected",
1929 connection()->GetStats().max_consecutive_rto_with_forward_progress);
1930 }
1931 }
1932
1933 if (error == quic::QUIC_NETWORK_IDLE_TIMEOUT) {
1934 UMA_HISTOGRAM_COUNTS_1M(
1935 "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
1936 GetNumActiveStreams());
1937 if (OneRttKeysAvailable()) {
1938 if (GetNumActiveStreams() > 0) {
1939 UMA_HISTOGRAM_BOOLEAN(
1940 "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
1941 connection()->sent_packet_manager().HasInFlightPackets());
1942 UMA_HISTOGRAM_COUNTS_1M(
1943 "Net.QuicSession.TimedOutWithOpenStreams.ConsecutivePTOCount",
1944 connection()->sent_packet_manager().GetConsecutivePtoCount());
1945 base::UmaHistogramSparse(
1946 "Net.QuicSession.TimedOutWithOpenStreams.LocalPort",
1947 connection()->self_address().port());
1948 }
1949 } else {
1950 UMA_HISTOGRAM_COUNTS_1M(
1951 "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
1952 GetNumActiveStreams());
1953 UMA_HISTOGRAM_COUNTS_1M(
1954 "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
1955 num_total_streams_);
1956 }
1957 }
1958
1959 if (OneRttKeysAvailable()) {
1960 // QUIC connections should not timeout while there are open streams,
1961 // since PING frames are sent to prevent timeouts. If, however, the
1962 // connection timed out with open streams then QUIC traffic has become
1963 // blackholed. Alternatively, if too many retransmission timeouts occur
1964 // then QUIC traffic has become blackholed.
1965 if (session_pool_ && (error == quic::QUIC_TOO_MANY_RTOS ||
1966 (error == quic::QUIC_NETWORK_IDLE_TIMEOUT &&
1967 GetNumActiveStreams() > 0))) {
1968 session_pool_->OnBlackholeAfterHandshakeConfirmed(this);
1969 }
1970 UMA_HISTOGRAM_COUNTS_100(
1971 "Net.QuicSession.CryptoRetransmitCount.HandshakeConfirmed",
1972 connection()->GetStats().crypto_retransmit_count);
1973 UMA_HISTOGRAM_COUNTS_100(
1974 "Net.QuicSession.MaxConsecutiveRtoWithForwardProgress",
1975 connection()->GetStats().max_consecutive_rto_with_forward_progress);
1976 UMA_HISTOGRAM_COUNTS_1000("Net.QuicSession.NumPingsSent",
1977 connection()->GetStats().ping_frames_sent);
1978 UMA_HISTOGRAM_LONG_TIMES_100(
1979 "Net.QuicSession.ConnectionDuration",
1980 tick_clock_->NowTicks() - connect_timing_.connect_end);
1981 UMA_HISTOGRAM_COUNTS_100("Net.QuicSession.NumMigrations", num_migrations_);
1982
1983 // KeyUpdates are used in TLS, but we no longer support pre-TLS QUIC.
1984 DCHECK(connection()->version().UsesTls());
1985 base::UmaHistogramCounts100("Net.QuicSession.KeyUpdate.PerConnection2",
1986 connection()->GetStats().key_update_count);
1987 base::UmaHistogramCounts100(
1988 "Net.QuicSession.KeyUpdate.PotentialPeerKeyUpdateAttemptCount",
1989 connection()->PotentialPeerKeyUpdateAttemptCount());
1990 if (last_key_update_reason_ != quic::KeyUpdateReason::kInvalid) {
1991 std::string suffix =
1992 last_key_update_reason_ == quic::KeyUpdateReason::kRemote ? "Remote"
1993 : "Local";
1994 // These values are persisted to logs. Entries should not be renumbered
1995 // and numeric values should never be reused.
1996 enum class KeyUpdateSuccess {
1997 kInvalid = 0,
1998 kSuccess = 1,
1999 kFailedInitial = 2,
2000 kFailedNonInitial = 3,
2001 kMaxValue = kFailedNonInitial,
2002 };
2003 KeyUpdateSuccess value = KeyUpdateSuccess::kInvalid;
2004 if (connection()->HaveSentPacketsInCurrentKeyPhaseButNoneAcked()) {
2005 if (connection()->GetStats().key_update_count >= 2) {
2006 value = KeyUpdateSuccess::kFailedNonInitial;
2007 } else {
2008 value = KeyUpdateSuccess::kFailedInitial;
2009 }
2010 } else {
2011 value = KeyUpdateSuccess::kSuccess;
2012 }
2013 base::UmaHistogramEnumeration(
2014 "Net.QuicSession.KeyUpdate.Success." + suffix, value);
2015 }
2016 } else {
2017 if (error == quic::QUIC_PUBLIC_RESET) {
2018 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
2019 } else if (connection()->GetStats().packets_received == 0) {
2020 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
2021 base::UmaHistogramSparse(
2022 "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
2023 error);
2024 } else {
2025 RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
2026 base::UmaHistogramSparse(
2027 "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
2028 error);
2029 }
2030 UMA_HISTOGRAM_COUNTS_100(
2031 "Net.QuicSession.CryptoRetransmitCount.HandshakeNotConfirmed",
2032 connection()->GetStats().crypto_retransmit_count);
2033 }
2034
2035 base::UmaHistogramCounts1M(
2036 "Net.QuicSession.UndecryptablePacketsReceivedWithDecrypter",
2037 connection()->GetStats().num_failed_authentication_packets_received);
2038 base::UmaHistogramSparse("Net.QuicSession.QuicVersion",
2039 connection()->transport_version());
2040 NotifyFactoryOfSessionGoingAway();
2041 quic::QuicSession::OnConnectionClosed(frame, source);
2042
2043 if (!callback_.is_null()) {
2044 std::move(callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
2045 }
2046
2047 bool socket_found_in_writer = false;
2048 for (auto& packet_reader : packet_readers_) {
2049 packet_reader->CloseSocket();
2050 // If a writer exists that was not destroyed when the connection migrated,
2051 // then that writer may not be notified that its socket has been closed.
2052 // We know that the writer is a QuicChromiumPacketWriter since the packet
2053 // writer is set with the same type originally.
2054 socket_found_in_writer |=
2055 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
2056 ->OnSocketClosed(packet_reader->socket());
2057 }
2058 CHECK(socket_found_in_writer);
2059 DCHECK(!HasActiveRequestStreams());
2060 CloseAllHandles(ERR_UNEXPECTED);
2061 CancelAllRequests(ERR_CONNECTION_CLOSED);
2062 NotifyRequestsOfConfirmation(ERR_CONNECTION_CLOSED);
2063 NotifyFactoryOfSessionClosedLater();
2064 }
2065
OnSuccessfulVersionNegotiation(const quic::ParsedQuicVersion & version)2066 void QuicChromiumClientSession::OnSuccessfulVersionNegotiation(
2067 const quic::ParsedQuicVersion& version) {
2068 logger_->OnSuccessfulVersionNegotiation(version);
2069 quic::QuicSpdySession::OnSuccessfulVersionNegotiation(version);
2070 }
2071
HandleWriteError(int error_code,scoped_refptr<QuicChromiumPacketWriter::ReusableIOBuffer> packet)2072 int QuicChromiumClientSession::HandleWriteError(
2073 int error_code,
2074 scoped_refptr<QuicChromiumPacketWriter::ReusableIOBuffer> packet) {
2075 current_migration_cause_ = ON_WRITE_ERROR;
2076 LogHandshakeStatusOnMigrationSignal();
2077
2078 base::UmaHistogramSparse("Net.QuicSession.WriteError", -error_code);
2079 if (OneRttKeysAvailable()) {
2080 base::UmaHistogramSparse("Net.QuicSession.WriteError.HandshakeConfirmed",
2081 -error_code);
2082 }
2083
2084 // For now, skip reporting if there are multiple packet writers and
2085 // connection migration is enabled.
2086 if (packet_readers_.size() == 1u || !migrate_session_early_v2_) {
2087 handles::NetworkHandle current_network = GetCurrentNetwork();
2088 for (auto& observer : connectivity_observer_list_) {
2089 observer.OnSessionEncounteringWriteError(this, current_network,
2090 error_code);
2091 }
2092 }
2093
2094 if (error_code == ERR_MSG_TOO_BIG || session_pool_ == nullptr ||
2095 !migrate_session_on_network_change_v2_ || !OneRttKeysAvailable()) {
2096 return error_code;
2097 }
2098
2099 handles::NetworkHandle current_network = GetCurrentNetwork();
2100
2101 net_log_.AddEventWithInt64Params(
2102 NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_WRITE_ERROR, "network",
2103 current_network);
2104
2105 DCHECK(packet != nullptr);
2106 DCHECK_NE(ERR_IO_PENDING, error_code);
2107 DCHECK_GT(0, error_code);
2108 DCHECK(packet_ == nullptr);
2109
2110 // Post a task to migrate the session onto a new network.
2111 task_runner_->PostTask(
2112 FROM_HERE,
2113 base::BindOnce(
2114 &QuicChromiumClientSession::MigrateSessionOnWriteError,
2115 weak_factory_.GetWeakPtr(), error_code,
2116 // UnsafeDanglingUntriaged triggered by test:
2117 // QuicSessionPoolTest.MigrateSessionOnSyncWriteErrorPauseBeforeConnected
2118 // TODO(https://crbug.com/1380714): Remove `UnsafeDanglingUntriaged`
2119 base::UnsafeDanglingUntriaged(connection()->writer())));
2120
2121 ignore_read_error_ = true;
2122
2123 // Cause the packet writer to return ERR_IO_PENDING and block so
2124 // that the actual migration happens from the message loop instead
2125 // of under the call stack of quic::QuicConnection::WritePacket.
2126 return ERR_IO_PENDING;
2127 }
2128
MigrateSessionOnWriteError(int error_code,quic::QuicPacketWriter * writer)2129 void QuicChromiumClientSession::MigrateSessionOnWriteError(
2130 int error_code,
2131 quic::QuicPacketWriter* writer) {
2132 DCHECK(migrate_session_on_network_change_v2_);
2133 // If |writer| is no longer actively in use, or a session migration has
2134 // started from MigrateNetworkImmediately, abort this migration attempt.
2135 if (writer != connection()->writer() ||
2136 pending_migrate_network_immediately_) {
2137 return;
2138 }
2139
2140 most_recent_write_error_timestamp_ = tick_clock_->NowTicks();
2141 most_recent_write_error_ = error_code;
2142
2143 if (session_pool_ == nullptr) {
2144 // Close the connection if migration failed. Do not cause a
2145 // connection close packet to be sent since socket may be borked.
2146 connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR,
2147 "Write error with nulled stream factory",
2148 quic::ConnectionCloseBehavior::SILENT_CLOSE);
2149 return;
2150 }
2151
2152 current_migration_cause_ = ON_WRITE_ERROR;
2153
2154 if (migrate_idle_session_ && CheckIdleTimeExceedsIdleMigrationPeriod()) {
2155 return;
2156 }
2157
2158 if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
2159 // connection close packet to be sent since socket may be borked.
2160 connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR,
2161 "Write error for non-migratable session",
2162 quic::ConnectionCloseBehavior::SILENT_CLOSE);
2163 return;
2164 }
2165
2166 // Do not migrate if connection migration is disabled.
2167 if (config()->DisableConnectionMigration()) {
2168 HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG,
2169 connection_id(),
2170 "Migration disabled by config");
2171 // Close the connection since migration was disabled. Do not cause a
2172 // connection close packet to be sent since socket may be borked.
2173 connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR,
2174 "Write error for non-migratable session",
2175 quic::ConnectionCloseBehavior::SILENT_CLOSE);
2176 return;
2177 }
2178
2179 handles::NetworkHandle new_network =
2180 session_pool_->FindAlternateNetwork(GetCurrentNetwork());
2181 if (new_network == handles::kInvalidNetworkHandle) {
2182 // No alternate network found.
2183 HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_ALTERNATE_NETWORK,
2184 connection_id(),
2185 "No alternate network found");
2186 OnNoNewNetwork();
2187 return;
2188 }
2189
2190 if (GetCurrentNetwork() == default_network_ &&
2191 current_migrations_to_non_default_network_on_write_error_ >=
2192 max_migrations_to_non_default_network_on_write_error_) {
2193 HistogramAndLogMigrationFailure(
2194 MIGRATION_STATUS_ON_WRITE_ERROR_DISABLED, connection_id(),
2195 "Exceeds maximum number of migrations on write error");
2196 connection()->CloseConnection(
2197 quic::QUIC_PACKET_WRITE_ERROR,
2198 "Too many migrations for write error for the same network",
2199 quic::ConnectionCloseBehavior::SILENT_CLOSE);
2200 return;
2201 }
2202 current_migrations_to_non_default_network_on_write_error_++;
2203
2204 net_log_.BeginEventWithStringParams(
2205 NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED, "trigger",
2206 "WriteError");
2207 pending_migrate_session_on_write_error_ = true;
2208 Migrate(new_network, ToIPEndPoint(connection()->peer_address()),
2209 /*close_session_on_error=*/false,
2210 base::BindOnce(
2211 &QuicChromiumClientSession::FinishMigrateSessionOnWriteError,
2212 weak_factory_.GetWeakPtr(), new_network));
2213 net_log_.EndEvent(NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED);
2214 }
2215
FinishMigrateSessionOnWriteError(handles::NetworkHandle new_network,MigrationResult result)2216 void QuicChromiumClientSession::FinishMigrateSessionOnWriteError(
2217 handles::NetworkHandle new_network,
2218 MigrationResult result) {
2219 pending_migrate_session_on_write_error_ = false;
2220 if (result == MigrationResult::FAILURE) {
2221 // Close the connection if migration failed. Do not cause a
2222 // connection close packet to be sent since socket may be borked.
2223 connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR,
2224 "Write and subsequent migration failed",
2225 quic::ConnectionCloseBehavior::SILENT_CLOSE);
2226 return;
2227 }
2228 if (new_network != default_network_) {
2229 StartMigrateBackToDefaultNetworkTimer(
2230 base::Seconds(kMinRetryTimeForDefaultNetworkSecs));
2231 } else {
2232 CancelMigrateBackToDefaultNetworkTimer();
2233 }
2234 }
2235
OnNoNewNetwork()2236 void QuicChromiumClientSession::OnNoNewNetwork() {
2237 DCHECK(OneRttKeysAvailable());
2238 wait_for_new_network_ = true;
2239 net_log_.AddEvent(
2240 NetLogEventType::QUIC_CONNECTION_MIGRATION_WAITING_FOR_NEW_NETWORK);
2241
2242 DVLOG(1) << "Force blocking the packet writer";
2243 // Force blocking the packet writer to avoid any writes since there is no
2244 // alternate network available.
2245 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
2246 ->set_force_write_blocked(true);
2247
2248 if (base::FeatureList::IsEnabled(features::kDisableBlackholeOnNoNewNetwork)) {
2249 // Turn off the black hole detector since the writer is blocked.
2250 // Blackhole will be re-enabled once a packet is sent again.
2251 connection()->blackhole_detector().StopDetection(false);
2252 }
2253
2254 // Post a task to maybe close the session if the alarm fires.
2255 task_runner_->PostDelayedTask(
2256 FROM_HERE,
2257 base::BindOnce(&QuicChromiumClientSession::OnMigrationTimeout,
2258 weak_factory_.GetWeakPtr(), packet_readers_.size()),
2259 base::Seconds(kWaitTimeForNewNetworkSecs));
2260 }
2261
WriteToNewSocket()2262 void QuicChromiumClientSession::WriteToNewSocket() {
2263 // Set |send_packet_after_migration_| to true so that a packet will be
2264 // sent when the writer becomes unblocked.
2265 send_packet_after_migration_ = true;
2266
2267 DVLOG(1) << "Cancel force blocking the packet writer";
2268 // Notify writer that it is no longer forced blocked, which may call
2269 // OnWriteUnblocked() if the writer has no write in progress.
2270 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
2271 ->set_force_write_blocked(false);
2272 }
2273
OnMigrationTimeout(size_t num_sockets)2274 void QuicChromiumClientSession::OnMigrationTimeout(size_t num_sockets) {
2275 // If number of sockets has changed, this migration task is stale.
2276 if (num_sockets != packet_readers_.size()) {
2277 return;
2278 }
2279
2280 net_log_.AddEvent(
2281 NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE_WAITING_FOR_NETWORK);
2282
2283 int net_error = current_migration_cause_ == ON_NETWORK_DISCONNECTED
2284 ? ERR_INTERNET_DISCONNECTED
2285 : ERR_NETWORK_CHANGED;
2286
2287 // |current_migration_cause_| will be reset after logging.
2288 LogMigrationResultToHistogram(MIGRATION_STATUS_TIMEOUT);
2289
2290 CloseSessionOnError(net_error, quic::QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK,
2291 quic::ConnectionCloseBehavior::SILENT_CLOSE);
2292 }
2293
OnPortMigrationProbeSucceeded(handles::NetworkHandle network,const quic::QuicSocketAddress & peer_address,const quic::QuicSocketAddress & self_address,std::unique_ptr<QuicChromiumPacketWriter> writer,std::unique_ptr<QuicChromiumPacketReader> reader)2294 void QuicChromiumClientSession::OnPortMigrationProbeSucceeded(
2295 handles::NetworkHandle network,
2296 const quic::QuicSocketAddress& peer_address,
2297 const quic::QuicSocketAddress& self_address,
2298 std::unique_ptr<QuicChromiumPacketWriter> writer,
2299 std::unique_ptr<QuicChromiumPacketReader> reader) {
2300 DCHECK(writer);
2301 DCHECK(reader);
2302
2303 net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CONNECTIVITY_PROBING_FINISHED,
2304 [&] {
2305 return NetLogProbingResultParams(network, &peer_address,
2306 /*is_success=*/true);
2307 });
2308
2309 LogProbeResultToHistogram(current_migration_cause_, true);
2310
2311 // Remove |this| as the old packet writer's delegate. Write error on old
2312 // writers will be ignored.
2313 // Set |this| to listen on socket write events on the packet writer
2314 // that was used for probing.
2315 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
2316 ->set_delegate(nullptr);
2317 writer->set_delegate(this);
2318
2319 if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
2320 // If idle sessions won't be migrated, close the connection.
2321 CloseSessionOnErrorLater(
2322 ERR_NETWORK_CHANGED,
2323 quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
2324 quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
2325 return;
2326 }
2327
2328 if (migrate_idle_session_ && CheckIdleTimeExceedsIdleMigrationPeriod()) {
2329 return;
2330 }
2331
2332 // Migrate to the probed socket immediately: socket, writer and reader will
2333 // be acquired by connection and used as default on success.
2334 if (!MigrateToSocket(self_address, peer_address, std::move(reader),
2335 std::move(writer))) {
2336 LogMigrateToSocketStatus(false);
2337 net_log_.AddEvent(
2338 NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE_AFTER_PROBING);
2339 return;
2340 }
2341
2342 LogMigrateToSocketStatus(true);
2343
2344 num_migrations_++;
2345 HistogramAndLogMigrationSuccess(connection_id());
2346 }
2347
OnConnectionMigrationProbeSucceeded(handles::NetworkHandle network,const quic::QuicSocketAddress & peer_address,const quic::QuicSocketAddress & self_address,std::unique_ptr<QuicChromiumPacketWriter> writer,std::unique_ptr<QuicChromiumPacketReader> reader)2348 void QuicChromiumClientSession::OnConnectionMigrationProbeSucceeded(
2349 handles::NetworkHandle network,
2350 const quic::QuicSocketAddress& peer_address,
2351 const quic::QuicSocketAddress& self_address,
2352 std::unique_ptr<QuicChromiumPacketWriter> writer,
2353 std::unique_ptr<QuicChromiumPacketReader> reader) {
2354 DCHECK(writer);
2355 DCHECK(reader);
2356
2357 net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CONNECTIVITY_PROBING_FINISHED,
2358 [&] {
2359 return NetLogProbingResultParams(network, &peer_address,
2360 /*is_success=*/true);
2361 });
2362 if (network == handles::kInvalidNetworkHandle) {
2363 return;
2364 }
2365
2366 LogProbeResultToHistogram(current_migration_cause_, true);
2367
2368 // Remove |this| as the old packet writer's delegate. Write error on old
2369 // writers will be ignored.
2370 // Set |this| to listen on socket write events on the packet writer
2371 // that was used for probing.
2372 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
2373 ->set_delegate(nullptr);
2374 writer->set_delegate(this);
2375
2376 // Close streams that are not migratable to the probed |network|.
2377 ResetNonMigratableStreams();
2378
2379 if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
2380 // If idle sessions won't be migrated, close the connection.
2381 CloseSessionOnErrorLater(
2382 ERR_NETWORK_CHANGED,
2383 quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
2384 quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
2385 return;
2386 }
2387
2388 if (migrate_idle_session_ && CheckIdleTimeExceedsIdleMigrationPeriod()) {
2389 return;
2390 }
2391
2392 // Migrate to the probed socket immediately: socket, writer and reader will
2393 // be acquired by connection and used as default on success.
2394 if (!MigrateToSocket(self_address, peer_address, std::move(reader),
2395 std::move(writer))) {
2396 LogMigrateToSocketStatus(false);
2397 net_log_.AddEvent(
2398 NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE_AFTER_PROBING);
2399 return;
2400 }
2401
2402 LogMigrateToSocketStatus(true);
2403
2404 net_log_.AddEventWithInt64Params(
2405 NetLogEventType::QUIC_CONNECTION_MIGRATION_SUCCESS_AFTER_PROBING,
2406 "migrate_to_network", network);
2407 num_migrations_++;
2408 HistogramAndLogMigrationSuccess(connection_id());
2409 if (network == default_network_) {
2410 DVLOG(1) << "Client successfully migrated to default network: "
2411 << default_network_;
2412 CancelMigrateBackToDefaultNetworkTimer();
2413 return;
2414 }
2415
2416 DVLOG(1) << "Client successfully got off default network after "
2417 << "successful probing network: " << network << ".";
2418 current_migrations_to_non_default_network_on_path_degrading_++;
2419 if (!migrate_back_to_default_timer_.IsRunning()) {
2420 current_migration_cause_ = ON_MIGRATE_BACK_TO_DEFAULT_NETWORK;
2421 // Session gets off the |default_network|, stay on |network| for now but
2422 // try to migrate back to default network after 1 second.
2423 StartMigrateBackToDefaultNetworkTimer(
2424 base::Seconds(kMinRetryTimeForDefaultNetworkSecs));
2425 }
2426 }
2427
OnServerPreferredAddressProbeSucceeded(handles::NetworkHandle network,const quic::QuicSocketAddress & peer_address,const quic::QuicSocketAddress & self_address,std::unique_ptr<QuicChromiumPacketWriter> writer,std::unique_ptr<QuicChromiumPacketReader> reader)2428 void QuicChromiumClientSession::OnServerPreferredAddressProbeSucceeded(
2429 handles::NetworkHandle network,
2430 const quic::QuicSocketAddress& peer_address,
2431 const quic::QuicSocketAddress& self_address,
2432 std::unique_ptr<QuicChromiumPacketWriter> writer,
2433 std::unique_ptr<QuicChromiumPacketReader> reader) {
2434 net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CONNECTIVITY_PROBING_FINISHED,
2435 [&] {
2436 return NetLogProbingResultParams(network, &peer_address,
2437 /*is_success=*/true);
2438 });
2439
2440 LogProbeResultToHistogram(current_migration_cause_, true);
2441 connection()->mutable_stats().server_preferred_address_validated = true;
2442
2443 // Remove |this| as the old packet writer's delegate. Write error on old
2444 // writers will be ignored.
2445 // Set |this| to listen on socket write events on the packet writer
2446 // that was used for probing.
2447 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
2448 ->set_delegate(nullptr);
2449 writer->set_delegate(this);
2450
2451 // Migrate to the probed socket immediately: socket, writer and reader will
2452 // be acquired by connection and used as default on success.
2453 if (!MigrateToSocket(self_address, peer_address, std::move(reader),
2454 std::move(writer))) {
2455 LogMigrateToSocketStatus(false);
2456 net_log_.AddEvent(
2457 NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE_AFTER_PROBING);
2458 return;
2459 }
2460
2461 LogMigrateToSocketStatus(true);
2462
2463 num_migrations_++;
2464 HistogramAndLogMigrationSuccess(connection_id());
2465 }
2466
OnProbeFailed(handles::NetworkHandle network,const quic::QuicSocketAddress & peer_address)2467 void QuicChromiumClientSession::OnProbeFailed(
2468 handles::NetworkHandle network,
2469 const quic::QuicSocketAddress& peer_address) {
2470 net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CONNECTIVITY_PROBING_FINISHED,
2471 [&] {
2472 return NetLogProbingResultParams(network, &peer_address,
2473 /*is_success=*/false);
2474 });
2475
2476 LogProbeResultToHistogram(current_migration_cause_, false);
2477
2478 auto* context = static_cast<QuicChromiumPathValidationContext*>(
2479 connection()->GetPathValidationContext());
2480
2481 if (!context) {
2482 return;
2483 }
2484
2485 if (context->network() == network &&
2486 context->peer_address() == peer_address) {
2487 connection()->CancelPathValidation();
2488 }
2489
2490 if (network != handles::kInvalidNetworkHandle) {
2491 // Probing failure can be ignored.
2492 DVLOG(1) << "Connectivity probing failed on <network: " << network
2493 << ", peer_address: " << peer_address.ToString() << ">.";
2494 DVLOG_IF(1, network == default_network_ &&
2495 GetCurrentNetwork() != default_network_)
2496 << "Client probing failed on the default network, still using "
2497 "non-default network.";
2498 }
2499 }
2500
OnNetworkConnected(handles::NetworkHandle network)2501 void QuicChromiumClientSession::OnNetworkConnected(
2502 handles::NetworkHandle network) {
2503 if (connection()->IsPathDegrading()) {
2504 base::TimeDelta duration =
2505 tick_clock_->NowTicks() - most_recent_path_degrading_timestamp_;
2506 UMA_HISTOGRAM_CUSTOM_TIMES("Net.QuicNetworkDegradingDurationTillConnected",
2507 duration, base::Milliseconds(1),
2508 base::Minutes(10), 50);
2509 }
2510 net_log_.AddEventWithInt64Params(
2511 NetLogEventType::QUIC_SESSION_NETWORK_CONNECTED, "connected_network",
2512 network);
2513 if (!migrate_session_on_network_change_v2_) {
2514 return;
2515 }
2516
2517 // If there was no migration waiting for new network and the path is not
2518 // degrading, ignore this signal.
2519 if (!wait_for_new_network_ && !connection()->IsPathDegrading()) {
2520 return;
2521 }
2522
2523 net_log_.AddEventWithInt64Params(
2524 NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_NETWORK_CONNECTED,
2525 "connected_network", network);
2526
2527 if (connection()->IsPathDegrading()) {
2528 current_migration_cause_ = NEW_NETWORK_CONNECTED_POST_PATH_DEGRADING;
2529 }
2530
2531 if (wait_for_new_network_) {
2532 wait_for_new_network_ = false;
2533 net_log_.AddEventWithInt64Params(
2534 NetLogEventType::QUIC_CONNECTION_MIGRATION_SUCCESS_WAITING_FOR_NETWORK,
2535 "network", network);
2536 if (current_migration_cause_ == ON_WRITE_ERROR) {
2537 current_migrations_to_non_default_network_on_write_error_++;
2538 }
2539 // |wait_for_new_network_| is true, there was no working network previously.
2540 // |network| is now the only possible candidate, migrate immediately.
2541 MigrateNetworkImmediately(network);
2542 } else {
2543 // The connection is path degrading.
2544 DCHECK(connection()->IsPathDegrading());
2545 MaybeMigrateToAlternateNetworkOnPathDegrading();
2546 }
2547 }
2548
OnNetworkDisconnectedV2(handles::NetworkHandle disconnected_network)2549 void QuicChromiumClientSession::OnNetworkDisconnectedV2(
2550 handles::NetworkHandle disconnected_network) {
2551 LogMetricsOnNetworkDisconnected();
2552 net_log_.AddEventWithInt64Params(
2553 NetLogEventType::QUIC_SESSION_NETWORK_DISCONNECTED,
2554 "disconnected_network", disconnected_network);
2555 if (!migrate_session_on_network_change_v2_) {
2556 return;
2557 }
2558 net_log_.AddEventWithInt64Params(
2559 NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_NETWORK_DISCONNECTED,
2560 "disconnected_network", disconnected_network);
2561
2562 // Stop probing the disconnected network if there is one.
2563 auto* context = static_cast<QuicChromiumPathValidationContext*>(
2564 connection()->GetPathValidationContext());
2565 if (context && context->network() == disconnected_network &&
2566 context->peer_address() == peer_address()) {
2567 connection()->CancelPathValidation();
2568 }
2569
2570 if (disconnected_network == default_network_) {
2571 DVLOG(1) << "Default network: " << default_network_ << " is disconnected.";
2572 default_network_ = handles::kInvalidNetworkHandle;
2573 current_migrations_to_non_default_network_on_write_error_ = 0;
2574 }
2575
2576 // Ignore the signal if the current active network is not affected.
2577 if (GetCurrentNetwork() != disconnected_network) {
2578 DVLOG(1) << "Client's current default network is not affected by the "
2579 << "disconnected one.";
2580 return;
2581 }
2582
2583 if (base::FeatureList::IsEnabled(
2584 features::kQuicMigrationIgnoreDisconnectSignalDuringProbing) &&
2585 current_migration_cause_ == ON_NETWORK_MADE_DEFAULT) {
2586 DVLOG(1) << "Ignoring a network disconnection signal because a "
2587 "connection migration is happening on the default network.";
2588 return;
2589 }
2590
2591 current_migration_cause_ = ON_NETWORK_DISCONNECTED;
2592 LogHandshakeStatusOnMigrationSignal();
2593 if (!OneRttKeysAvailable()) {
2594 // Close the connection if handshake is not confirmed. Migration before
2595 // handshake is not allowed.
2596 CloseSessionOnErrorLater(
2597 ERR_NETWORK_CHANGED,
2598 quic::QUIC_CONNECTION_MIGRATION_HANDSHAKE_UNCONFIRMED,
2599 quic::ConnectionCloseBehavior::SILENT_CLOSE);
2600 return;
2601 }
2602
2603 // Attempt to find alternative network.
2604 handles::NetworkHandle new_network =
2605 session_pool_->FindAlternateNetwork(disconnected_network);
2606
2607 if (new_network == handles::kInvalidNetworkHandle) {
2608 OnNoNewNetwork();
2609 return;
2610 }
2611
2612 // Current network is being disconnected, migrate immediately to the
2613 // alternative network.
2614 MigrateNetworkImmediately(new_network);
2615 }
2616
OnNetworkMadeDefault(handles::NetworkHandle new_network)2617 void QuicChromiumClientSession::OnNetworkMadeDefault(
2618 handles::NetworkHandle new_network) {
2619 LogMetricsOnNetworkMadeDefault();
2620 net_log_.AddEventWithInt64Params(
2621 NetLogEventType::QUIC_SESSION_NETWORK_MADE_DEFAULT, "new_default_network",
2622 new_network);
2623
2624 if (!migrate_session_on_network_change_v2_) {
2625 return;
2626 }
2627
2628 DCHECK_NE(handles::kInvalidNetworkHandle, new_network);
2629 net_log_.AddEventWithInt64Params(
2630 NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_NETWORK_MADE_DEFAULT,
2631 "new_default_network", new_network);
2632 default_network_ = new_network;
2633
2634 DVLOG(1) << "Network: " << new_network
2635 << " becomes default, old default: " << default_network_;
2636 current_migration_cause_ = ON_NETWORK_MADE_DEFAULT;
2637 current_migrations_to_non_default_network_on_write_error_ = 0;
2638 current_migrations_to_non_default_network_on_path_degrading_ = 0;
2639
2640 // Simply cancel the timer to migrate back to the default network if session
2641 // is already on the default network.
2642 if (GetCurrentNetwork() == new_network) {
2643 CancelMigrateBackToDefaultNetworkTimer();
2644 HistogramAndLogMigrationFailure(MIGRATION_STATUS_ALREADY_MIGRATED,
2645 connection_id(),
2646 "Already migrated on the new network");
2647 return;
2648 }
2649
2650 LogHandshakeStatusOnMigrationSignal();
2651
2652 // Stay on the current network. Try to migrate back to default network
2653 // without any delay, which will start probing the new default network and
2654 // migrate to the new network immediately on success.
2655 StartMigrateBackToDefaultNetworkTimer(base::TimeDelta());
2656 }
2657
MigrateNetworkImmediately(handles::NetworkHandle network)2658 void QuicChromiumClientSession::MigrateNetworkImmediately(
2659 handles::NetworkHandle network) {
2660 // There is no choice but to migrate to |network|. If any error encountered,
2661 // close the session. When migration succeeds:
2662 // - if no longer on the default network, start timer to migrate back;
2663 // - otherwise, it's brought to default network, cancel the running timer to
2664 // migrate back.
2665
2666 DCHECK(migrate_session_on_network_change_v2_);
2667
2668 if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
2669 HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_MIGRATABLE_STREAMS,
2670 connection_id(), "No active streams");
2671 CloseSessionOnErrorLater(
2672 ERR_NETWORK_CHANGED,
2673 quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
2674 quic::ConnectionCloseBehavior::SILENT_CLOSE);
2675 return;
2676 }
2677
2678 if (migrate_idle_session_ && CheckIdleTimeExceedsIdleMigrationPeriod()) {
2679 return;
2680 }
2681
2682 // Do not migrate if connection migration is disabled.
2683 if (config()->DisableConnectionMigration()) {
2684 HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG,
2685 connection_id(),
2686 "Migration disabled by config");
2687 CloseSessionOnErrorLater(ERR_NETWORK_CHANGED,
2688 quic::QUIC_CONNECTION_MIGRATION_DISABLED_BY_CONFIG,
2689 quic::ConnectionCloseBehavior::SILENT_CLOSE);
2690 return;
2691 }
2692
2693 if (network == GetCurrentNetwork()) {
2694 HistogramAndLogMigrationFailure(MIGRATION_STATUS_ALREADY_MIGRATED,
2695 connection_id(),
2696 "Already bound to new network");
2697 return;
2698 }
2699
2700 // Cancel probing on |network| if there is any.
2701 auto* context = static_cast<QuicChromiumPathValidationContext*>(
2702 connection()->GetPathValidationContext());
2703 if (context && context->network() == network &&
2704 context->peer_address() == peer_address()) {
2705 connection()->CancelPathValidation();
2706 }
2707 pending_migrate_network_immediately_ = true;
2708 Migrate(network, ToIPEndPoint(connection()->peer_address()),
2709 /*close_session_on_error=*/true,
2710 base::BindOnce(
2711 &QuicChromiumClientSession::FinishMigrateNetworkImmediately,
2712 weak_factory_.GetWeakPtr(), network));
2713 }
2714
FinishMigrateNetworkImmediately(handles::NetworkHandle network,MigrationResult result)2715 void QuicChromiumClientSession::FinishMigrateNetworkImmediately(
2716 handles::NetworkHandle network,
2717 MigrationResult result) {
2718 pending_migrate_network_immediately_ = false;
2719 if (result == MigrationResult::FAILURE) {
2720 return;
2721 }
2722
2723 if (network == default_network_) {
2724 CancelMigrateBackToDefaultNetworkTimer();
2725 return;
2726 }
2727
2728 // TODO(zhongyi): reconsider this, maybe we just want to hear back
2729 // We are forced to migrate to |network|, probably |default_network_| is
2730 // not working, start to migrate back to default network after 1 secs.
2731 StartMigrateBackToDefaultNetworkTimer(
2732 base::Seconds(kMinRetryTimeForDefaultNetworkSecs));
2733 }
2734
OnWriteError(int error_code)2735 void QuicChromiumClientSession::OnWriteError(int error_code) {
2736 DCHECK_NE(ERR_IO_PENDING, error_code);
2737 DCHECK_GT(0, error_code);
2738 connection()->OnWriteError(error_code);
2739 }
2740
OnWriteUnblocked()2741 void QuicChromiumClientSession::OnWriteUnblocked() {
2742 DCHECK(!connection()->writer()->IsWriteBlocked());
2743
2744 // A new packet will be written after migration completes, unignore read
2745 // errors.
2746 if (ignore_read_error_) {
2747 ignore_read_error_ = false;
2748 }
2749
2750 if (packet_) {
2751 DCHECK(send_packet_after_migration_);
2752 send_packet_after_migration_ = false;
2753 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
2754 ->WritePacketToSocket(std::move(packet_));
2755 return;
2756 }
2757
2758 // Unblock the connection, which may send queued packets.
2759 connection()->OnCanWrite();
2760 if (send_packet_after_migration_) {
2761 send_packet_after_migration_ = false;
2762 if (!connection()->writer()->IsWriteBlocked()) {
2763 connection()->SendPing();
2764 }
2765 }
2766 }
2767
OnPathDegrading()2768 void QuicChromiumClientSession::OnPathDegrading() {
2769 if (most_recent_path_degrading_timestamp_ == base::TimeTicks()) {
2770 most_recent_path_degrading_timestamp_ = tick_clock_->NowTicks();
2771 }
2772
2773 handles::NetworkHandle current_network = GetCurrentNetwork();
2774 for (auto& observer : connectivity_observer_list_) {
2775 observer.OnSessionPathDegrading(this, current_network);
2776 }
2777
2778 if (!session_pool_ || connection()->multi_port_stats()) {
2779 return;
2780 }
2781
2782 if (allow_port_migration_ && !migrate_session_early_v2_) {
2783 MaybeMigrateToDifferentPortOnPathDegrading();
2784 return;
2785 }
2786
2787 MaybeMigrateToAlternateNetworkOnPathDegrading();
2788 }
2789
OnForwardProgressMadeAfterPathDegrading()2790 void QuicChromiumClientSession::OnForwardProgressMadeAfterPathDegrading() {
2791 handles::NetworkHandle current_network = GetCurrentNetwork();
2792 for (auto& observer : connectivity_observer_list_) {
2793 observer.OnSessionResumedPostPathDegrading(this, current_network);
2794 }
2795 }
2796
OnKeyUpdate(quic::KeyUpdateReason reason)2797 void QuicChromiumClientSession::OnKeyUpdate(quic::KeyUpdateReason reason) {
2798 net_log_.AddEventWithStringParams(NetLogEventType::QUIC_SESSION_KEY_UPDATE,
2799 "reason",
2800 quic::KeyUpdateReasonString(reason));
2801
2802 base::UmaHistogramEnumeration("Net.QuicSession.KeyUpdate.Reason", reason);
2803
2804 last_key_update_reason_ = reason;
2805 }
2806
OnProofValid(const quic::QuicCryptoClientConfig::CachedState & cached)2807 void QuicChromiumClientSession::OnProofValid(
2808 const quic::QuicCryptoClientConfig::CachedState& cached) {
2809 DCHECK(cached.proof_valid());
2810
2811 if (!server_info_) {
2812 return;
2813 }
2814
2815 QuicServerInfo::State* state = server_info_->mutable_state();
2816
2817 state->server_config = cached.server_config();
2818 state->source_address_token = cached.source_address_token();
2819 state->cert_sct = cached.cert_sct();
2820 state->chlo_hash = cached.chlo_hash();
2821 state->server_config_sig = cached.signature();
2822 state->certs = cached.certs();
2823
2824 server_info_->Persist();
2825 }
2826
OnProofVerifyDetailsAvailable(const quic::ProofVerifyDetails & verify_details)2827 void QuicChromiumClientSession::OnProofVerifyDetailsAvailable(
2828 const quic::ProofVerifyDetails& verify_details) {
2829 const ProofVerifyDetailsChromium* verify_details_chromium =
2830 reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
2831 cert_verify_result_ = std::make_unique<CertVerifyResult>(
2832 verify_details_chromium->cert_verify_result);
2833 logger_->OnCertificateVerified(*cert_verify_result_);
2834 pkp_bypassed_ = verify_details_chromium->pkp_bypassed;
2835 is_fatal_cert_error_ = verify_details_chromium->is_fatal_cert_error;
2836 }
2837
StartReading()2838 void QuicChromiumClientSession::StartReading() {
2839 for (auto& packet_reader : packet_readers_) {
2840 packet_reader->StartReading();
2841 }
2842 }
2843
CloseSessionOnError(int net_error,quic::QuicErrorCode quic_error,quic::ConnectionCloseBehavior behavior)2844 void QuicChromiumClientSession::CloseSessionOnError(
2845 int net_error,
2846 quic::QuicErrorCode quic_error,
2847 quic::ConnectionCloseBehavior behavior) {
2848 base::UmaHistogramSparse("Net.QuicSession.CloseSessionOnError", -net_error);
2849
2850 if (!callback_.is_null()) {
2851 std::move(callback_).Run(net_error);
2852 }
2853
2854 NotifyAllStreamsOfError(net_error);
2855
2856 net_log_.AddEventWithIntParams(NetLogEventType::QUIC_SESSION_CLOSE_ON_ERROR,
2857 "net_error", net_error);
2858
2859 if (connection()->connected()) {
2860 connection()->CloseConnection(quic_error, "net error", behavior);
2861 }
2862 DCHECK(!connection()->connected());
2863
2864 CloseAllHandles(net_error);
2865 NotifyFactoryOfSessionClosed();
2866 }
2867
CloseSessionOnErrorLater(int net_error,quic::QuicErrorCode quic_error,quic::ConnectionCloseBehavior behavior)2868 void QuicChromiumClientSession::CloseSessionOnErrorLater(
2869 int net_error,
2870 quic::QuicErrorCode quic_error,
2871 quic::ConnectionCloseBehavior behavior) {
2872 base::UmaHistogramSparse("Net.QuicSession.CloseSessionOnError", -net_error);
2873
2874 if (!callback_.is_null()) {
2875 std::move(callback_).Run(net_error);
2876 }
2877 NotifyAllStreamsOfError(net_error);
2878 net_log_.AddEventWithIntParams(NetLogEventType::QUIC_SESSION_CLOSE_ON_ERROR,
2879 "net_error", net_error);
2880
2881 if (connection()->connected()) {
2882 connection()->CloseConnection(quic_error, "net error", behavior);
2883 }
2884 DCHECK(!connection()->connected());
2885
2886 CloseAllHandles(net_error);
2887 NotifyFactoryOfSessionClosedLater();
2888 }
2889
NotifyAllStreamsOfError(int net_error)2890 void QuicChromiumClientSession::NotifyAllStreamsOfError(int net_error) {
2891 PerformActionOnActiveStreams([net_error](quic::QuicStream* stream) {
2892 static_cast<QuicChromiumClientStream*>(stream)->OnError(net_error);
2893 return true;
2894 });
2895 }
2896
CloseAllHandles(int net_error)2897 void QuicChromiumClientSession::CloseAllHandles(int net_error) {
2898 while (!handles_.empty()) {
2899 Handle* handle = *handles_.begin();
2900 handles_.erase(handle);
2901 handle->OnSessionClosed(connection()->version(), net_error, error(),
2902 port_migration_detected_,
2903 quic_connection_migration_attempted_,
2904 quic_connection_migration_successful_,
2905 GetConnectTiming(), WasConnectionEverUsed());
2906 }
2907 }
2908
CancelAllRequests(int net_error)2909 void QuicChromiumClientSession::CancelAllRequests(int net_error) {
2910 UMA_HISTOGRAM_COUNTS_1000("Net.QuicSession.AbortedPendingStreamRequests",
2911 stream_requests_.size());
2912
2913 while (!stream_requests_.empty()) {
2914 StreamRequest* request = stream_requests_.front();
2915 stream_requests_.pop_front();
2916 request->OnRequestCompleteFailure(net_error);
2917 }
2918 }
2919
NotifyRequestsOfConfirmation(int net_error)2920 void QuicChromiumClientSession::NotifyRequestsOfConfirmation(int net_error) {
2921 // Post tasks to avoid reentrancy.
2922 for (auto& callback : waiting_for_confirmation_callbacks_) {
2923 task_runner_->PostTask(FROM_HERE,
2924 base::BindOnce(std::move(callback), net_error));
2925 }
2926
2927 waiting_for_confirmation_callbacks_.clear();
2928 }
2929
MaybeMigrateToDifferentPortOnPathDegrading()2930 void QuicChromiumClientSession::MaybeMigrateToDifferentPortOnPathDegrading() {
2931 DCHECK(allow_port_migration_ && !migrate_session_early_v2_);
2932
2933 current_migration_cause_ = CHANGE_PORT_ON_PATH_DEGRADING;
2934
2935 // Migration before handshake confirmed is not allowed.
2936 if (!connection()->IsHandshakeConfirmed()) {
2937 HistogramAndLogMigrationFailure(
2938 MIGRATION_STATUS_PATH_DEGRADING_BEFORE_HANDSHAKE_CONFIRMED,
2939 connection_id(), "Path degrading before handshake confirmed");
2940 return;
2941 }
2942
2943 if (config()->DisableConnectionMigration()) {
2944 HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG,
2945 connection_id(),
2946 "Migration disabled by config");
2947 return;
2948 }
2949
2950 net_log_.BeginEvent(NetLogEventType::QUIC_PORT_MIGRATION_TRIGGERED);
2951
2952 if (!session_pool_) {
2953 return;
2954 }
2955
2956 // Probe a different port, session will migrate to the probed port on success.
2957 // DoNothingAs is passed in for `probing_callback` as the return value of
2958 // StartProbing is not needed.
2959 StartProbing(base::DoNothingAs<void(ProbingResult)>(), default_network_,
2960 peer_address());
2961 net_log_.EndEvent(NetLogEventType::QUIC_PORT_MIGRATION_TRIGGERED);
2962 }
2963
2964 void QuicChromiumClientSession::
MaybeMigrateToAlternateNetworkOnPathDegrading()2965 MaybeMigrateToAlternateNetworkOnPathDegrading() {
2966 net_log_.AddEvent(
2967 NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_PATH_DEGRADING);
2968
2969 current_migration_cause_ = CHANGE_NETWORK_ON_PATH_DEGRADING;
2970
2971 if (!migrate_session_early_v2_) {
2972 HistogramAndLogMigrationFailure(MIGRATION_STATUS_PATH_DEGRADING_NOT_ENABLED,
2973 connection_id(),
2974 "Migration on path degrading not enabled");
2975 return;
2976 }
2977
2978 if (GetCurrentNetwork() == default_network_ &&
2979 current_migrations_to_non_default_network_on_path_degrading_ >=
2980 max_migrations_to_non_default_network_on_path_degrading_) {
2981 HistogramAndLogMigrationFailure(
2982 MIGRATION_STATUS_ON_PATH_DEGRADING_DISABLED, connection_id(),
2983 "Exceeds maximum number of migrations on path degrading");
2984 return;
2985 }
2986
2987 handles::NetworkHandle alternate_network =
2988 session_pool_->FindAlternateNetwork(GetCurrentNetwork());
2989 if (alternate_network == handles::kInvalidNetworkHandle) {
2990 HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_ALTERNATE_NETWORK,
2991 connection_id(),
2992 "No alternative network on path degrading");
2993 return;
2994 }
2995
2996 LogHandshakeStatusOnMigrationSignal();
2997
2998 if (!connection()->IsHandshakeConfirmed()) {
2999 HistogramAndLogMigrationFailure(
3000 MIGRATION_STATUS_PATH_DEGRADING_BEFORE_HANDSHAKE_CONFIRMED,
3001 connection_id(), "Path degrading before handshake confirmed");
3002 return;
3003 }
3004
3005 net_log_.BeginEventWithStringParams(
3006 NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED, "trigger",
3007 "PathDegrading");
3008 // Probe the alternative network, session will migrate to the probed
3009 // network and decide whether it wants to migrate back to the default
3010 // network on success. DoNothingAs is passed in for `probing_callback` as the
3011 // return value of MaybeStartProbing is not needed.
3012 MaybeStartProbing(base::DoNothingAs<void(ProbingResult)>(), alternate_network,
3013 peer_address());
3014 net_log_.EndEvent(NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED);
3015 }
3016
MaybeStartProbing(ProbingCallback probing_callback,handles::NetworkHandle network,const quic::QuicSocketAddress & peer_address)3017 void QuicChromiumClientSession::MaybeStartProbing(
3018 ProbingCallback probing_callback,
3019 handles::NetworkHandle network,
3020 const quic::QuicSocketAddress& peer_address) {
3021 if (!session_pool_) {
3022 task_runner_->PostTask(
3023 FROM_HERE, base::BindOnce(std::move(probing_callback),
3024 ProbingResult::DISABLED_WITH_IDLE_SESSION));
3025 return;
3026 }
3027
3028 CHECK_NE(handles::kInvalidNetworkHandle, network);
3029
3030 if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
3031 HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_MIGRATABLE_STREAMS,
3032 connection_id(), "No active streams");
3033 CloseSessionOnErrorLater(
3034 ERR_NETWORK_CHANGED,
3035 quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
3036 quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
3037 task_runner_->PostTask(
3038 FROM_HERE, base::BindOnce(std::move(probing_callback),
3039 ProbingResult::DISABLED_WITH_IDLE_SESSION));
3040 return;
3041 }
3042
3043 if (migrate_idle_session_ && CheckIdleTimeExceedsIdleMigrationPeriod()) {
3044 task_runner_->PostTask(
3045 FROM_HERE, base::BindOnce(std::move(probing_callback),
3046 ProbingResult::DISABLED_WITH_IDLE_SESSION));
3047 return;
3048 }
3049
3050 if (config()->DisableConnectionMigration()) {
3051 DVLOG(1) << "Client disables probing network with connection migration "
3052 << "disabled by config";
3053 HistogramAndLogMigrationFailure(MIGRATION_STATUS_DISABLED_BY_CONFIG,
3054 connection_id(),
3055 "Migration disabled by config");
3056 task_runner_->PostTask(FROM_HERE,
3057 base::BindOnce(std::move(probing_callback),
3058 ProbingResult::DISABLED_BY_CONFIG));
3059 return;
3060 }
3061
3062 StartProbing(std::move(probing_callback), network, peer_address);
3063 }
3064
CreateContextForMultiPortPath(std::unique_ptr<quic::MultiPortPathContextObserver> context_observer)3065 void QuicChromiumClientSession::CreateContextForMultiPortPath(
3066 std::unique_ptr<quic::MultiPortPathContextObserver> context_observer) {
3067 // Create and configure socket on default network
3068 std::unique_ptr<DatagramClientSocket> probing_socket =
3069 session_pool_->CreateSocket(net_log_.net_log(), net_log_.source());
3070 if (base::FeatureList::IsEnabled(net::features::kAsyncMultiPortPath)) {
3071 DatagramClientSocket* probing_socket_ptr = probing_socket.get();
3072 CompletionOnceCallback configure_callback = base::BindOnce(
3073 &QuicChromiumClientSession::FinishCreateContextForMultiPortPath,
3074 weak_factory_.GetWeakPtr(), std::move(context_observer),
3075 std::move(probing_socket));
3076 session_pool_->ConnectAndConfigureSocket(
3077 std::move(configure_callback), probing_socket_ptr,
3078 ToIPEndPoint(peer_address()), default_network_,
3079 session_key_.socket_tag());
3080 return;
3081 }
3082
3083 if (session_pool_->ConfigureSocket(
3084 probing_socket.get(), ToIPEndPoint(peer_address()), default_network_,
3085 session_key_.socket_tag()) != OK) {
3086 return;
3087 }
3088
3089 FinishCreateContextForMultiPortPath(std::move(context_observer),
3090 std::move(probing_socket), OK);
3091 }
3092
FinishCreateContextForMultiPortPath(std::unique_ptr<quic::MultiPortPathContextObserver> context_observer,std::unique_ptr<DatagramClientSocket> probing_socket,int rv)3093 void QuicChromiumClientSession::FinishCreateContextForMultiPortPath(
3094 std::unique_ptr<quic::MultiPortPathContextObserver> context_observer,
3095 std::unique_ptr<DatagramClientSocket> probing_socket,
3096 int rv) {
3097 if (rv != OK) {
3098 context_observer->OnMultiPortPathContextAvailable(nullptr);
3099 return;
3100 }
3101 // Create new packet writer and reader on the probing socket.
3102 auto probing_writer = std::make_unique<QuicChromiumPacketWriter>(
3103 probing_socket.get(), task_runner_);
3104 auto probing_reader = std::make_unique<QuicChromiumPacketReader>(
3105 std::move(probing_socket), clock_, this, yield_after_packets_,
3106 yield_after_duration_, net_log_);
3107
3108 probing_reader->StartReading();
3109 path_validation_writer_delegate_.set_network(default_network_);
3110 path_validation_writer_delegate_.set_peer_address(peer_address());
3111 probing_writer->set_delegate(&path_validation_writer_delegate_);
3112 IPEndPoint local_address;
3113 probing_reader->socket()->GetLocalAddress(&local_address);
3114 context_observer->OnMultiPortPathContextAvailable(
3115 std::make_unique<QuicChromiumPathValidationContext>(
3116 ToQuicSocketAddress(local_address), peer_address(), default_network_,
3117 std::move(probing_writer), std::move(probing_reader)));
3118 }
3119
MigrateToMultiPortPath(std::unique_ptr<quic::QuicPathValidationContext> context)3120 void QuicChromiumClientSession::MigrateToMultiPortPath(
3121 std::unique_ptr<quic::QuicPathValidationContext> context) {
3122 DCHECK_NE(nullptr, context);
3123 auto* chrome_context =
3124 static_cast<QuicChromiumPathValidationContext*>(context.get());
3125 std::unique_ptr<QuicChromiumPacketWriter> owned_writer =
3126 chrome_context->ReleaseWriter();
3127 // Remove |this| as the old packet writer's delegate. Write error on old
3128 // writers will be ignored.
3129 // Set |this| to listen on socket write events on the packet writer
3130 // that was used for probing.
3131 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
3132 ->set_delegate(nullptr);
3133 owned_writer->set_delegate(this);
3134
3135 if (!MigrateToSocket(
3136 chrome_context->self_address(), chrome_context->peer_address(),
3137 chrome_context->ReleaseReader(), std::move(owned_writer))) {
3138 LogMigrateToSocketStatus(false);
3139 return;
3140 }
3141 LogMigrateToSocketStatus(true);
3142 num_migrations_++;
3143 }
3144
StartProbing(ProbingCallback probing_callback,handles::NetworkHandle network,const quic::QuicSocketAddress & peer_address)3145 void QuicChromiumClientSession::StartProbing(
3146 ProbingCallback probing_callback,
3147 handles::NetworkHandle network,
3148 const quic::QuicSocketAddress& peer_address) {
3149 // Check if probing manager is probing the same path.
3150 auto* existing_context = static_cast<QuicChromiumPathValidationContext*>(
3151 connection()->GetPathValidationContext());
3152 if (existing_context && existing_context->network() == network &&
3153 existing_context->peer_address() == peer_address) {
3154 task_runner_->PostTask(FROM_HERE,
3155 base::BindOnce(std::move(probing_callback),
3156 ProbingResult::DISABLED_BY_CONFIG));
3157 return;
3158 }
3159
3160 // Create and configure socket on |network|.
3161 std::unique_ptr<DatagramClientSocket> probing_socket =
3162 session_pool_->CreateSocket(net_log_.net_log(), net_log_.source());
3163 DatagramClientSocket* probing_socket_ptr = probing_socket.get();
3164 CompletionOnceCallback configure_callback =
3165 base::BindOnce(&QuicChromiumClientSession::FinishStartProbing,
3166 weak_factory_.GetWeakPtr(), std::move(probing_callback),
3167 std::move(probing_socket), network, peer_address);
3168
3169 if (current_migration_cause_ != UNKNOWN_CAUSE &&
3170 !MidMigrationCallbackForTesting().is_null()) {
3171 std::move(MidMigrationCallbackForTesting()).Run(); // IN-TEST
3172 }
3173
3174 session_pool_->ConnectAndConfigureSocket(
3175 std::move(configure_callback), probing_socket_ptr,
3176 ToIPEndPoint(peer_address), network, session_key_.socket_tag());
3177
3178 return;
3179 }
3180
FinishStartProbing(ProbingCallback probing_callback,std::unique_ptr<DatagramClientSocket> probing_socket,handles::NetworkHandle network,const quic::QuicSocketAddress & peer_address,int rv)3181 void QuicChromiumClientSession::FinishStartProbing(
3182 ProbingCallback probing_callback,
3183 std::unique_ptr<DatagramClientSocket> probing_socket,
3184 handles::NetworkHandle network,
3185 const quic::QuicSocketAddress& peer_address,
3186 int rv) {
3187 if (rv != OK) {
3188 HistogramAndLogMigrationFailure(MIGRATION_STATUS_INTERNAL_ERROR,
3189 connection_id(),
3190 "Socket configuration failed");
3191 task_runner_->PostTask(FROM_HERE,
3192 base::BindOnce(std::move(probing_callback),
3193 ProbingResult::INTERNAL_ERROR));
3194
3195 return;
3196 }
3197 // Create new packet writer and reader on the probing socket.
3198 auto probing_writer = std::make_unique<QuicChromiumPacketWriter>(
3199 probing_socket.get(), task_runner_);
3200 auto probing_reader = std::make_unique<QuicChromiumPacketReader>(
3201 std::move(probing_socket), clock_, this, yield_after_packets_,
3202 yield_after_duration_, net_log_);
3203
3204 probing_reader->StartReading();
3205 path_validation_writer_delegate_.set_network(network);
3206 path_validation_writer_delegate_.set_peer_address(peer_address);
3207 probing_writer->set_delegate(&path_validation_writer_delegate_);
3208 IPEndPoint local_address;
3209 probing_reader->socket()->GetLocalAddress(&local_address);
3210 auto context = std::make_unique<QuicChromiumPathValidationContext>(
3211 ToQuicSocketAddress(local_address), peer_address, network,
3212 std::move(probing_writer), std::move(probing_reader));
3213 switch (current_migration_cause_) {
3214 case CHANGE_PORT_ON_PATH_DEGRADING:
3215 ValidatePath(
3216 std::move(context),
3217 std::make_unique<PortMigrationValidationResultDelegate>(this),
3218 quic::PathValidationReason::kPortMigration);
3219 break;
3220 case ON_SERVER_PREFERRED_ADDRESS_AVAILABLE:
3221 ValidatePath(
3222 std::move(context),
3223 std::make_unique<ServerPreferredAddressValidationResultDelegate>(
3224 this),
3225 quic::PathValidationReason::kServerPreferredAddressMigration);
3226 break;
3227 default:
3228 ValidatePath(
3229 std::move(context),
3230 std::make_unique<ConnectionMigrationValidationResultDelegate>(this),
3231 quic::PathValidationReason::kConnectionMigration);
3232 break;
3233 }
3234
3235 task_runner_->PostTask(FROM_HERE, base::BindOnce(std::move(probing_callback),
3236 ProbingResult::PENDING));
3237 }
3238
StartMigrateBackToDefaultNetworkTimer(base::TimeDelta delay)3239 void QuicChromiumClientSession::StartMigrateBackToDefaultNetworkTimer(
3240 base::TimeDelta delay) {
3241 if (current_migration_cause_ != ON_NETWORK_MADE_DEFAULT) {
3242 current_migration_cause_ = ON_MIGRATE_BACK_TO_DEFAULT_NETWORK;
3243 }
3244
3245 CancelMigrateBackToDefaultNetworkTimer();
3246 // Post a task to try migrate back to default network after |delay|.
3247 migrate_back_to_default_timer_.Start(
3248 FROM_HERE, delay,
3249 base::BindOnce(
3250 &QuicChromiumClientSession::MaybeRetryMigrateBackToDefaultNetwork,
3251 weak_factory_.GetWeakPtr()));
3252 }
3253
CancelMigrateBackToDefaultNetworkTimer()3254 void QuicChromiumClientSession::CancelMigrateBackToDefaultNetworkTimer() {
3255 retry_migrate_back_count_ = 0;
3256 migrate_back_to_default_timer_.Stop();
3257 }
3258
TryMigrateBackToDefaultNetwork(base::TimeDelta timeout)3259 void QuicChromiumClientSession::TryMigrateBackToDefaultNetwork(
3260 base::TimeDelta timeout) {
3261 if (default_network_ == handles::kInvalidNetworkHandle) {
3262 DVLOG(1) << "Default network is not connected";
3263 return;
3264 }
3265
3266 net_log_.AddEventWithInt64Params(
3267 NetLogEventType::QUIC_CONNECTION_MIGRATION_ON_MIGRATE_BACK, "retry_count",
3268 retry_migrate_back_count_);
3269 // Start probe default network immediately, if manager is probing
3270 // the same network, this will be a no-op. Otherwise, previous probe
3271 // will be cancelled and manager starts to probe |default_network_|
3272 // immediately.
3273 MaybeStartProbing(
3274 base::BindOnce(
3275 &QuicChromiumClientSession::FinishTryMigrateBackToDefaultNetwork,
3276 weak_factory_.GetWeakPtr(), timeout),
3277 default_network_, peer_address());
3278 }
3279
FinishTryMigrateBackToDefaultNetwork(base::TimeDelta timeout,ProbingResult result)3280 void QuicChromiumClientSession::FinishTryMigrateBackToDefaultNetwork(
3281 base::TimeDelta timeout,
3282 ProbingResult result) {
3283 if (result != ProbingResult::PENDING) {
3284 // Session is not allowed to migrate, mark session as going away, cancel
3285 // migrate back to default timer.
3286 NotifyFactoryOfSessionGoingAway();
3287 CancelMigrateBackToDefaultNetworkTimer();
3288 return;
3289 }
3290
3291 retry_migrate_back_count_++;
3292 migrate_back_to_default_timer_.Start(
3293 FROM_HERE, timeout,
3294 base::BindOnce(
3295 &QuicChromiumClientSession::MaybeRetryMigrateBackToDefaultNetwork,
3296 weak_factory_.GetWeakPtr()));
3297 }
3298
MaybeRetryMigrateBackToDefaultNetwork()3299 void QuicChromiumClientSession::MaybeRetryMigrateBackToDefaultNetwork() {
3300 base::TimeDelta retry_migrate_back_timeout =
3301 base::Seconds(UINT64_C(1) << retry_migrate_back_count_);
3302 if (pending_migrate_session_on_write_error_) {
3303 StartMigrateBackToDefaultNetworkTimer(base::TimeDelta());
3304 return;
3305 }
3306 if (default_network_ == GetCurrentNetwork()) {
3307 // If session has been back on the default already by other direct
3308 // migration attempt, cancel migrate back now.
3309 CancelMigrateBackToDefaultNetworkTimer();
3310 return;
3311 }
3312 if (retry_migrate_back_timeout > max_time_on_non_default_network_) {
3313 // Mark session as going away to accept no more streams.
3314 NotifyFactoryOfSessionGoingAway();
3315 return;
3316 }
3317 TryMigrateBackToDefaultNetwork(retry_migrate_back_timeout);
3318 }
3319
CheckIdleTimeExceedsIdleMigrationPeriod()3320 bool QuicChromiumClientSession::CheckIdleTimeExceedsIdleMigrationPeriod() {
3321 if (!migrate_idle_session_) {
3322 return false;
3323 }
3324
3325 if (HasActiveRequestStreams()) {
3326 return false;
3327 }
3328
3329 // There are no active/drainning streams, check the last stream's finish time.
3330 if (tick_clock_->NowTicks() - most_recent_stream_close_time_ <
3331 idle_migration_period_) {
3332 // Still within the idle migration period.
3333 return false;
3334 }
3335
3336 HistogramAndLogMigrationFailure(MIGRATION_STATUS_IDLE_MIGRATION_TIMEOUT,
3337 connection_id(),
3338 "Ilde migration period exceeded");
3339 CloseSessionOnErrorLater(ERR_NETWORK_CHANGED, quic::QUIC_NETWORK_IDLE_TIMEOUT,
3340 quic::ConnectionCloseBehavior::SILENT_CLOSE);
3341 return true;
3342 }
3343
ResetNonMigratableStreams()3344 void QuicChromiumClientSession::ResetNonMigratableStreams() {
3345 // TODO(zhongyi): may close non-migratable draining streams as well to avoid
3346 // sending additional data on alternate networks.
3347 PerformActionOnActiveStreams([](quic::QuicStream* stream) {
3348 QuicChromiumClientStream* chrome_stream =
3349 static_cast<QuicChromiumClientStream*>(stream);
3350 if (!chrome_stream->can_migrate_to_cellular_network()) {
3351 // Close the stream in both direction by resetting the stream.
3352 // TODO(zhongyi): use a different error code to reset streams for
3353 // connection migration.
3354 chrome_stream->Reset(quic::QUIC_STREAM_CANCELLED);
3355 }
3356 return true;
3357 });
3358 }
3359
LogMetricsOnNetworkDisconnected()3360 void QuicChromiumClientSession::LogMetricsOnNetworkDisconnected() {
3361 if (most_recent_path_degrading_timestamp_ != base::TimeTicks()) {
3362 most_recent_network_disconnected_timestamp_ = tick_clock_->NowTicks();
3363 base::TimeDelta degrading_duration =
3364 most_recent_network_disconnected_timestamp_ -
3365 most_recent_path_degrading_timestamp_;
3366 UMA_HISTOGRAM_CUSTOM_TIMES(
3367 "Net.QuicNetworkDegradingDurationTillDisconnected", degrading_duration,
3368 base::Milliseconds(1), base::Minutes(10), 100);
3369 }
3370 if (most_recent_write_error_timestamp_ != base::TimeTicks()) {
3371 base::TimeDelta write_error_to_disconnection_gap =
3372 most_recent_network_disconnected_timestamp_ -
3373 most_recent_write_error_timestamp_;
3374 UMA_HISTOGRAM_CUSTOM_TIMES(
3375 "Net.QuicNetworkGapBetweenWriteErrorAndDisconnection",
3376 write_error_to_disconnection_gap, base::Milliseconds(1),
3377 base::Minutes(10), 100);
3378 base::UmaHistogramSparse("Net.QuicSession.WriteError.NetworkDisconnected",
3379 -most_recent_write_error_);
3380 most_recent_write_error_ = 0;
3381 most_recent_write_error_timestamp_ = base::TimeTicks();
3382 }
3383 }
3384
LogMetricsOnNetworkMadeDefault()3385 void QuicChromiumClientSession::LogMetricsOnNetworkMadeDefault() {
3386 if (most_recent_path_degrading_timestamp_ != base::TimeTicks()) {
3387 if (most_recent_network_disconnected_timestamp_ != base::TimeTicks()) {
3388 // NetworkDiscconected happens before NetworkMadeDefault, the platform
3389 // is dropping WiFi.
3390 base::TimeTicks now = tick_clock_->NowTicks();
3391 base::TimeDelta disconnection_duration =
3392 now - most_recent_network_disconnected_timestamp_;
3393 base::TimeDelta degrading_duration =
3394 now - most_recent_path_degrading_timestamp_;
3395 UMA_HISTOGRAM_CUSTOM_TIMES("Net.QuicNetworkDisconnectionDuration",
3396 disconnection_duration, base::Milliseconds(1),
3397 base::Minutes(10), 100);
3398 UMA_HISTOGRAM_CUSTOM_TIMES(
3399 "Net.QuicNetworkDegradingDurationTillNewNetworkMadeDefault",
3400 degrading_duration, base::Milliseconds(1), base::Minutes(10), 100);
3401 most_recent_network_disconnected_timestamp_ = base::TimeTicks();
3402 }
3403 most_recent_path_degrading_timestamp_ = base::TimeTicks();
3404 }
3405 }
3406
LogMigrationResultToHistogram(QuicConnectionMigrationStatus status)3407 void QuicChromiumClientSession::LogMigrationResultToHistogram(
3408 QuicConnectionMigrationStatus status) {
3409 if (current_migration_cause_ == CHANGE_PORT_ON_PATH_DEGRADING) {
3410 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.PortMigration", status,
3411 MIGRATION_STATUS_MAX);
3412 current_migration_cause_ = UNKNOWN_CAUSE;
3413 return;
3414 }
3415
3416 if (current_migration_cause_ == ON_SERVER_PREFERRED_ADDRESS_AVAILABLE) {
3417 UMA_HISTOGRAM_ENUMERATION(
3418 "Net.QuicSession.OnServerPreferredAddressAvailable", status,
3419 MIGRATION_STATUS_MAX);
3420 current_migration_cause_ = UNKNOWN_CAUSE;
3421 return;
3422 }
3423
3424 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionMigration", status,
3425 MIGRATION_STATUS_MAX);
3426
3427 // Log the connection migraiton result to different histograms based on the
3428 // cause of the connection migration.
3429 std::string histogram_name = "Net.QuicSession.ConnectionMigration." +
3430 MigrationCauseToString(current_migration_cause_);
3431 base::UmaHistogramEnumeration(histogram_name, status, MIGRATION_STATUS_MAX);
3432 current_migration_cause_ = UNKNOWN_CAUSE;
3433 }
3434
LogHandshakeStatusOnMigrationSignal() const3435 void QuicChromiumClientSession::LogHandshakeStatusOnMigrationSignal() const {
3436 if (current_migration_cause_ == CHANGE_PORT_ON_PATH_DEGRADING) {
3437 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.HandshakeStatusOnPortMigration",
3438 OneRttKeysAvailable());
3439 return;
3440 }
3441
3442 if (current_migration_cause_ == ON_SERVER_PREFERRED_ADDRESS_AVAILABLE) {
3443 UMA_HISTOGRAM_BOOLEAN(
3444 "Net.QuicSession.HandshakeStatusOnMigratingToServerPreferredAddress",
3445 OneRttKeysAvailable());
3446 return;
3447 }
3448
3449 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.HandshakeStatusOnConnectionMigration",
3450 OneRttKeysAvailable());
3451
3452 const std::string histogram_name =
3453 "Net.QuicSession.HandshakeStatusOnConnectionMigration." +
3454 MigrationCauseToString(current_migration_cause_);
3455 STATIC_HISTOGRAM_POINTER_GROUP(
3456 histogram_name, current_migration_cause_, MIGRATION_CAUSE_MAX,
3457 AddBoolean(OneRttKeysAvailable()),
3458 base::BooleanHistogram::FactoryGet(
3459 histogram_name, base::HistogramBase::kUmaTargetedHistogramFlag));
3460 }
3461
HistogramAndLogMigrationFailure(QuicConnectionMigrationStatus status,quic::QuicConnectionId connection_id,const char * reason)3462 void QuicChromiumClientSession::HistogramAndLogMigrationFailure(
3463 QuicConnectionMigrationStatus status,
3464 quic::QuicConnectionId connection_id,
3465 const char* reason) {
3466 NetLogEventType event_type =
3467 NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE;
3468 if (current_migration_cause_ == CHANGE_PORT_ON_PATH_DEGRADING) {
3469 event_type = NetLogEventType::QUIC_PORT_MIGRATION_FAILURE;
3470 } else if (current_migration_cause_ ==
3471 ON_SERVER_PREFERRED_ADDRESS_AVAILABLE) {
3472 event_type =
3473 NetLogEventType::QUIC_FAILED_TO_VALIDATE_SERVER_PREFERRED_ADDRESS;
3474 }
3475
3476 net_log_.AddEvent(event_type, [&] {
3477 return NetLogQuicMigrationFailureParams(connection_id, reason);
3478 });
3479
3480 // |current_migration_cause_| will be reset afterwards.
3481 LogMigrationResultToHistogram(status);
3482 }
3483
HistogramAndLogMigrationSuccess(quic::QuicConnectionId connection_id)3484 void QuicChromiumClientSession::HistogramAndLogMigrationSuccess(
3485 quic::QuicConnectionId connection_id) {
3486 NetLogEventType event_type =
3487 NetLogEventType::QUIC_CONNECTION_MIGRATION_SUCCESS;
3488 if (current_migration_cause_ == CHANGE_PORT_ON_PATH_DEGRADING) {
3489 event_type = NetLogEventType::QUIC_PORT_MIGRATION_SUCCESS;
3490 } else if (current_migration_cause_ ==
3491 ON_SERVER_PREFERRED_ADDRESS_AVAILABLE) {
3492 event_type =
3493 NetLogEventType::QUIC_SUCCESSFULLY_MIGRATED_TO_SERVER_PREFERRED_ADDRESS;
3494 }
3495
3496 net_log_.AddEvent(event_type, [&] {
3497 return NetLogQuicMigrationSuccessParams(connection_id);
3498 });
3499
3500 // |current_migration_cause_| will be reset afterwards.
3501 LogMigrationResultToHistogram(MIGRATION_STATUS_SUCCESS);
3502 }
3503
GetInfoAsValue(const std::set<HostPortPair> & aliases)3504 base::Value::Dict QuicChromiumClientSession::GetInfoAsValue(
3505 const std::set<HostPortPair>& aliases) {
3506 base::Value::Dict dict;
3507 dict.Set("version", ParsedQuicVersionToString(connection()->version()));
3508 dict.Set("open_streams", static_cast<int>(GetNumActiveStreams()));
3509
3510 base::Value::List stream_list;
3511 auto* stream_list_ptr = &stream_list;
3512
3513 PerformActionOnActiveStreams([stream_list_ptr](quic::QuicStream* stream) {
3514 stream_list_ptr->Append(base::NumberToString(stream->id()));
3515 return true;
3516 });
3517
3518 dict.Set("active_streams", std::move(stream_list));
3519
3520 dict.Set("total_streams", static_cast<int>(num_total_streams_));
3521 dict.Set("peer_address", peer_address().ToString());
3522 dict.Set("network_anonymization_key",
3523 session_key_.network_anonymization_key().ToDebugString());
3524 dict.Set("connection_id", connection_id().ToString());
3525 if (!connection()->client_connection_id().IsEmpty()) {
3526 dict.Set("client_connection_id",
3527 connection()->client_connection_id().ToString());
3528 }
3529 dict.Set("connected", connection()->connected());
3530 const quic::QuicConnectionStats& stats = connection()->GetStats();
3531 dict.Set("packets_sent", static_cast<int>(stats.packets_sent));
3532 dict.Set("packets_received", static_cast<int>(stats.packets_received));
3533 dict.Set("packets_lost", static_cast<int>(stats.packets_lost));
3534 SSLInfo ssl_info;
3535
3536 base::Value::List alias_list;
3537 for (const auto& alias : aliases) {
3538 alias_list.Append(alias.ToString());
3539 }
3540 dict.Set("aliases", std::move(alias_list));
3541
3542 return dict;
3543 }
3544
gquic_zero_rtt_disabled() const3545 bool QuicChromiumClientSession::gquic_zero_rtt_disabled() const {
3546 if (!session_pool_) {
3547 return false;
3548 }
3549 return session_pool_->gquic_zero_rtt_disabled();
3550 }
3551
3552 std::unique_ptr<QuicChromiumClientSession::Handle>
CreateHandle(url::SchemeHostPort destination)3553 QuicChromiumClientSession::CreateHandle(url::SchemeHostPort destination) {
3554 return std::make_unique<QuicChromiumClientSession::Handle>(
3555 weak_factory_.GetWeakPtr(), std::move(destination));
3556 }
3557
OnReadError(int result,const DatagramClientSocket * socket)3558 bool QuicChromiumClientSession::OnReadError(
3559 int result,
3560 const DatagramClientSocket* socket) {
3561 DCHECK(socket != nullptr);
3562 base::UmaHistogramSparse("Net.QuicSession.ReadError.AnyNetwork", -result);
3563 if (socket != GetDefaultSocket()) {
3564 DVLOG(1) << "Ignoring read error " << ErrorToString(result)
3565 << " on old socket";
3566 base::UmaHistogramSparse("Net.QuicSession.ReadError.OtherNetworks",
3567 -result);
3568 // Ignore read errors from sockets that are not affecting the current
3569 // network, i.e., sockets that are no longer active and probing socket.
3570 // TODO(jri): Maybe clean up old sockets on error.
3571 return false;
3572 }
3573
3574 if (ignore_read_error_) {
3575 DVLOG(1) << "Ignoring read error " << ErrorToString(result)
3576 << " during pending migration";
3577 // Ignore read errors during pending migration. Connection will be closed if
3578 // pending migration failed or timed out.
3579 base::UmaHistogramSparse("Net.QuicSession.ReadError.PendingMigration",
3580 -result);
3581 return false;
3582 }
3583
3584 base::UmaHistogramSparse("Net.QuicSession.ReadError.CurrentNetwork", -result);
3585 if (OneRttKeysAvailable()) {
3586 base::UmaHistogramSparse(
3587 "Net.QuicSession.ReadError.CurrentNetwork.HandshakeConfirmed", -result);
3588 }
3589
3590 DVLOG(1) << "Closing session on read error " << ErrorToString(result);
3591 connection()->CloseConnection(quic::QUIC_PACKET_READ_ERROR,
3592 ErrorToString(result),
3593 quic::ConnectionCloseBehavior::SILENT_CLOSE);
3594 return false;
3595 }
3596
OnPacket(const quic::QuicReceivedPacket & packet,const quic::QuicSocketAddress & local_address,const quic::QuicSocketAddress & peer_address)3597 bool QuicChromiumClientSession::OnPacket(
3598 const quic::QuicReceivedPacket& packet,
3599 const quic::QuicSocketAddress& local_address,
3600 const quic::QuicSocketAddress& peer_address) {
3601 ProcessUdpPacket(local_address, peer_address, packet);
3602 uint8_t new_incoming_ecn =
3603 (0x1 << static_cast<uint8_t>(packet.ecn_codepoint()));
3604 if (new_incoming_ecn != observed_incoming_ecn_ &&
3605 incoming_packets_before_ecn_transition_ > 0) {
3606 observed_ecn_transition_ = true;
3607 }
3608 if (!observed_ecn_transition_) {
3609 ++incoming_packets_before_ecn_transition_;
3610 }
3611 observed_incoming_ecn_ |= new_incoming_ecn;
3612 if (!connection()->connected()) {
3613 NotifyFactoryOfSessionClosedLater();
3614 return false;
3615 }
3616 return true;
3617 }
3618
NotifyFactoryOfSessionGoingAway()3619 void QuicChromiumClientSession::NotifyFactoryOfSessionGoingAway() {
3620 going_away_ = true;
3621 if (session_pool_) {
3622 session_pool_->OnSessionGoingAway(this);
3623 }
3624 }
3625
NotifyFactoryOfSessionClosedLater()3626 void QuicChromiumClientSession::NotifyFactoryOfSessionClosedLater() {
3627 going_away_ = true;
3628 DCHECK_EQ(0u, GetNumActiveStreams());
3629 DCHECK(!connection()->connected());
3630 task_runner_->PostTask(
3631 FROM_HERE,
3632 base::BindOnce(&QuicChromiumClientSession::NotifyFactoryOfSessionClosed,
3633 weak_factory_.GetWeakPtr()));
3634 }
3635
NotifyFactoryOfSessionClosed()3636 void QuicChromiumClientSession::NotifyFactoryOfSessionClosed() {
3637 going_away_ = true;
3638 DCHECK_EQ(0u, GetNumActiveStreams());
3639 // Will delete |this|.
3640 if (session_pool_) {
3641 session_pool_->OnSessionClosed(this);
3642 }
3643 }
3644
OnCryptoHandshakeComplete()3645 void QuicChromiumClientSession::OnCryptoHandshakeComplete() {
3646 if (session_pool_) {
3647 session_pool_->set_is_quic_known_to_work_on_current_network(true);
3648 }
3649
3650 // Update |connect_end| only when handshake is confirmed. This should also
3651 // take care of any failed 0-RTT request.
3652 connect_timing_.connect_end = tick_clock_->NowTicks();
3653 DCHECK_LE(connect_timing_.connect_start, connect_timing_.connect_end);
3654 base::TimeDelta handshake_confirmed_time =
3655 connect_timing_.connect_end - connect_timing_.connect_start;
3656 UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime",
3657 handshake_confirmed_time);
3658
3659 // Also record the handshake time when ECH was advertised in DNS. The ECH
3660 // experiment does not change DNS behavior, so this measures the same servers
3661 // in both experiment and control groups.
3662 if (!ech_config_list_.empty()) {
3663 UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime.ECH",
3664 handshake_confirmed_time);
3665 }
3666
3667 // Track how long it has taken to finish handshake after we have finished
3668 // DNS host resolution.
3669 if (!connect_timing_.domain_lookup_end.is_null()) {
3670 UMA_HISTOGRAM_TIMES(
3671 "Net.QuicSession.HostResolution.HandshakeConfirmedTime",
3672 tick_clock_->NowTicks() - connect_timing_.domain_lookup_end);
3673 }
3674
3675 auto it = handles_.begin();
3676 while (it != handles_.end()) {
3677 Handle* handle = *it;
3678 ++it;
3679 handle->OnCryptoHandshakeConfirmed();
3680 }
3681
3682 NotifyRequestsOfConfirmation(OK);
3683 // Attempt to migrate back to the default network after handshake has been
3684 // confirmed if the session is not created on the default network.
3685 if (migrate_session_on_network_change_v2_ &&
3686 default_network_ != handles::kInvalidNetworkHandle &&
3687 GetCurrentNetwork() != default_network_) {
3688 current_migration_cause_ = ON_MIGRATE_BACK_TO_DEFAULT_NETWORK;
3689 StartMigrateBackToDefaultNetworkTimer(
3690 base::Seconds(kMinRetryTimeForDefaultNetworkSecs));
3691 }
3692 }
3693
Migrate(handles::NetworkHandle network,IPEndPoint peer_address,bool close_session_on_error,MigrationCallback migration_callback)3694 void QuicChromiumClientSession::Migrate(handles::NetworkHandle network,
3695 IPEndPoint peer_address,
3696 bool close_session_on_error,
3697 MigrationCallback migration_callback) {
3698 quic_connection_migration_attempted_ = true;
3699 quic_connection_migration_successful_ = false;
3700 if (!session_pool_) {
3701 task_runner_->PostTask(
3702 FROM_HERE,
3703 base::BindOnce(&QuicChromiumClientSession::DoMigrationCallback,
3704 weak_factory_.GetWeakPtr(),
3705 std::move(migration_callback),
3706 MigrationResult::FAILURE));
3707 return;
3708 }
3709
3710 if (network != handles::kInvalidNetworkHandle) {
3711 // This is a migration attempt from connection migration.
3712 ResetNonMigratableStreams();
3713 if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
3714 task_runner_->PostTask(
3715 FROM_HERE,
3716 base::BindOnce(&QuicChromiumClientSession::DoMigrationCallback,
3717 weak_factory_.GetWeakPtr(),
3718 std::move(migration_callback),
3719 MigrationResult::FAILURE));
3720 // If idle sessions can not be migrated, close the session if needed.
3721 if (close_session_on_error) {
3722 CloseSessionOnErrorLater(
3723 ERR_NETWORK_CHANGED,
3724 quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
3725 quic::ConnectionCloseBehavior::SILENT_CLOSE);
3726 }
3727 return;
3728 }
3729 }
3730
3731 // Create and configure socket on |network|.
3732 std::unique_ptr<DatagramClientSocket> socket(
3733 session_pool_->CreateSocket(net_log_.net_log(), net_log_.source()));
3734 DatagramClientSocket* socket_ptr = socket.get();
3735 DVLOG(1) << "Force blocking the packet writer";
3736 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
3737 ->set_force_write_blocked(true);
3738 if (base::FeatureList::IsEnabled(features::kDisableBlackholeOnNoNewNetwork)) {
3739 // Turn off the black hole detector since the writer is blocked.
3740 // Blackhole will be re-enabled once a packet is sent again.
3741 connection()->blackhole_detector().StopDetection(false);
3742 }
3743 CompletionOnceCallback connect_callback = base::BindOnce(
3744 &QuicChromiumClientSession::FinishMigrate, weak_factory_.GetWeakPtr(),
3745 std::move(socket), peer_address, close_session_on_error,
3746 std::move(migration_callback));
3747
3748 if (!MidMigrationCallbackForTesting().is_null()) {
3749 std::move(MidMigrationCallbackForTesting()).Run(); // IN-TEST
3750 }
3751
3752 session_pool_->ConnectAndConfigureSocket(std::move(connect_callback),
3753 socket_ptr, peer_address, network,
3754 session_key_.socket_tag());
3755 }
3756
FinishMigrate(std::unique_ptr<DatagramClientSocket> socket,IPEndPoint peer_address,bool close_session_on_error,MigrationCallback callback,int rv)3757 void QuicChromiumClientSession::FinishMigrate(
3758 std::unique_ptr<DatagramClientSocket> socket,
3759 IPEndPoint peer_address,
3760 bool close_session_on_error,
3761 MigrationCallback callback,
3762 int rv) {
3763 if (rv != OK) {
3764 HistogramAndLogMigrationFailure(MIGRATION_STATUS_INTERNAL_ERROR,
3765 connection_id(),
3766 "Socket configuration failed");
3767 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
3768 ->set_force_write_blocked(false);
3769 task_runner_->PostTask(
3770 FROM_HERE,
3771 base::BindOnce(&QuicChromiumClientSession::DoMigrationCallback,
3772 weak_factory_.GetWeakPtr(), std::move(callback),
3773 MigrationResult::FAILURE));
3774 if (close_session_on_error) {
3775 CloseSessionOnErrorLater(ERR_NETWORK_CHANGED,
3776 quic::QUIC_CONNECTION_MIGRATION_INTERNAL_ERROR,
3777 quic::ConnectionCloseBehavior::SILENT_CLOSE);
3778 }
3779 return;
3780 }
3781
3782 // Create new packet reader and writer on the new socket.
3783 auto new_reader = std::make_unique<QuicChromiumPacketReader>(
3784 std::move(socket), clock_, this, yield_after_packets_,
3785 yield_after_duration_, net_log_);
3786 new_reader->StartReading();
3787 auto new_writer = std::make_unique<QuicChromiumPacketWriter>(
3788 new_reader->socket(), task_runner_);
3789
3790 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
3791 ->set_delegate(nullptr);
3792 new_writer->set_delegate(this);
3793
3794 IPEndPoint self_address;
3795 new_reader->socket()->GetLocalAddress(&self_address);
3796 // Migrate to the new socket.
3797 if (!MigrateToSocket(ToQuicSocketAddress(self_address),
3798 ToQuicSocketAddress(peer_address), std::move(new_reader),
3799 std::move(new_writer))) {
3800 task_runner_->PostTask(
3801 FROM_HERE,
3802 base::BindOnce(&QuicChromiumClientSession::DoMigrationCallback,
3803 weak_factory_.GetWeakPtr(), std::move(callback),
3804 MigrationResult::FAILURE));
3805 if (close_session_on_error) {
3806 CloseSessionOnErrorLater(ERR_NETWORK_CHANGED,
3807 quic::QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES,
3808 quic::ConnectionCloseBehavior::SILENT_CLOSE);
3809 }
3810 return;
3811 }
3812 quic_connection_migration_successful_ = true;
3813 HistogramAndLogMigrationSuccess(connection_id());
3814 task_runner_->PostTask(
3815 FROM_HERE, base::BindOnce(&QuicChromiumClientSession::DoMigrationCallback,
3816 weak_factory_.GetWeakPtr(), std::move(callback),
3817 MigrationResult::SUCCESS));
3818 }
3819
DoMigrationCallback(MigrationCallback callback,MigrationResult rv)3820 void QuicChromiumClientSession::DoMigrationCallback(MigrationCallback callback,
3821 MigrationResult rv) {
3822 std::move(callback).Run(rv);
3823 }
3824
MigrateToSocket(const quic::QuicSocketAddress & self_address,const quic::QuicSocketAddress & peer_address,std::unique_ptr<QuicChromiumPacketReader> reader,std::unique_ptr<QuicChromiumPacketWriter> writer)3825 bool QuicChromiumClientSession::MigrateToSocket(
3826 const quic::QuicSocketAddress& self_address,
3827 const quic::QuicSocketAddress& peer_address,
3828 std::unique_ptr<QuicChromiumPacketReader> reader,
3829 std::unique_ptr<QuicChromiumPacketWriter> writer) {
3830 // TODO(zhongyi): figure out whether we want to limit the number of
3831 // connection migrations for v2, which includes migration on platform signals,
3832 // write error events, and path degrading on original network.
3833 if (!migrate_session_on_network_change_v2_ &&
3834 packet_readers_.size() >= kMaxReadersPerQuicSession) {
3835 HistogramAndLogMigrationFailure(MIGRATION_STATUS_TOO_MANY_CHANGES,
3836 connection_id(), "Too many changes");
3837 return false;
3838 }
3839
3840 packet_readers_.push_back(std::move(reader));
3841 // Force the writer to be blocked to prevent it being used until
3842 // WriteToNewSocket completes.
3843 DVLOG(1) << "Force blocking the packet writer";
3844 writer->set_force_write_blocked(true);
3845 if (!MigratePath(self_address, peer_address, writer.release(),
3846 /*owns_writer=*/true)) {
3847 HistogramAndLogMigrationFailure(MIGRATION_STATUS_NO_UNUSED_CONNECTION_ID,
3848 connection_id(),
3849 "No unused server connection ID");
3850 DVLOG(1) << "MigratePath fails as there is no CID available";
3851 return false;
3852 }
3853 // Post task to write the pending packet or a PING packet to the new
3854 // socket. This avoids reentrancy issues if there is a write error
3855 // on the write to the new socket.
3856 task_runner_->PostTask(
3857 FROM_HERE, base::BindOnce(&QuicChromiumClientSession::WriteToNewSocket,
3858 weak_factory_.GetWeakPtr()));
3859 return true;
3860 }
3861
PopulateNetErrorDetails(NetErrorDetails * details) const3862 void QuicChromiumClientSession::PopulateNetErrorDetails(
3863 NetErrorDetails* details) const {
3864 details->quic_port_migration_detected = port_migration_detected_;
3865 details->quic_connection_error = error();
3866 details->quic_connection_migration_attempted =
3867 quic_connection_migration_attempted_;
3868 details->quic_connection_migration_successful =
3869 quic_connection_migration_successful_;
3870 }
3871
GetDefaultSocket() const3872 const DatagramClientSocket* QuicChromiumClientSession::GetDefaultSocket()
3873 const {
3874 DCHECK(packet_readers_.back()->socket() != nullptr);
3875 // The most recently added socket is the currently active one.
3876 return packet_readers_.back()->socket();
3877 }
3878
GetCurrentNetwork() const3879 handles::NetworkHandle QuicChromiumClientSession::GetCurrentNetwork() const {
3880 // If connection migration is enabled, alternate network interface may be
3881 // used to send packet, it is identified as the bound network of the default
3882 // socket. Otherwise, always use |default_network_|.
3883 return migrate_session_on_network_change_v2_
3884 ? GetDefaultSocket()->GetBoundNetwork()
3885 : default_network_;
3886 }
3887
OnServerPreferredAddressAvailable(const quic::QuicSocketAddress & server_preferred_address)3888 void QuicChromiumClientSession::OnServerPreferredAddressAvailable(
3889 const quic::QuicSocketAddress& server_preferred_address) {
3890 current_migration_cause_ = ON_SERVER_PREFERRED_ADDRESS_AVAILABLE;
3891
3892 net_log_.BeginEvent(
3893 NetLogEventType::QUIC_ON_SERVER_PREFERRED_ADDRESS_AVAILABLE);
3894
3895 if (!session_pool_) {
3896 return;
3897 }
3898
3899 StartProbing(base::DoNothingAs<void(ProbingResult)>(), default_network_,
3900 server_preferred_address);
3901 net_log_.EndEvent(
3902 NetLogEventType::QUIC_START_VALIDATING_SERVER_PREFERRED_ADDRESS);
3903 }
3904
3905 const LoadTimingInfo::ConnectTiming&
GetConnectTiming()3906 QuicChromiumClientSession::GetConnectTiming() {
3907 connect_timing_.ssl_start = connect_timing_.connect_start;
3908 connect_timing_.ssl_end = connect_timing_.connect_end;
3909 return connect_timing_;
3910 }
3911
GetQuicVersion() const3912 quic::ParsedQuicVersion QuicChromiumClientSession::GetQuicVersion() const {
3913 return connection()->version();
3914 }
3915
3916 const std::set<std::string>&
GetDnsAliasesForSessionKey(const QuicSessionKey & key) const3917 QuicChromiumClientSession::GetDnsAliasesForSessionKey(
3918 const QuicSessionKey& key) const {
3919 static const base::NoDestructor<std::set<std::string>> emptyset_result;
3920 return session_pool_ ? session_pool_->GetDnsAliasesForSessionKey(key)
3921 : *emptyset_result;
3922 }
3923
3924 quic::QuicPacketLength
GetGuaranteedLargestMessagePayload() const3925 QuicChromiumClientSession::Handle::GetGuaranteedLargestMessagePayload() const {
3926 if (!session_) {
3927 return 0;
3928 }
3929 return session_->GetGuaranteedLargestMessagePayload();
3930 }
3931
3932 #if BUILDFLAG(ENABLE_WEBSOCKETS)
3933 std::unique_ptr<WebSocketQuicStreamAdapter>
CreateWebSocketQuicStreamAdapterImpl(WebSocketQuicStreamAdapter::Delegate * delegate)3934 QuicChromiumClientSession::CreateWebSocketQuicStreamAdapterImpl(
3935 WebSocketQuicStreamAdapter::Delegate* delegate) {
3936 DCHECK(connection()->connected());
3937 DCHECK(CanOpenNextOutgoingBidirectionalStream());
3938 auto websocket_quic_spdy_stream = std::make_unique<WebSocketQuicSpdyStream>(
3939 GetNextOutgoingBidirectionalStreamId(), this, quic::BIDIRECTIONAL);
3940
3941 auto adapter = std::make_unique<WebSocketQuicStreamAdapter>(
3942 websocket_quic_spdy_stream.get(), delegate);
3943 ActivateStream(std::move(websocket_quic_spdy_stream));
3944
3945 ++num_total_streams_;
3946 return adapter;
3947 }
3948
3949 std::unique_ptr<WebSocketQuicStreamAdapter>
CreateWebSocketQuicStreamAdapter(WebSocketQuicStreamAdapter::Delegate * delegate,base::OnceCallback<void (std::unique_ptr<WebSocketQuicStreamAdapter>)> callback,StreamRequest * stream_request)3950 QuicChromiumClientSession::CreateWebSocketQuicStreamAdapter(
3951 WebSocketQuicStreamAdapter::Delegate* delegate,
3952 base::OnceCallback<void(std::unique_ptr<WebSocketQuicStreamAdapter>)>
3953 callback,
3954 StreamRequest* stream_request) {
3955 DCHECK(connection()->connected());
3956 if (!CanOpenNextOutgoingBidirectionalStream()) {
3957 stream_request->pending_start_time_ = tick_clock_->NowTicks();
3958 stream_request->for_websockets_ = true;
3959 stream_request->websocket_adapter_delegate_ = delegate;
3960 stream_request->start_websocket_callback_ = std::move(callback);
3961
3962 stream_requests_.push_back(stream_request);
3963 UMA_HISTOGRAM_COUNTS_1000("Net.QuicSession.NumPendingStreamRequests",
3964 stream_requests_.size());
3965 return nullptr;
3966 }
3967
3968 return CreateWebSocketQuicStreamAdapterImpl(delegate);
3969 }
3970 #endif // BUILDFLAG(ENABLE_WEBSOCKETS)
3971
3972 } // namespace net
3973