123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- // Copyright (c) 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "net/quic/quic_connectivity_monitor.h"
- #include "base/metrics/histogram_functions.h"
- #include "base/metrics/histogram_macros.h"
- namespace net {
- namespace {
- bool IsErrorRelatedToConnectivity(int error_code) {
- return (error_code == ERR_ADDRESS_UNREACHABLE ||
- error_code == ERR_ACCESS_DENIED ||
- error_code == ERR_INTERNET_DISCONNECTED);
- }
- } // namespace
- QuicConnectivityMonitor::QuicConnectivityMonitor(
- handles::NetworkHandle default_network)
- : default_network_(default_network) {}
- QuicConnectivityMonitor::~QuicConnectivityMonitor() = default;
- void QuicConnectivityMonitor::RecordConnectivityStatsToHistograms(
- const std::string& notification,
- handles::NetworkHandle affected_network) const {
- if (notification == "OnNetworkSoonToDisconnect" ||
- notification == "OnNetworkDisconnected") {
- // If the disconnected network is not the default network, ignore
- // stats collections.
- if (affected_network != default_network_)
- return;
- }
- base::ClampedNumeric<int> num_degrading_sessions = GetNumDegradingSessions();
- if (num_sessions_active_during_current_speculative_connectivity_failure_) {
- UMA_HISTOGRAM_COUNTS_100(
- "Net.QuicConnectivityMonitor.NumSessionsTrackedSinceSpeculativeError",
- num_sessions_active_during_current_speculative_connectivity_failure_
- .value());
- }
- UMA_HISTOGRAM_COUNTS_100(
- "Net.QuicConnectivityMonitor.NumActiveQuicSessionsAtNetworkChange",
- active_sessions_.size());
- int percentage = 0;
- if (num_sessions_active_during_current_speculative_connectivity_failure_ &&
- num_sessions_active_during_current_speculative_connectivity_failure_
- .value() > 0) {
- percentage = base::saturated_cast<int>(
- num_all_degraded_sessions_ * 100.0 /
- num_sessions_active_during_current_speculative_connectivity_failure_
- .value());
- }
- UMA_HISTOGRAM_COUNTS_100(
- "Net.QuicConnectivityMonitor.NumAllSessionsDegradedAtNetworkChange",
- num_all_degraded_sessions_);
- const std::string raw_histogram_name1 =
- "Net.QuicConnectivityMonitor.NumAllDegradedSessions." + notification;
- base::UmaHistogramCustomCounts(raw_histogram_name1,
- num_all_degraded_sessions_, 1, 100, 50);
- const std::string percentage_histogram_name1 =
- "Net.QuicConnectivityMonitor.PercentageAllDegradedSessions." +
- notification;
- base::UmaHistogramPercentageObsoleteDoNotUse(percentage_histogram_name1,
- percentage);
- // Skip degrading session collection if there are less than two sessions.
- if (active_sessions_.size() < 2u)
- return;
- const std::string raw_histogram_name =
- "Net.QuicConnectivityMonitor.NumActiveDegradingSessions." + notification;
- base::UmaHistogramCustomCounts(raw_histogram_name, num_degrading_sessions, 1,
- 100, 50);
- percentage = base::saturated_cast<double>(num_degrading_sessions * 100.0 /
- active_sessions_.size());
- const std::string percentage_histogram_name =
- "Net.QuicConnectivityMonitor.PercentageActiveDegradingSessions." +
- notification;
- base::UmaHistogramPercentageObsoleteDoNotUse(percentage_histogram_name,
- percentage);
- }
- size_t QuicConnectivityMonitor::GetNumDegradingSessions() const {
- return degrading_sessions_.size();
- }
- size_t QuicConnectivityMonitor::GetCountForWriteErrorCode(
- int write_error_code) const {
- auto it = write_error_map_.find(write_error_code);
- return it == write_error_map_.end() ? 0u : it->second;
- }
- void QuicConnectivityMonitor::SetInitialDefaultNetwork(
- handles::NetworkHandle default_network) {
- default_network_ = default_network;
- }
- void QuicConnectivityMonitor::OnSessionPathDegrading(
- QuicChromiumClientSession* session,
- handles::NetworkHandle network) {
- if (network != default_network_)
- return;
- degrading_sessions_.insert(session);
- num_all_degraded_sessions_++;
- // If the degrading session used to be on the previous default network, it is
- // possible that the session is no longer tracked in |active_sessions_| due
- // to the recent default network change.
- active_sessions_.insert(session);
- if (!num_sessions_active_during_current_speculative_connectivity_failure_) {
- num_sessions_active_during_current_speculative_connectivity_failure_ =
- active_sessions_.size();
- } else {
- // Before seeing session degrading, PACKET_WRITE_ERROR has been observed.
- UMA_HISTOGRAM_COUNTS_100(
- "Net.QuicConnectivityMonitor.NumWriteErrorsSeenBeforeDegradation",
- quic_error_map_[quic::QUIC_PACKET_WRITE_ERROR]);
- }
- }
- void QuicConnectivityMonitor::OnSessionResumedPostPathDegrading(
- QuicChromiumClientSession* session,
- handles::NetworkHandle network) {
- if (network != default_network_)
- return;
- degrading_sessions_.erase(session);
- // If the resumed session used to be on the previous default network, it is
- // possible that the session is no longer tracked in |active_sessions_| due
- // to the recent default network change.
- active_sessions_.insert(session);
- num_all_degraded_sessions_ = 0u;
- num_sessions_active_during_current_speculative_connectivity_failure_ =
- absl::nullopt;
- }
- void QuicConnectivityMonitor::OnSessionEncounteringWriteError(
- QuicChromiumClientSession* session,
- handles::NetworkHandle network,
- int error_code) {
- if (network != default_network_)
- return;
- // If the session used to be on the previous default network, it is
- // possible that the session is no longer tracked in |active_sessions_| due
- // to the recent default network change.
- active_sessions_.insert(session);
- ++write_error_map_[error_code];
- bool is_session_degraded =
- degrading_sessions_.find(session) != degrading_sessions_.end();
- UMA_HISTOGRAM_BOOLEAN(
- "Net.QuicConnectivityMonitor.SessionDegradedBeforeWriteError",
- is_session_degraded);
- if (!num_sessions_active_during_current_speculative_connectivity_failure_ &&
- IsErrorRelatedToConnectivity(error_code)) {
- num_sessions_active_during_current_speculative_connectivity_failure_ =
- active_sessions_.size();
- }
- }
- void QuicConnectivityMonitor::OnSessionClosedAfterHandshake(
- QuicChromiumClientSession* session,
- handles::NetworkHandle network,
- quic::ConnectionCloseSource source,
- quic::QuicErrorCode error_code) {
- if (network != default_network_)
- return;
- if (source == quic::ConnectionCloseSource::FROM_PEER) {
- // Connection closed by the peer post handshake with PUBLIC RESET
- // is most likely a NAT rebinding issue.
- if (error_code == quic::QUIC_PUBLIC_RESET)
- quic_error_map_[error_code]++;
- return;
- }
- if (error_code == quic::QUIC_PACKET_WRITE_ERROR ||
- error_code == quic::QUIC_TOO_MANY_RTOS) {
- // Connection close by self with PACKET_WRITE_ERROR or TOO_MANY_RTOS
- // is likely a connectivity issue.
- quic_error_map_[error_code]++;
- }
- }
- void QuicConnectivityMonitor::OnSessionRegistered(
- QuicChromiumClientSession* session,
- handles::NetworkHandle network) {
- if (network != default_network_)
- return;
- active_sessions_.insert(session);
- if (num_sessions_active_during_current_speculative_connectivity_failure_) {
- num_sessions_active_during_current_speculative_connectivity_failure_
- .value()++;
- }
- }
- void QuicConnectivityMonitor::OnSessionRemoved(
- QuicChromiumClientSession* session) {
- degrading_sessions_.erase(session);
- active_sessions_.erase(session);
- }
- void QuicConnectivityMonitor::OnDefaultNetworkUpdated(
- handles::NetworkHandle default_network) {
- default_network_ = default_network;
- active_sessions_.clear();
- degrading_sessions_.clear();
- num_sessions_active_during_current_speculative_connectivity_failure_ =
- absl::nullopt;
- write_error_map_.clear();
- quic_error_map_.clear();
- }
- void QuicConnectivityMonitor::OnIPAddressChanged() {
- // If handles::NetworkHandle is supported, connectivity monitor will receive
- // notifications via OnDefaultNetworkUpdated.
- if (NetworkChangeNotifier::AreNetworkHandlesSupported())
- return;
- DCHECK_EQ(default_network_, handles::kInvalidNetworkHandle);
- degrading_sessions_.clear();
- write_error_map_.clear();
- }
- void QuicConnectivityMonitor::OnSessionGoingAwayOnIPAddressChange(
- QuicChromiumClientSession* session) {
- // This should only be called after ConnectivityMonitor gets notified via
- // OnIPAddressChanged().
- DCHECK(degrading_sessions_.empty());
- // |session| that encounters IP address change will lose track which network
- // it is bound to. Future connectivity monitoring may be misleading.
- session->RemoveConnectivityObserver(this);
- }
- } // namespace net
|