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