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