• 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   // Does the actual work to determine the current connection type.
76   // It is not thread safe, see crbug.com/324913.
77   static ConnectionType RecomputeCurrentConnectionType();
78 
79   // Calls RecomputeCurrentConnectionTypeImpl on the DNS sequence and runs
80   // |reply_callback| with the type on the calling sequence.
81   virtual void RecomputeCurrentConnectionTypeOnBlockingSequence(
82       base::OnceCallback<void(ConnectionType)> reply_callback) const;
83 
84   void SetCurrentConnectionType(ConnectionType connection_type);
85 
86   // Notifies IP address change observers of a change immediately, and notifies
87   // network state change observers on a delay.  Must only be called on the
88   // sequence |this| was created on.
89   void NotifyObservers(ConnectionType connection_type);
90 
91   // Forwards connection type notifications to parent class.
92   void NotifyParentOfConnectionTypeChange();
93   void NotifyParentOfConnectionTypeChangeImpl(ConnectionType connection_type);
94 
95   // Tries to start listening for a single subsequent address change.  Returns
96   // false on failure.  The caller is responsible for updating |is_watching_|.
97   // Virtual for unit tests.  Must only be called on the sequence |this| was
98   // created on.
99   virtual bool WatchForAddressChangeInternal();
100 
101   static NetworkChangeCalculatorParams NetworkChangeCalculatorParamsWin();
102 
103   // Gets the current network connection cost (if possible) and caches it.
104   void InitializeConnectionCost();
105   // Does the work of initializing for thread safety.
106   bool InitializeConnectionCostOnce();
107   // Retrieves the current network connection cost from the OS's Cost Manager.
108   HRESULT UpdateConnectionCostFromCostManager();
109   // Converts the OS enum values to the enum values used in our code.
110   static ConnectionCost ConnectionCostFromNlmCost(NLM_CONNECTION_COST cost);
111   // Sets the cached network connection cost value.
112   void SetCurrentConnectionCost(ConnectionCost connection_cost);
113   // Callback method for the notification event sink.
114   void OnCostChanged();
115   // Tells this class that an observer was added and therefore this class needs
116   // to register for notifications.
117   void ConnectionCostObserverAdded() override;
118   // Since ConnectionCostObserverAdded() can be called on any thread and we
119   // don't want to do a bunch of work on an arbitrary thread, this method used
120   // to post task to do the work.
121   void OnConnectionCostObserverAdded();
122 
123   // All member variables may only be accessed on the sequence |this| was
124   // created on.
125 
126   // False when not currently watching for network change events.  This only
127   // happens on initialization and when WatchForAddressChangeInternal fails and
128   // there is a pending task to try again.  Needed for safe cleanup.
129   bool is_watching_ = false;
130 
131   base::win::ObjectWatcher addr_watcher_;
132   OVERLAPPED addr_overlapped_;
133 
134   base::OneShotTimer timer_;
135 
136   // Number of times WatchForAddressChange has failed in a row.
137   int sequential_failures_ = 0;
138 
139   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
140 
141   mutable base::Lock last_computed_connection_type_lock_;
142   ConnectionType last_computed_connection_type_;
143 
144   std::atomic<ConnectionCost> last_computed_connection_cost_ =
145       ConnectionCost::CONNECTION_COST_UNKNOWN;
146 
147   // Result of IsOffline() when NotifyObserversOfConnectionTypeChange()
148   // was last called.
149   bool last_announced_offline_;
150   // Number of times polled to check if still offline.
151   int offline_polls_;
152 
153   Microsoft::WRL::ComPtr<INetworkCostManager> network_cost_manager_;
154   Microsoft::WRL::ComPtr<NetworkCostManagerEventSink>
155       network_cost_manager_event_sink_;
156 
157   // Used to ensure that all registration actions are properly sequenced on the
158   // same thread regardless of which thread was used to call into the
159   // NetworkChangeNotifier API.
160   scoped_refptr<base::SequencedTaskRunner> sequence_runner_for_registration_;
161 
162   SEQUENCE_CHECKER(sequence_checker_);
163 
164   // Used for calling WatchForAddressChange again on failure.
165   base::WeakPtrFactory<NetworkChangeNotifierWin> weak_factory_{this};
166 };
167 
168 }  // namespace net
169 
170 #endif  // NET_BASE_NETWORK_CHANGE_NOTIFIER_WIN_H_
171