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