xref: /aosp_15_r20/external/cronet/net/base/network_change_notifier_win.h (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 #ifndef NET_BASE_NETWORK_CHANGE_NOTIFIER_WIN_H_
6 #define NET_BASE_NETWORK_CHANGE_NOTIFIER_WIN_H_
7 
8 #include <windows.h>
9 
10 #include <netlistmgr.h>
11 #include <ocidl.h>
12 #include <wrl.h>
13 #include <wrl/client.h>
14 
15 #include <memory>
16 
17 #include "base/compiler_specific.h"
18 #include "base/functional/callback.h"
19 #include "base/memory/scoped_refptr.h"
20 #include "base/memory/weak_ptr.h"
21 #include "base/sequence_checker.h"
22 #include "base/thread_annotations.h"
23 #include "base/timer/timer.h"
24 #include "base/win/object_watcher.h"
25 #include "net/base/net_export.h"
26 #include "net/base/network_change_notifier.h"
27 
28 namespace base {
29 class SequencedTaskRunner;
30 }  // namespace base
31 
32 namespace net {
33 
34 class NetworkCostManagerEventSink;
35 
36 // NetworkChangeNotifierWin uses a SequenceChecker, as all its internal
37 // notification code must be called on the sequence it is created and destroyed
38 // on.  All the NetworkChangeNotifier methods it implements are threadsafe.
39 class NET_EXPORT_PRIVATE NetworkChangeNotifierWin
40     : public NetworkChangeNotifier,
41       public base::win::ObjectWatcher::Delegate {
42  public:
43   NetworkChangeNotifierWin();
44   NetworkChangeNotifierWin(const NetworkChangeNotifierWin&) = delete;
45   NetworkChangeNotifierWin& operator=(const NetworkChangeNotifierWin&) = delete;
46   ~NetworkChangeNotifierWin() override;
47 
48   // Begins listening for a single subsequent address change.  If it fails to
49   // start watching, it retries on a timer.  Must be called only once, on the
50   // sequence |this| was created on.  This cannot be called in the constructor,
51   // as WatchForAddressChangeInternal is mocked out in unit tests.
52   // TODO(mmenke): Consider making this function a part of the
53   //               NetworkChangeNotifier interface, so other subclasses can be
54   //               unit tested in similar fashion, as needed.
55   void WatchForAddressChange();
56 
57  protected:
58   // For unit tests only.
is_watching()59   bool is_watching() const { return is_watching_; }
set_is_watching(bool is_watching)60   void set_is_watching(bool is_watching) { is_watching_ = is_watching; }
sequential_failures()61   int sequential_failures() const { return sequential_failures_; }
62 
63  private:
64   friend class NetworkChangeNotifierWinTest;
65   friend class TestNetworkChangeNotifierWin;
66 
67   // NetworkChangeNotifier methods:
68   ConnectionCost GetCurrentConnectionCost() override;
69 
70   ConnectionType GetCurrentConnectionType() const override;
71 
72   // ObjectWatcher::Delegate methods:
73   // Must only be called on the sequence |this| was created on.
74   void OnObjectSignaled(HANDLE object) override;
75 
76   // Recompute the current connection type on newer versions of Windows (Win10
77   // Build 19041 and above).
78   static ConnectionType RecomputeCurrentConnectionTypeModern();
79 
80   // Does the actual work to determine the current connection type. This will
81   // call into RecomputeCurrentConnectionTypeModern on modern OS. It is not
82   // thread safe, see crbug.com/324913.
83   static ConnectionType RecomputeCurrentConnectionType();
84 
85   // Calls RecomputeCurrentConnectionTypeImpl on the DNS sequence and runs
86   // |reply_callback| with the type on the calling sequence.
87   virtual void RecomputeCurrentConnectionTypeOnBlockingSequence(
88       base::OnceCallback<void(ConnectionType)> reply_callback) const;
89 
90   void SetCurrentConnectionType(ConnectionType connection_type);
91 
92   // Notifies IP address change observers of a change immediately, and notifies
93   // network state change observers on a delay.  Must only be called on the
94   // sequence |this| was created on.
95   void NotifyObservers(ConnectionType connection_type);
96 
97   // Forwards connection type notifications to parent class.
98   void NotifyParentOfConnectionTypeChange();
99   void NotifyParentOfConnectionTypeChangeImpl(ConnectionType connection_type);
100 
101   // Tries to start listening for a single subsequent address change.  Returns
102   // false on failure.  The caller is responsible for updating |is_watching_|.
103   // Virtual for unit tests.  Must only be called on the sequence |this| was
104   // created on.
105   virtual bool WatchForAddressChangeInternal();
106 
107   static NetworkChangeCalculatorParams NetworkChangeCalculatorParamsWin();
108 
109   // Gets the current network connection cost (if possible) and caches it.
110   void InitializeConnectionCost();
111   // Does the work of initializing for thread safety.
112   bool InitializeConnectionCostOnce();
113   // Retrieves the current network connection cost from the OS's Cost Manager.
114   HRESULT UpdateConnectionCostFromCostManager();
115   // Converts the OS enum values to the enum values used in our code.
116   static ConnectionCost ConnectionCostFromNlmCost(NLM_CONNECTION_COST cost);
117   // Sets the cached network connection cost value.
118   void SetCurrentConnectionCost(ConnectionCost connection_cost);
119   // Callback method for the notification event sink.
120   void OnCostChanged();
121   // Tells this class that an observer was added and therefore this class needs
122   // to register for notifications.
123   void ConnectionCostObserverAdded() override;
124   // Since ConnectionCostObserverAdded() can be called on any thread and we
125   // don't want to do a bunch of work on an arbitrary thread, this method used
126   // to post task to do the work.
127   void OnConnectionCostObserverAdded();
128 
129   // All member variables may only be accessed on the sequence |this| was
130   // created on.
131 
132   // False when not currently watching for network change events.  This only
133   // happens on initialization and when WatchForAddressChangeInternal fails and
134   // there is a pending task to try again.  Needed for safe cleanup.
135   bool is_watching_ = false;
136 
137   base::win::ObjectWatcher addr_watcher_;
138   OVERLAPPED addr_overlapped_;
139 
140   base::OneShotTimer timer_;
141 
142   // Number of times WatchForAddressChange has failed in a row.
143   int sequential_failures_ = 0;
144 
145   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
146 
147   mutable base::Lock last_computed_connection_type_lock_;
148   ConnectionType last_computed_connection_type_;
149 
150   std::atomic<ConnectionCost> last_computed_connection_cost_ =
151       ConnectionCost::CONNECTION_COST_UNKNOWN;
152 
153   // Result of IsOffline() when NotifyObserversOfConnectionTypeChange()
154   // was last called.
155   bool last_announced_offline_;
156   // Number of times polled to check if still offline.
157   int offline_polls_;
158 
159   Microsoft::WRL::ComPtr<INetworkCostManager> network_cost_manager_;
160   Microsoft::WRL::ComPtr<NetworkCostManagerEventSink>
161       network_cost_manager_event_sink_;
162 
163   // Used to ensure that all registration actions are properly sequenced on the
164   // same thread regardless of which thread was used to call into the
165   // NetworkChangeNotifier API.
166   scoped_refptr<base::SequencedTaskRunner> sequence_runner_for_registration_;
167 
168   SEQUENCE_CHECKER(sequence_checker_);
169 
170   // Used for calling WatchForAddressChange again on failure.
171   base::WeakPtrFactory<NetworkChangeNotifierWin> weak_factory_{this};
172 };
173 
174 }  // namespace net
175 
176 #endif  // NET_BASE_NETWORK_CHANGE_NOTIFIER_WIN_H_
177