|  | // 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/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<std::string>& 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<DnsConfigService> dns_config_service_; | 
|  | // Used to detect online/offline state and IP address changes. | 
|  | std::unique_ptr<internal::AddressTrackerLinux> address_tracker_; | 
|  | NetworkChangeNotifier::ConnectionType last_type_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(Thread); | 
|  | }; | 
|  |  | 
|  | NetworkChangeNotifierLinux::Thread::Thread( | 
|  | const std::unordered_set<std::string>& 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::GetMaxBandwidthForConnectionSubtype( | 
|  | last_type_ == CONNECTION_NONE ? SUBTYPE_NONE : SUBTYPE_UNKNOWN); | 
|  | NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChange( | 
|  | max_bandwidth_mbps, last_type_); | 
|  | } | 
|  | } | 
|  |  | 
|  | NetworkChangeNotifierLinux::NetworkChangeNotifierLinux( | 
|  | const std::unordered_set<std::string>& 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 |