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