// Copyright (c) 2012 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/base/network_change_notifier_linux.h" #include "base/bind.h" #include "base/compiler_specific.h" #include "base/macros.h" #include "base/message_loop/message_loop.h" #include "base/threading/thread.h" #include "net/base/address_tracker_linux.h" #include "net/dns/dns_config_service.h" namespace net { class NetworkChangeNotifierLinux::Thread : public base::Thread { public: explicit Thread(const std::unordered_set& ignored_interfaces); ~Thread() override; // Plumbing for NetworkChangeNotifier::GetCurrentConnectionType. // Safe to call from any thread. NetworkChangeNotifier::ConnectionType GetCurrentConnectionType() { return address_tracker_->GetCurrentConnectionType(); } const internal::AddressTrackerLinux* address_tracker() const { return address_tracker_.get(); } protected: // base::Thread void Init() override; void CleanUp() override; private: void OnIPAddressChanged(); void OnLinkChanged(); std::unique_ptr dns_config_service_; // Used to detect online/offline state and IP address changes. std::unique_ptr address_tracker_; NetworkChangeNotifier::ConnectionType last_type_; DISALLOW_COPY_AND_ASSIGN(Thread); }; NetworkChangeNotifierLinux::Thread::Thread( const std::unordered_set& ignored_interfaces) : base::Thread("NetworkChangeNotifier"), address_tracker_(new internal::AddressTrackerLinux( base::Bind(&NetworkChangeNotifierLinux::Thread::OnIPAddressChanged, base::Unretained(this)), base::Bind(&NetworkChangeNotifierLinux::Thread::OnLinkChanged, base::Unretained(this)), base::Bind(base::DoNothing), ignored_interfaces)), last_type_(NetworkChangeNotifier::CONNECTION_NONE) {} NetworkChangeNotifierLinux::Thread::~Thread() { DCHECK(!Thread::IsRunning()); } void NetworkChangeNotifierLinux::Thread::Init() { address_tracker_->Init(); dns_config_service_ = DnsConfigService::CreateSystemService(); dns_config_service_->WatchConfig( base::Bind(&NetworkChangeNotifier::SetDnsConfig)); } void NetworkChangeNotifierLinux::Thread::CleanUp() { // Delete AddressTrackerLinux before MessageLoop gets deleted as // AddressTrackerLinux's FileDescriptorWatcher holds a pointer to the // MessageLoop. address_tracker_.reset(); dns_config_service_.reset(); } void NetworkChangeNotifierLinux::Thread::OnIPAddressChanged() { NetworkChangeNotifier::NotifyObserversOfIPAddressChange(); // When the IP address of a network interface is added/deleted, the // connection type may have changed. OnLinkChanged(); } void NetworkChangeNotifierLinux::Thread::OnLinkChanged() { if (last_type_ != GetCurrentConnectionType()) { NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange(); last_type_ = GetCurrentConnectionType(); double max_bandwidth_mbps = NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype( last_type_ == CONNECTION_NONE ? SUBTYPE_NONE : SUBTYPE_UNKNOWN); NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChange( max_bandwidth_mbps, last_type_); } } NetworkChangeNotifierLinux::NetworkChangeNotifierLinux( const std::unordered_set& ignored_interfaces) : NetworkChangeNotifier(NetworkChangeCalculatorParamsLinux()), notifier_thread_(new Thread(ignored_interfaces)) { // We create this notifier thread because the notification implementation // needs a MessageLoopForIO, and there's no guarantee that // MessageLoop::current() meets that criterion. base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0); notifier_thread_->StartWithOptions(thread_options); } NetworkChangeNotifierLinux::~NetworkChangeNotifierLinux() { // Stopping from here allows us to sanity- check that the notifier // thread shut down properly. notifier_thread_->Stop(); } // static NetworkChangeNotifier::NetworkChangeCalculatorParams NetworkChangeNotifierLinux::NetworkChangeCalculatorParamsLinux() { NetworkChangeCalculatorParams params; // Delay values arrived at by simple experimentation and adjusted so as to // produce a single signal when switching between network connections. params.ip_address_offline_delay_ = base::TimeDelta::FromMilliseconds(2000); params.ip_address_online_delay_ = base::TimeDelta::FromMilliseconds(2000); params.connection_type_offline_delay_ = base::TimeDelta::FromMilliseconds(1500); params.connection_type_online_delay_ = base::TimeDelta::FromMilliseconds(500); return params; } NetworkChangeNotifier::ConnectionType NetworkChangeNotifierLinux::GetCurrentConnectionType() const { return notifier_thread_->GetCurrentConnectionType(); } const internal::AddressTrackerLinux* NetworkChangeNotifierLinux::GetAddressTrackerInternal() const { return notifier_thread_->address_tracker(); } } // namespace net