xref: /aosp_15_r20/external/cronet/net/base/network_change_notifier_linux.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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/base/network_change_notifier_linux.h"
6 
7 #include <string>
8 
9 #include "base/compiler_specific.h"
10 #include "base/functional/bind.h"
11 #include "base/functional/callback_helpers.h"
12 #include "base/task/sequenced_task_runner.h"
13 #include "base/task/task_traits.h"
14 #include "base/task/thread_pool.h"
15 #include "base/threading/thread.h"
16 #include "net/base/address_tracker_linux.h"
17 #include "net/dns/dns_config_service_posix.h"
18 
19 namespace net {
20 
21 // A collection of objects that live on blocking threads.
22 class NetworkChangeNotifierLinux::BlockingThreadObjects {
23  public:
24   explicit BlockingThreadObjects(
25       const std::unordered_set<std::string>& ignored_interfaces,
26       scoped_refptr<base::SequencedTaskRunner> blocking_thread_runner);
27   BlockingThreadObjects(const BlockingThreadObjects&) = delete;
28   BlockingThreadObjects& operator=(const BlockingThreadObjects&) = delete;
29 
30   // Plumbing for NetworkChangeNotifier::GetCurrentConnectionType.
31   // Safe to call from any thread.
GetCurrentConnectionType()32   NetworkChangeNotifier::ConnectionType GetCurrentConnectionType() {
33     return address_tracker_.GetCurrentConnectionType();
34   }
35 
address_tracker()36   internal::AddressTrackerLinux* address_tracker() { return &address_tracker_; }
37 
38   // Begin watching for netlink changes.
39   void Init();
40 
41   void InitForTesting(base::ScopedFD netlink_fd);  // IN-TEST
42 
43  private:
44   void OnIPAddressChanged();
45   void OnLinkChanged();
46   // Used to detect online/offline state and IP address changes.
47   internal::AddressTrackerLinux address_tracker_;
48   NetworkChangeNotifier::ConnectionType last_type_ =
49       NetworkChangeNotifier::CONNECTION_NONE;
50 };
51 
BlockingThreadObjects(const std::unordered_set<std::string> & ignored_interfaces,scoped_refptr<base::SequencedTaskRunner> blocking_thread_runner)52 NetworkChangeNotifierLinux::BlockingThreadObjects::BlockingThreadObjects(
53     const std::unordered_set<std::string>& ignored_interfaces,
54     scoped_refptr<base::SequencedTaskRunner> blocking_thread_runner)
55     : address_tracker_(
56           base::BindRepeating(&NetworkChangeNotifierLinux::
57                                   BlockingThreadObjects::OnIPAddressChanged,
58                               base::Unretained(this)),
59           base::BindRepeating(
60               &NetworkChangeNotifierLinux::BlockingThreadObjects::OnLinkChanged,
61               base::Unretained(this)),
62           base::DoNothing(),
63           ignored_interfaces,
64           std::move(blocking_thread_runner)) {}
65 
Init()66 void NetworkChangeNotifierLinux::BlockingThreadObjects::Init() {
67   address_tracker_.Init();
68   last_type_ = GetCurrentConnectionType();
69 }
70 
InitForTesting(base::ScopedFD netlink_fd)71 void NetworkChangeNotifierLinux::BlockingThreadObjects::InitForTesting(
72     base::ScopedFD netlink_fd) {
73   address_tracker_.InitWithFdForTesting(std::move(netlink_fd));  // IN-TEST
74   last_type_ = GetCurrentConnectionType();
75 }
76 
OnIPAddressChanged()77 void NetworkChangeNotifierLinux::BlockingThreadObjects::OnIPAddressChanged() {
78   NetworkChangeNotifier::NotifyObserversOfIPAddressChange();
79   // When the IP address of a network interface is added/deleted, the
80   // connection type may have changed.
81   OnLinkChanged();
82 }
83 
OnLinkChanged()84 void NetworkChangeNotifierLinux::BlockingThreadObjects::OnLinkChanged() {
85   if (last_type_ != GetCurrentConnectionType()) {
86     NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange();
87     last_type_ = GetCurrentConnectionType();
88     double max_bandwidth_mbps =
89         NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype(
90             last_type_ == CONNECTION_NONE ? SUBTYPE_NONE : SUBTYPE_UNKNOWN);
91     NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChange(
92         max_bandwidth_mbps, last_type_);
93   }
94 }
95 
96 // static
97 std::unique_ptr<NetworkChangeNotifierLinux>
CreateWithSocketForTesting(const std::unordered_set<std::string> & ignored_interfaces,base::ScopedFD netlink_fd)98 NetworkChangeNotifierLinux::CreateWithSocketForTesting(
99     const std::unordered_set<std::string>& ignored_interfaces,
100     base::ScopedFD netlink_fd) {
101   auto ncn_linux = std::make_unique<NetworkChangeNotifierLinux>(
102       ignored_interfaces, /*initialize_blocking_thread_objects=*/false,
103       base::PassKey<NetworkChangeNotifierLinux>());
104   ncn_linux->InitBlockingThreadObjectsForTesting(  // IN-TEST
105       std::move(netlink_fd));
106   return ncn_linux;
107 }
108 
NetworkChangeNotifierLinux(const std::unordered_set<std::string> & ignored_interfaces)109 NetworkChangeNotifierLinux::NetworkChangeNotifierLinux(
110     const std::unordered_set<std::string>& ignored_interfaces)
111     : NetworkChangeNotifierLinux(ignored_interfaces,
112                                  /*initialize_blocking_thread_objects*/ true,
113                                  base::PassKey<NetworkChangeNotifierLinux>()) {}
114 
NetworkChangeNotifierLinux(const std::unordered_set<std::string> & ignored_interfaces,bool initialize_blocking_thread_objects,base::PassKey<NetworkChangeNotifierLinux>)115 NetworkChangeNotifierLinux::NetworkChangeNotifierLinux(
116     const std::unordered_set<std::string>& ignored_interfaces,
117     bool initialize_blocking_thread_objects,
118     base::PassKey<NetworkChangeNotifierLinux>)
119     : NetworkChangeNotifier(NetworkChangeCalculatorParamsLinux()),
120       blocking_thread_runner_(
121           base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})),
122       blocking_thread_objects_(
123           new BlockingThreadObjects(ignored_interfaces,
124                                     blocking_thread_runner_),
125           // Ensure |blocking_thread_objects_| lives on
126           // |blocking_thread_runner_| to prevent races where
127           // NetworkChangeNotifierLinux outlives
128           // TaskEnvironment. https://crbug.com/938126
129           base::OnTaskRunnerDeleter(blocking_thread_runner_)) {
130   if (initialize_blocking_thread_objects) {
131     blocking_thread_runner_->PostTask(
132         FROM_HERE,
133         base::BindOnce(&NetworkChangeNotifierLinux::BlockingThreadObjects::Init,
134                        // The Unretained pointer is safe here because it's
135                        // posted before the deleter can post.
136                        base::Unretained(blocking_thread_objects_.get())));
137   }
138 }
139 
~NetworkChangeNotifierLinux()140 NetworkChangeNotifierLinux::~NetworkChangeNotifierLinux() {
141   ClearGlobalPointer();
142 }
143 
144 // static
145 NetworkChangeNotifier::NetworkChangeCalculatorParams
NetworkChangeCalculatorParamsLinux()146 NetworkChangeNotifierLinux::NetworkChangeCalculatorParamsLinux() {
147   NetworkChangeCalculatorParams params;
148   // Delay values arrived at by simple experimentation and adjusted so as to
149   // produce a single signal when switching between network connections.
150   params.ip_address_offline_delay_ = base::Milliseconds(2000);
151   params.ip_address_online_delay_ = base::Milliseconds(2000);
152   params.connection_type_offline_delay_ = base::Milliseconds(1500);
153   params.connection_type_online_delay_ = base::Milliseconds(500);
154   return params;
155 }
156 
InitBlockingThreadObjectsForTesting(base::ScopedFD netlink_fd)157 void NetworkChangeNotifierLinux::InitBlockingThreadObjectsForTesting(
158     base::ScopedFD netlink_fd) {
159   DCHECK(blocking_thread_objects_);
160   blocking_thread_runner_->PostTask(
161       FROM_HERE,
162       base::BindOnce(
163           &NetworkChangeNotifierLinux::BlockingThreadObjects::InitForTesting,
164           // The Unretained pointer is safe here because it's
165           // posted before the deleter can post.
166           base::Unretained(blocking_thread_objects_.get()),
167           std::move(netlink_fd)));
168 }
169 
170 NetworkChangeNotifier::ConnectionType
GetCurrentConnectionType() const171 NetworkChangeNotifierLinux::GetCurrentConnectionType() const {
172   return blocking_thread_objects_->GetCurrentConnectionType();
173 }
174 
GetAddressMapOwnerInternal()175 AddressMapOwnerLinux* NetworkChangeNotifierLinux::GetAddressMapOwnerInternal() {
176   return blocking_thread_objects_->address_tracker();
177 }
178 
179 }  // namespace net
180