| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/base/network_change_notifier.h" |
| |
| #include <limits> |
| #include <string> |
| #include <unordered_set> |
| #include <utility> |
| |
| #include "base/memory/ref_counted.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/no_destructor.h" |
| #include "base/observer_list.h" |
| #include "base/sequence_checker.h" |
| #include "base/strings/string_util.h" |
| #include "base/synchronization/lock.h" |
| #include "base/threading/thread_checker.h" |
| #include "base/timer/timer.h" |
| #include "build/build_config.h" |
| #include "build/chromeos_buildflags.h" |
| #include "net/base/network_change_notifier_factory.h" |
| #include "net/base/network_interfaces.h" |
| #include "net/base/url_util.h" |
| #include "net/dns/dns_config.h" |
| #include "net/dns/dns_config_service.h" |
| #include "net/dns/system_dns_config_change_notifier.h" |
| #include "net/url_request/url_request.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "url/gurl.h" |
| |
| #if defined(STARBOARD) |
| #include "net/base/network_change_notifier_starboard.h" |
| #elif BUILDFLAG(IS_WIN) |
| #include "net/base/network_change_notifier_win.h" |
| #elif BUILDFLAG(IS_LINUX) |
| #include "net/base/network_change_notifier_linux.h" |
| #elif BUILDFLAG(IS_APPLE) |
| #include "net/base/network_change_notifier_mac.h" |
| #elif BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) |
| #include "net/base/network_change_notifier_passive.h" |
| #elif BUILDFLAG(IS_FUCHSIA) |
| #include "net/base/network_change_notifier_fuchsia.h" |
| #endif |
| |
| namespace net { |
| |
| namespace { |
| |
| // The process-wide singleton notifier. |
| NetworkChangeNotifier* g_network_change_notifier = nullptr; |
| |
| // Class factory singleton. |
| NetworkChangeNotifierFactory* g_network_change_notifier_factory = nullptr; |
| |
| // Lock to protect |g_network_change_notifier| during creation time. Since |
| // creation of the process-wide instance can happen on any thread, this lock is |
| // used to guarantee only one instance is created. Once the global instance is |
| // created, the owner is responsible for destroying it on the same thread. All |
| // the other calls to the NetworkChangeNotifier do not require this lock as |
| // the global instance is only destroyed when the process is getting killed. |
| base::Lock& NetworkChangeNotifierCreationLock() { |
| static base::NoDestructor<base::Lock> instance; |
| return *instance; |
| } |
| |
| class MockNetworkChangeNotifier : public NetworkChangeNotifier { |
| public: |
| explicit MockNetworkChangeNotifier( |
| std::unique_ptr<SystemDnsConfigChangeNotifier> dns_config_notifier) |
| : NetworkChangeNotifier( |
| NetworkChangeCalculatorParams(), |
| dns_config_notifier.get(), |
| // Omit adding observers from the constructor as that would prevent |
| // construction when SingleThreadTaskRunner::CurrentDefaultHandle |
| // isn't set. |
| /* omit_observers_in_constructor_for_testing=*/true), |
| dns_config_notifier_(std::move(dns_config_notifier)) {} |
| |
| ~MockNetworkChangeNotifier() override { StopSystemDnsConfigNotifier(); } |
| |
| ConnectionType GetCurrentConnectionType() const override { |
| return CONNECTION_UNKNOWN; |
| } |
| |
| private: |
| std::unique_ptr<SystemDnsConfigChangeNotifier> dns_config_notifier_; |
| }; |
| |
| } // namespace |
| |
| // static |
| bool NetworkChangeNotifier::test_notifications_only_ = false; |
| |
| NetworkChangeNotifier::NetworkChangeCalculatorParams:: |
| NetworkChangeCalculatorParams() = default; |
| |
| // Calculates NetworkChange signal from IPAddress, ConnectionCost, and |
| // ConnectionType signals. |
| class NetworkChangeNotifier::NetworkChangeCalculator |
| : public ConnectionTypeObserver, |
| public ConnectionCostObserver, |
| public IPAddressObserver { |
| public: |
| explicit NetworkChangeCalculator(const NetworkChangeCalculatorParams& params) |
| : params_(params) { |
| DCHECK(g_network_change_notifier); |
| AddConnectionTypeObserver(this); |
| AddConnectionCostObserver(this); |
| AddIPAddressObserver(this); |
| } |
| |
| NetworkChangeCalculator(const NetworkChangeCalculator&) = delete; |
| NetworkChangeCalculator& operator=(const NetworkChangeCalculator&) = delete; |
| |
| ~NetworkChangeCalculator() override { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| RemoveConnectionTypeObserver(this); |
| RemoveConnectionCostObserver(this); |
| RemoveIPAddressObserver(this); |
| } |
| |
| // NetworkChangeNotifier::IPAddressObserver implementation. |
| void OnIPAddressChanged() override { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| pending_connection_type_ = GetConnectionType(); |
| base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE |
| ? params_.ip_address_offline_delay_ : params_.ip_address_online_delay_; |
| // Cancels any previous timer. |
| timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify); |
| } |
| |
| // NetworkChangeNotifier::ConnectionTypeObserver implementation. |
| void OnConnectionTypeChanged(ConnectionType type) override { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| pending_connection_type_ = type; |
| base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE |
| ? params_.connection_type_offline_delay_ |
| : params_.connection_type_online_delay_; |
| // Cancels any previous timer. |
| timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify); |
| } |
| |
| // NetworkChangeNotifier::ConnectionCostObserver implementation. |
| void OnConnectionCostChanged(ConnectionCost cost) override { |
| base::UmaHistogramEnumeration("Net.NetworkChangeNotifier.NewConnectionCost", |
| cost, CONNECTION_COST_LAST); |
| } |
| |
| private: |
| void Notify() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| // Don't bother signaling about dead connections. |
| if (have_announced_ && |
| (last_announced_connection_type_ == CONNECTION_NONE) && |
| (pending_connection_type_ == CONNECTION_NONE)) { |
| return; |
| } |
| |
| UMA_HISTOGRAM_ENUMERATION("Net.NetworkChangeNotifier.NewConnectionType", |
| pending_connection_type_, CONNECTION_LAST + 1); |
| |
| have_announced_ = true; |
| last_announced_connection_type_ = pending_connection_type_; |
| // Immediately before sending out an online signal, send out an offline |
| // signal to perform any destructive actions before constructive actions. |
| if (pending_connection_type_ != CONNECTION_NONE) |
| NetworkChangeNotifier::NotifyObserversOfNetworkChange(CONNECTION_NONE); |
| NetworkChangeNotifier::NotifyObserversOfNetworkChange( |
| pending_connection_type_); |
| } |
| |
| const NetworkChangeCalculatorParams params_; |
| |
| // Indicates if NotifyObserversOfNetworkChange has been called yet. |
| bool have_announced_ = false; |
| // Last value passed to NotifyObserversOfNetworkChange. |
| ConnectionType last_announced_connection_type_ = CONNECTION_NONE; |
| // Value to pass to NotifyObserversOfNetworkChange when Notify is called. |
| ConnectionType pending_connection_type_ = CONNECTION_NONE; |
| // Used to delay notifications so duplicates can be combined. |
| base::OneShotTimer timer_; |
| |
| base::ThreadChecker thread_checker_; |
| }; |
| |
| // Holds the collection of observer lists used by NetworkChangeNotifier. |
| class NetworkChangeNotifier::ObserverList { |
| public: |
| ObserverList() |
| : ip_address_observer_list_( |
| base::MakeRefCounted<base::ObserverListThreadSafe< |
| NetworkChangeNotifier::IPAddressObserver>>( |
| base::ObserverListPolicy::EXISTING_ONLY)), |
| connection_type_observer_list_( |
| base::MakeRefCounted<base::ObserverListThreadSafe< |
| NetworkChangeNotifier::ConnectionTypeObserver>>( |
| base::ObserverListPolicy::EXISTING_ONLY)), |
| resolver_state_observer_list_( |
| base::MakeRefCounted<base::ObserverListThreadSafe< |
| NetworkChangeNotifier::DNSObserver>>( |
| base::ObserverListPolicy::EXISTING_ONLY)), |
| network_change_observer_list_( |
| base::MakeRefCounted<base::ObserverListThreadSafe< |
| NetworkChangeNotifier::NetworkChangeObserver>>( |
| base::ObserverListPolicy::EXISTING_ONLY)), |
| max_bandwidth_observer_list_( |
| base::MakeRefCounted<base::ObserverListThreadSafe< |
| NetworkChangeNotifier::MaxBandwidthObserver>>( |
| base::ObserverListPolicy::EXISTING_ONLY)), |
| network_observer_list_( |
| base::MakeRefCounted<base::ObserverListThreadSafe< |
| NetworkChangeNotifier::NetworkObserver>>( |
| base::ObserverListPolicy::EXISTING_ONLY)), |
| connection_cost_observer_list_( |
| base::MakeRefCounted<base::ObserverListThreadSafe< |
| NetworkChangeNotifier::ConnectionCostObserver>>( |
| base::ObserverListPolicy::EXISTING_ONLY)), |
| default_network_active_observer_list_( |
| base::MakeRefCounted< |
| base::ObserverListThreadSafe<DefaultNetworkActiveObserver>>( |
| base::ObserverListPolicy::EXISTING_ONLY)) {} |
| |
| ObserverList(const ObserverList&) = delete; |
| ObserverList& operator=(const ObserverList&) = delete; |
| ~ObserverList() = default; |
| |
| const scoped_refptr< |
| base::ObserverListThreadSafe<NetworkChangeNotifier::IPAddressObserver>> |
| ip_address_observer_list_; |
| const scoped_refptr<base::ObserverListThreadSafe< |
| NetworkChangeNotifier::ConnectionTypeObserver>> |
| connection_type_observer_list_; |
| const scoped_refptr< |
| base::ObserverListThreadSafe<NetworkChangeNotifier::DNSObserver>> |
| resolver_state_observer_list_; |
| const scoped_refptr<base::ObserverListThreadSafe< |
| NetworkChangeNotifier::NetworkChangeObserver>> |
| network_change_observer_list_; |
| const scoped_refptr< |
| base::ObserverListThreadSafe<NetworkChangeNotifier::MaxBandwidthObserver>> |
| max_bandwidth_observer_list_; |
| const scoped_refptr< |
| base::ObserverListThreadSafe<NetworkChangeNotifier::NetworkObserver>> |
| network_observer_list_; |
| const scoped_refptr<base::ObserverListThreadSafe< |
| NetworkChangeNotifier::ConnectionCostObserver>> |
| connection_cost_observer_list_; |
| const scoped_refptr< |
| base::ObserverListThreadSafe<DefaultNetworkActiveObserver>> |
| default_network_active_observer_list_; |
| |
| // Indicates if connection cost observer was added before |
| // network_change_notifier was initialized, if so ConnectionCostObserverAdded |
| // is invoked from constructor. |
| std::atomic_bool connection_cost_observers_added_ = false; |
| }; |
| |
| class NetworkChangeNotifier::SystemDnsConfigObserver |
| : public SystemDnsConfigChangeNotifier::Observer { |
| public: |
| virtual ~SystemDnsConfigObserver() = default; |
| |
| void OnSystemDnsConfigChanged(absl::optional<DnsConfig> config) override { |
| NotifyObserversOfDNSChange(); |
| } |
| }; |
| |
| void NetworkChangeNotifier::ClearGlobalPointer() { |
| if (!cleared_global_pointer_) { |
| cleared_global_pointer_ = true; |
| DCHECK_EQ(this, g_network_change_notifier); |
| g_network_change_notifier = nullptr; |
| } |
| } |
| |
| NetworkChangeNotifier::~NetworkChangeNotifier() { |
| network_change_calculator_.reset(); |
| ClearGlobalPointer(); |
| StopSystemDnsConfigNotifier(); |
| } |
| |
| // static |
| NetworkChangeNotifierFactory* NetworkChangeNotifier::GetFactory() { |
| return g_network_change_notifier_factory; |
| } |
| |
| // static |
| void NetworkChangeNotifier::SetFactory( |
| NetworkChangeNotifierFactory* factory) { |
| CHECK(!g_network_change_notifier_factory); |
| g_network_change_notifier_factory = factory; |
| } |
| |
| // static |
| std::unique_ptr<NetworkChangeNotifier> NetworkChangeNotifier::CreateIfNeeded( |
| NetworkChangeNotifier::ConnectionType initial_type, |
| NetworkChangeNotifier::ConnectionSubtype initial_subtype) { |
| { |
| base::AutoLock auto_lock(NetworkChangeNotifierCreationLock()); |
| if (g_network_change_notifier) |
| return nullptr; |
| } |
| |
| if (g_network_change_notifier_factory) { |
| return g_network_change_notifier_factory->CreateInstanceWithInitialTypes( |
| initial_type, initial_subtype); |
| } |
| |
| #if defined(STARBOARD) |
| return std::make_unique<NetworkChangeNotifierStarboard>(); |
| #elif BUILDFLAG(IS_WIN) |
| std::unique_ptr<NetworkChangeNotifierWin> network_change_notifier = |
| std::make_unique<NetworkChangeNotifierWin>(); |
| network_change_notifier->WatchForAddressChange(); |
| return network_change_notifier; |
| #elif BUILDFLAG(IS_ANDROID) |
| // Fallback to use NetworkChangeNotifierPassive if |
| // NetworkChangeNotifierFactory is not set. Currently used for tests and when |
| // running network service in a separate process. |
| return std::make_unique<NetworkChangeNotifierPassive>(initial_type, |
| initial_subtype); |
| #elif BUILDFLAG(IS_CHROMEOS) |
| return std::make_unique<NetworkChangeNotifierPassive>(initial_type, |
| initial_subtype); |
| #elif BUILDFLAG(IS_LINUX) |
| return std::make_unique<NetworkChangeNotifierLinux>( |
| std::unordered_set<std::string>()); |
| #elif BUILDFLAG(IS_APPLE) |
| return std::make_unique<NetworkChangeNotifierMac>(); |
| #elif BUILDFLAG(IS_FUCHSIA) |
| return std::make_unique<NetworkChangeNotifierFuchsia>( |
| /*require_wlan=*/false); |
| #else |
| NOTIMPLEMENTED(); |
| return nullptr; |
| #endif |
| } |
| |
| // static |
| NetworkChangeNotifier::ConnectionCost |
| NetworkChangeNotifier::GetConnectionCost() { |
| return g_network_change_notifier |
| ? g_network_change_notifier->GetCurrentConnectionCost() |
| : CONNECTION_COST_UNKNOWN; |
| } |
| |
| // static |
| NetworkChangeNotifier::ConnectionType |
| NetworkChangeNotifier::GetConnectionType() { |
| return g_network_change_notifier ? |
| g_network_change_notifier->GetCurrentConnectionType() : |
| CONNECTION_UNKNOWN; |
| } |
| |
| // static |
| NetworkChangeNotifier::ConnectionSubtype |
| NetworkChangeNotifier::GetConnectionSubtype() { |
| return g_network_change_notifier |
| ? g_network_change_notifier->GetCurrentConnectionSubtype() |
| : SUBTYPE_UNKNOWN; |
| } |
| |
| // static |
| void NetworkChangeNotifier::GetMaxBandwidthAndConnectionType( |
| double* max_bandwidth_mbps, |
| ConnectionType* connection_type) { |
| if (!g_network_change_notifier) { |
| *connection_type = CONNECTION_UNKNOWN; |
| *max_bandwidth_mbps = |
| GetMaxBandwidthMbpsForConnectionSubtype(SUBTYPE_UNKNOWN); |
| return; |
| } |
| |
| g_network_change_notifier->GetCurrentMaxBandwidthAndConnectionType( |
| max_bandwidth_mbps, connection_type); |
| } |
| |
| // static |
| double NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype( |
| ConnectionSubtype subtype) { |
| switch (subtype) { |
| case SUBTYPE_GSM: |
| return 0.01; |
| case SUBTYPE_IDEN: |
| return 0.064; |
| case SUBTYPE_CDMA: |
| return 0.115; |
| case SUBTYPE_1XRTT: |
| return 0.153; |
| case SUBTYPE_GPRS: |
| return 0.237; |
| case SUBTYPE_EDGE: |
| return 0.384; |
| case SUBTYPE_UMTS: |
| return 2.0; |
| case SUBTYPE_EVDO_REV_0: |
| return 2.46; |
| case SUBTYPE_EVDO_REV_A: |
| return 3.1; |
| case SUBTYPE_HSPA: |
| return 3.6; |
| case SUBTYPE_EVDO_REV_B: |
| return 14.7; |
| case SUBTYPE_HSDPA: |
| return 14.3; |
| case SUBTYPE_HSUPA: |
| return 14.4; |
| case SUBTYPE_EHRPD: |
| return 21.0; |
| case SUBTYPE_HSPAP: |
| return 42.0; |
| case SUBTYPE_LTE: |
| return 100.0; |
| case SUBTYPE_LTE_ADVANCED: |
| return 100.0; |
| case SUBTYPE_BLUETOOTH_1_2: |
| return 1.0; |
| case SUBTYPE_BLUETOOTH_2_1: |
| return 3.0; |
| case SUBTYPE_BLUETOOTH_3_0: |
| return 24.0; |
| case SUBTYPE_BLUETOOTH_4_0: |
| return 1.0; |
| case SUBTYPE_ETHERNET: |
| return 10.0; |
| case SUBTYPE_FAST_ETHERNET: |
| return 100.0; |
| case SUBTYPE_GIGABIT_ETHERNET: |
| return 1000.0; |
| case SUBTYPE_10_GIGABIT_ETHERNET: |
| return 10000.0; |
| case SUBTYPE_WIFI_B: |
| return 11.0; |
| case SUBTYPE_WIFI_G: |
| return 54.0; |
| case SUBTYPE_WIFI_N: |
| return 600.0; |
| case SUBTYPE_WIFI_AC: |
| return 1300.0; |
| case SUBTYPE_WIFI_AD: |
| return 7000.0; |
| case SUBTYPE_UNKNOWN: |
| return std::numeric_limits<double>::infinity(); |
| case SUBTYPE_NONE: |
| return 0.0; |
| case SUBTYPE_OTHER: |
| return std::numeric_limits<double>::infinity(); |
| } |
| NOTREACHED(); |
| return std::numeric_limits<double>::infinity(); |
| } |
| |
| // static |
| bool NetworkChangeNotifier::AreNetworkHandlesSupported() { |
| if (g_network_change_notifier) { |
| return g_network_change_notifier->AreNetworkHandlesCurrentlySupported(); |
| } |
| return false; |
| } |
| |
| // static |
| void NetworkChangeNotifier::GetConnectedNetworks(NetworkList* network_list) { |
| DCHECK(AreNetworkHandlesSupported()); |
| if (g_network_change_notifier) { |
| g_network_change_notifier->GetCurrentConnectedNetworks(network_list); |
| } else { |
| network_list->clear(); |
| } |
| } |
| |
| // static |
| NetworkChangeNotifier::ConnectionType |
| NetworkChangeNotifier::GetNetworkConnectionType( |
| handles::NetworkHandle network) { |
| DCHECK(AreNetworkHandlesSupported()); |
| return g_network_change_notifier |
| ? g_network_change_notifier->GetCurrentNetworkConnectionType( |
| network) |
| : CONNECTION_UNKNOWN; |
| } |
| |
| // static |
| handles::NetworkHandle NetworkChangeNotifier::GetDefaultNetwork() { |
| DCHECK(AreNetworkHandlesSupported()); |
| return g_network_change_notifier |
| ? g_network_change_notifier->GetCurrentDefaultNetwork() |
| : handles::kInvalidNetworkHandle; |
| } |
| |
| // static |
| SystemDnsConfigChangeNotifier* |
| NetworkChangeNotifier::GetSystemDnsConfigNotifier() { |
| if (g_network_change_notifier) |
| return g_network_change_notifier->GetCurrentSystemDnsConfigNotifier(); |
| return nullptr; |
| } |
| |
| // static |
| bool NetworkChangeNotifier::IsDefaultNetworkActive() { |
| if (g_network_change_notifier) |
| return g_network_change_notifier->IsDefaultNetworkActiveInternal(); |
| // Assume true as a "default" to avoid batching indefinitely. |
| return true; |
| } |
| |
| // static |
| const char* NetworkChangeNotifier::ConnectionTypeToString( |
| ConnectionType type) { |
| static const char* const kConnectionTypeNames[] = { |
| "CONNECTION_UNKNOWN", "CONNECTION_ETHERNET", "CONNECTION_WIFI", |
| "CONNECTION_2G", "CONNECTION_3G", "CONNECTION_4G", |
| "CONNECTION_NONE", "CONNECTION_BLUETOOTH", "CONNECTION_5G", |
| }; |
| static_assert(std::size(kConnectionTypeNames) == |
| NetworkChangeNotifier::CONNECTION_LAST + 1, |
| "ConnectionType name count should match"); |
| if (type < CONNECTION_UNKNOWN || type > CONNECTION_LAST) { |
| NOTREACHED(); |
| return "CONNECTION_INVALID"; |
| } |
| return kConnectionTypeNames[type]; |
| } |
| |
| #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| // static |
| AddressMapOwnerLinux* NetworkChangeNotifier::GetAddressMapOwner() { |
| return g_network_change_notifier |
| ? g_network_change_notifier->GetAddressMapOwnerInternal() |
| : nullptr; |
| } |
| #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| |
| #if BUILDFLAG(IS_FUCHSIA) |
| // static |
| const internal::NetworkInterfaceCache* |
| NetworkChangeNotifier::GetNetworkInterfaceCache() { |
| return g_network_change_notifier |
| ? g_network_change_notifier->GetNetworkInterfaceCacheInternal() |
| : nullptr; |
| } |
| #endif // BUILDFLAG(IS_FUCHSIA) |
| |
| // static |
| bool NetworkChangeNotifier::IsOffline() { |
| return GetConnectionType() == CONNECTION_NONE; |
| } |
| |
| // static |
| bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type) { |
| bool is_cellular = false; |
| switch (type) { |
| case CONNECTION_2G: |
| case CONNECTION_3G: |
| case CONNECTION_4G: |
| case CONNECTION_5G: |
| is_cellular = true; |
| break; |
| case CONNECTION_UNKNOWN: |
| case CONNECTION_ETHERNET: |
| case CONNECTION_WIFI: |
| case CONNECTION_NONE: |
| case CONNECTION_BLUETOOTH: |
| is_cellular = false; |
| break; |
| } |
| return is_cellular; |
| } |
| |
| // static |
| NetworkChangeNotifier::ConnectionType |
| NetworkChangeNotifier::ConnectionTypeFromInterfaces() { |
| NetworkInterfaceList interfaces; |
| if (!GetNetworkList(&interfaces, EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES)) |
| return CONNECTION_UNKNOWN; |
| return ConnectionTypeFromInterfaceList(interfaces); |
| } |
| |
| // static |
| NetworkChangeNotifier::ConnectionType |
| NetworkChangeNotifier::ConnectionTypeFromInterfaceList( |
| const NetworkInterfaceList& interfaces) { |
| bool first = true; |
| ConnectionType result = CONNECTION_NONE; |
| for (const auto& network_interface : interfaces) { |
| #if BUILDFLAG(IS_WIN) |
| if (network_interface.friendly_name == "Teredo Tunneling Pseudo-Interface") |
| continue; |
| #endif |
| #if BUILDFLAG(IS_APPLE) |
| // Ignore link-local addresses as they aren't globally routable. |
| // Mac assigns these to disconnected interfaces like tunnel interfaces |
| // ("utun"), airdrop interfaces ("awdl"), and ethernet ports ("en"). |
| if (network_interface.address.IsLinkLocal()) |
| continue; |
| #endif |
| |
| // Remove VMware network interfaces as they're internal and should not be |
| // used to determine the network connection type. |
| if (base::ToLowerASCII(network_interface.friendly_name).find("vmnet") != |
| std::string::npos) { |
| continue; |
| } |
| if (first) { |
| first = false; |
| result = network_interface.type; |
| } else if (result != network_interface.type) { |
| return CONNECTION_UNKNOWN; |
| } |
| } |
| return result; |
| } |
| |
| // static |
| std::unique_ptr<NetworkChangeNotifier> |
| NetworkChangeNotifier::CreateMockIfNeeded() { |
| { |
| base::AutoLock auto_lock(NetworkChangeNotifierCreationLock()); |
| if (g_network_change_notifier) |
| return nullptr; |
| } |
| // Use an empty noop SystemDnsConfigChangeNotifier to disable actual system |
| // DNS configuration notifications. |
| return std::make_unique<MockNetworkChangeNotifier>( |
| std::make_unique<SystemDnsConfigChangeNotifier>( |
| nullptr /* task_runner */, nullptr /* dns_config_service */)); |
| } |
| |
| NetworkChangeNotifier::IPAddressObserver::IPAddressObserver() = default; |
| NetworkChangeNotifier::IPAddressObserver::~IPAddressObserver() = default; |
| |
| NetworkChangeNotifier::ConnectionTypeObserver::ConnectionTypeObserver() = |
| default; |
| NetworkChangeNotifier::ConnectionTypeObserver::~ConnectionTypeObserver() = |
| default; |
| |
| NetworkChangeNotifier::DNSObserver::DNSObserver() = default; |
| NetworkChangeNotifier::DNSObserver::~DNSObserver() = default; |
| |
| NetworkChangeNotifier::NetworkChangeObserver::NetworkChangeObserver() = default; |
| NetworkChangeNotifier::NetworkChangeObserver::~NetworkChangeObserver() = |
| default; |
| |
| NetworkChangeNotifier::MaxBandwidthObserver::MaxBandwidthObserver() = default; |
| NetworkChangeNotifier::MaxBandwidthObserver::~MaxBandwidthObserver() = default; |
| |
| NetworkChangeNotifier::NetworkObserver::NetworkObserver() = default; |
| NetworkChangeNotifier::NetworkObserver::~NetworkObserver() = default; |
| |
| NetworkChangeNotifier::ConnectionCostObserver::ConnectionCostObserver() = |
| default; |
| NetworkChangeNotifier::ConnectionCostObserver::~ConnectionCostObserver() = |
| default; |
| |
| NetworkChangeNotifier::DefaultNetworkActiveObserver:: |
| DefaultNetworkActiveObserver() = default; |
| NetworkChangeNotifier::DefaultNetworkActiveObserver:: |
| ~DefaultNetworkActiveObserver() = default; |
| |
| void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver* observer) { |
| DCHECK(!observer->observer_list_); |
| observer->observer_list_ = GetObserverList().ip_address_observer_list_; |
| observer->observer_list_->AddObserver(observer); |
| } |
| |
| void NetworkChangeNotifier::AddConnectionTypeObserver( |
| ConnectionTypeObserver* observer) { |
| DCHECK(!observer->observer_list_); |
| observer->observer_list_ = GetObserverList().connection_type_observer_list_; |
| observer->observer_list_->AddObserver(observer); |
| } |
| |
| void NetworkChangeNotifier::AddDNSObserver(DNSObserver* observer) { |
| DCHECK(!observer->observer_list_); |
| observer->observer_list_ = GetObserverList().resolver_state_observer_list_; |
| observer->observer_list_->AddObserver(observer); |
| } |
| |
| void NetworkChangeNotifier::AddNetworkChangeObserver( |
| NetworkChangeObserver* observer) { |
| DCHECK(!observer->observer_list_); |
| observer->observer_list_ = GetObserverList().network_change_observer_list_; |
| observer->observer_list_->AddObserver(observer); |
| } |
| |
| void NetworkChangeNotifier::AddMaxBandwidthObserver( |
| MaxBandwidthObserver* observer) { |
| DCHECK(!observer->observer_list_); |
| observer->observer_list_ = GetObserverList().max_bandwidth_observer_list_; |
| observer->observer_list_->AddObserver(observer); |
| } |
| |
| void NetworkChangeNotifier::AddNetworkObserver(NetworkObserver* observer) { |
| base::AutoLock auto_lock(NetworkChangeNotifierCreationLock()); |
| DCHECK(AreNetworkHandlesSupported()); |
| DCHECK(!observer->observer_list_); |
| observer->observer_list_ = GetObserverList().network_observer_list_; |
| observer->observer_list_->AddObserver(observer); |
| } |
| |
| void NetworkChangeNotifier::AddConnectionCostObserver( |
| ConnectionCostObserver* observer) { |
| DCHECK(!observer->observer_list_); |
| GetObserverList().connection_cost_observers_added_ = true; |
| observer->observer_list_ = GetObserverList().connection_cost_observer_list_; |
| observer->observer_list_->AddObserver(observer); |
| base::AutoLock auto_lock(NetworkChangeNotifierCreationLock()); |
| if (g_network_change_notifier) { |
| g_network_change_notifier->ConnectionCostObserverAdded(); |
| } |
| } |
| |
| void NetworkChangeNotifier::AddDefaultNetworkActiveObserver( |
| DefaultNetworkActiveObserver* observer) { |
| DCHECK(!observer->observer_list_); |
| observer->observer_list_ = |
| GetObserverList().default_network_active_observer_list_; |
| observer->observer_list_->AddObserver(observer); |
| base::AutoLock auto_lock(NetworkChangeNotifierCreationLock()); |
| // Currently we lose DefaultNetworkActiveObserverAdded notifications for |
| // observers added prior to NCN creation. This should be a non-issue as |
| // currently only Cronet listens to this and its observers are always added |
| // after NCN creation. |
| if (g_network_change_notifier) { |
| g_network_change_notifier->DefaultNetworkActiveObserverAdded(); |
| } |
| } |
| |
| void NetworkChangeNotifier::RemoveIPAddressObserver( |
| IPAddressObserver* observer) { |
| if (observer->observer_list_) { |
| observer->observer_list_->RemoveObserver(observer); |
| observer->observer_list_.reset(); |
| } |
| } |
| |
| void NetworkChangeNotifier::RemoveConnectionTypeObserver( |
| ConnectionTypeObserver* observer) { |
| if (observer->observer_list_) { |
| observer->observer_list_->RemoveObserver(observer); |
| observer->observer_list_.reset(); |
| } |
| } |
| |
| void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver* observer) { |
| if (observer->observer_list_) { |
| observer->observer_list_->RemoveObserver(observer); |
| observer->observer_list_.reset(); |
| } |
| } |
| |
| void NetworkChangeNotifier::RemoveNetworkChangeObserver( |
| NetworkChangeObserver* observer) { |
| if (observer->observer_list_) { |
| observer->observer_list_->RemoveObserver(observer); |
| observer->observer_list_.reset(); |
| } |
| } |
| |
| void NetworkChangeNotifier::RemoveMaxBandwidthObserver( |
| MaxBandwidthObserver* observer) { |
| if (observer->observer_list_) { |
| observer->observer_list_->RemoveObserver(observer); |
| observer->observer_list_.reset(); |
| } |
| } |
| |
| void NetworkChangeNotifier::RemoveNetworkObserver(NetworkObserver* observer) { |
| if (observer->observer_list_) { |
| observer->observer_list_->RemoveObserver(observer); |
| observer->observer_list_.reset(); |
| } |
| } |
| |
| void NetworkChangeNotifier::RemoveConnectionCostObserver( |
| ConnectionCostObserver* observer) { |
| if (observer->observer_list_) { |
| observer->observer_list_->RemoveObserver(observer); |
| observer->observer_list_.reset(); |
| } |
| } |
| |
| void NetworkChangeNotifier::RemoveDefaultNetworkActiveObserver( |
| DefaultNetworkActiveObserver* observer) { |
| if (observer->observer_list_) { |
| observer->observer_list_->RemoveObserver(observer); |
| observer->observer_list_.reset(); |
| g_network_change_notifier->DefaultNetworkActiveObserverRemoved(); |
| } |
| } |
| |
| void NetworkChangeNotifier::TriggerNonSystemDnsChange() { |
| NetworkChangeNotifier::NotifyObserversOfDNSChange(); |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests() { |
| if (g_network_change_notifier) |
| g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl(); |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests( |
| ConnectionType type) { |
| if (g_network_change_notifier) |
| g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(type); |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfDNSChangeForTests() { |
| if (g_network_change_notifier) |
| g_network_change_notifier->NotifyObserversOfDNSChangeImpl(); |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| ConnectionType type) { |
| if (g_network_change_notifier) |
| g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type); |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChangeForTests( |
| double max_bandwidth_mbps, |
| ConnectionType type) { |
| if (g_network_change_notifier) { |
| g_network_change_notifier->NotifyObserversOfMaxBandwidthChangeImpl( |
| max_bandwidth_mbps, type); |
| } |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfConnectionCostChangeForTests( |
| ConnectionCost cost) { |
| if (g_network_change_notifier) |
| g_network_change_notifier->NotifyObserversOfConnectionCostChangeImpl(cost); |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfDefaultNetworkActiveForTests() { |
| if (g_network_change_notifier) |
| g_network_change_notifier->NotifyObserversOfDefaultNetworkActiveImpl(); |
| } |
| |
| // static |
| void NetworkChangeNotifier::SetTestNotificationsOnly(bool test_only) { |
| DCHECK(!g_network_change_notifier); |
| NetworkChangeNotifier::test_notifications_only_ = test_only; |
| } |
| |
| NetworkChangeNotifier::NetworkChangeNotifier( |
| const NetworkChangeCalculatorParams& params |
| /*= NetworkChangeCalculatorParams()*/, |
| SystemDnsConfigChangeNotifier* system_dns_config_notifier /*= nullptr */, |
| bool omit_observers_in_constructor_for_testing /*= false */) |
| : system_dns_config_notifier_(system_dns_config_notifier), |
| system_dns_config_observer_(std::make_unique<SystemDnsConfigObserver>()) { |
| { |
| base::AutoLock auto_lock(NetworkChangeNotifierCreationLock()); |
| if (!system_dns_config_notifier_) { |
| static base::NoDestructor<SystemDnsConfigChangeNotifier> singleton{}; |
| system_dns_config_notifier_ = singleton.get(); |
| } |
| |
| DCHECK(!g_network_change_notifier); |
| g_network_change_notifier = this; |
| |
| system_dns_config_notifier_->AddObserver(system_dns_config_observer_.get()); |
| if (GetObserverList().connection_cost_observers_added_) { |
| g_network_change_notifier->ConnectionCostObserverAdded(); |
| } |
| } |
| if (!omit_observers_in_constructor_for_testing) { |
| network_change_calculator_ = |
| std::make_unique<NetworkChangeCalculator>(params); |
| } |
| } |
| |
| #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| AddressMapOwnerLinux* NetworkChangeNotifier::GetAddressMapOwnerInternal() { |
| return nullptr; |
| } |
| #endif |
| |
| #if BUILDFLAG(IS_FUCHSIA) |
| const internal::NetworkInterfaceCache* |
| NetworkChangeNotifier::GetNetworkInterfaceCacheInternal() const { |
| return nullptr; |
| } |
| #endif |
| |
| NetworkChangeNotifier::ConnectionCost |
| NetworkChangeNotifier::GetCurrentConnectionCost() { |
| // This is the default non-platform specific implementation and assumes that |
| // cellular connectivity is metered and non-cellular is not. The function can |
| // be specialized on each platform specific notifier implementation. |
| return IsConnectionCellular(GetCurrentConnectionType()) |
| ? CONNECTION_COST_METERED |
| : CONNECTION_COST_UNMETERED; |
| } |
| |
| NetworkChangeNotifier::ConnectionSubtype |
| NetworkChangeNotifier::GetCurrentConnectionSubtype() const { |
| return SUBTYPE_UNKNOWN; |
| } |
| |
| void NetworkChangeNotifier::GetCurrentMaxBandwidthAndConnectionType( |
| double* max_bandwidth_mbps, |
| ConnectionType* connection_type) const { |
| // This default implementation conforms to the NetInfo V3 specification but |
| // should be overridden to provide specific bandwidth data based on the |
| // platform. |
| *connection_type = GetCurrentConnectionType(); |
| *max_bandwidth_mbps = |
| *connection_type == CONNECTION_NONE |
| ? GetMaxBandwidthMbpsForConnectionSubtype(SUBTYPE_NONE) |
| : GetMaxBandwidthMbpsForConnectionSubtype(SUBTYPE_UNKNOWN); |
| } |
| |
| bool NetworkChangeNotifier::AreNetworkHandlesCurrentlySupported() const { |
| return false; |
| } |
| |
| void NetworkChangeNotifier::GetCurrentConnectedNetworks( |
| NetworkList* network_list) const { |
| network_list->clear(); |
| } |
| |
| NetworkChangeNotifier::ConnectionType |
| NetworkChangeNotifier::GetCurrentNetworkConnectionType( |
| handles::NetworkHandle network) const { |
| return CONNECTION_UNKNOWN; |
| } |
| |
| handles::NetworkHandle NetworkChangeNotifier::GetCurrentDefaultNetwork() const { |
| return handles::kInvalidNetworkHandle; |
| } |
| |
| SystemDnsConfigChangeNotifier* |
| NetworkChangeNotifier::GetCurrentSystemDnsConfigNotifier() { |
| DCHECK(system_dns_config_notifier_); |
| return system_dns_config_notifier_; |
| } |
| |
| bool NetworkChangeNotifier::IsDefaultNetworkActiveInternal() { |
| return true; |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() { |
| if (g_network_change_notifier && |
| !NetworkChangeNotifier::test_notifications_only_) { |
| g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl(); |
| } |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() { |
| if (g_network_change_notifier && |
| !NetworkChangeNotifier::test_notifications_only_) { |
| g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl( |
| GetConnectionType()); |
| } |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfNetworkChange( |
| ConnectionType type) { |
| if (g_network_change_notifier && |
| !NetworkChangeNotifier::test_notifications_only_) { |
| g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type); |
| } |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChange( |
| double max_bandwidth_mbps, |
| ConnectionType type) { |
| if (g_network_change_notifier && |
| !NetworkChangeNotifier::test_notifications_only_) { |
| g_network_change_notifier->NotifyObserversOfMaxBandwidthChangeImpl( |
| max_bandwidth_mbps, type); |
| } |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfDNSChange() { |
| if (g_network_change_notifier && |
| !NetworkChangeNotifier::test_notifications_only_) { |
| g_network_change_notifier->NotifyObserversOfDNSChangeImpl(); |
| } |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChange( |
| NetworkChangeType type, |
| handles::NetworkHandle network) { |
| if (g_network_change_notifier && |
| !NetworkChangeNotifier::test_notifications_only_) { |
| g_network_change_notifier->NotifyObserversOfSpecificNetworkChangeImpl( |
| type, network); |
| } |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfConnectionCostChange() { |
| if (g_network_change_notifier && |
| !NetworkChangeNotifier::test_notifications_only_) { |
| g_network_change_notifier->NotifyObserversOfConnectionCostChangeImpl( |
| GetConnectionCost()); |
| } |
| } |
| |
| // static |
| void NetworkChangeNotifier::NotifyObserversOfDefaultNetworkActive() { |
| if (g_network_change_notifier && |
| !NetworkChangeNotifier::test_notifications_only_) { |
| g_network_change_notifier->NotifyObserversOfDefaultNetworkActiveImpl(); |
| } |
| } |
| |
| void NetworkChangeNotifier::StopSystemDnsConfigNotifier() { |
| if (!system_dns_config_notifier_) |
| return; |
| |
| system_dns_config_notifier_->RemoveObserver( |
| system_dns_config_observer_.get()); |
| system_dns_config_observer_ = nullptr; |
| system_dns_config_notifier_ = nullptr; |
| } |
| |
| void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeImpl() { |
| GetObserverList().ip_address_observer_list_->Notify( |
| FROM_HERE, &IPAddressObserver::OnIPAddressChanged); |
| } |
| |
| void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeImpl( |
| ConnectionType type) { |
| GetObserverList().connection_type_observer_list_->Notify( |
| FROM_HERE, &ConnectionTypeObserver::OnConnectionTypeChanged, type); |
| } |
| |
| void NetworkChangeNotifier::NotifyObserversOfNetworkChangeImpl( |
| ConnectionType type) { |
| GetObserverList().network_change_observer_list_->Notify( |
| FROM_HERE, &NetworkChangeObserver::OnNetworkChanged, type); |
| } |
| |
| void NetworkChangeNotifier::NotifyObserversOfDNSChangeImpl() { |
| GetObserverList().resolver_state_observer_list_->Notify( |
| FROM_HERE, &DNSObserver::OnDNSChanged); |
| } |
| |
| void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChangeImpl( |
| double max_bandwidth_mbps, |
| ConnectionType type) { |
| GetObserverList().max_bandwidth_observer_list_->Notify( |
| FROM_HERE, &MaxBandwidthObserver::OnMaxBandwidthChanged, |
| max_bandwidth_mbps, type); |
| } |
| |
| void NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChangeImpl( |
| NetworkChangeType type, |
| handles::NetworkHandle network) { |
| switch (type) { |
| case NetworkChangeType::kConnected: |
| GetObserverList().network_observer_list_->Notify( |
| FROM_HERE, &NetworkObserver::OnNetworkConnected, network); |
| break; |
| case NetworkChangeType::kDisconnected: |
| GetObserverList().network_observer_list_->Notify( |
| FROM_HERE, &NetworkObserver::OnNetworkDisconnected, network); |
| break; |
| case NetworkChangeType::kSoonToDisconnect: |
| GetObserverList().network_observer_list_->Notify( |
| FROM_HERE, &NetworkObserver::OnNetworkSoonToDisconnect, network); |
| break; |
| case NetworkChangeType::kMadeDefault: |
| GetObserverList().network_observer_list_->Notify( |
| FROM_HERE, &NetworkObserver::OnNetworkMadeDefault, network); |
| break; |
| } |
| } |
| |
| void NetworkChangeNotifier::NotifyObserversOfConnectionCostChangeImpl( |
| ConnectionCost cost) { |
| GetObserverList().connection_cost_observer_list_->Notify( |
| FROM_HERE, &ConnectionCostObserver::OnConnectionCostChanged, cost); |
| } |
| |
| void NetworkChangeNotifier::NotifyObserversOfDefaultNetworkActiveImpl() { |
| GetObserverList().default_network_active_observer_list_->Notify( |
| FROM_HERE, &DefaultNetworkActiveObserver::OnDefaultNetworkActive); |
| } |
| |
| NetworkChangeNotifier::DisableForTest::DisableForTest() |
| : network_change_notifier_(g_network_change_notifier) { |
| DCHECK(g_network_change_notifier); |
| g_network_change_notifier = nullptr; |
| } |
| |
| NetworkChangeNotifier::DisableForTest::~DisableForTest() { |
| DCHECK(!g_network_change_notifier); |
| g_network_change_notifier = network_change_notifier_; |
| } |
| |
| // static |
| NetworkChangeNotifier::ObserverList& NetworkChangeNotifier::GetObserverList() { |
| static base::NoDestructor<NetworkChangeNotifier::ObserverList> observers; |
| return *observers; |
| } |
| |
| } // namespace net |