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