1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 <memory>
11 
12 #include "base/callback.h"
13 #include "base/compiler_specific.h"
14 #include "base/memory/scoped_refptr.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/sequence_checker.h"
17 #include "base/timer/timer.h"
18 #include "base/win/object_watcher.h"
19 #include "net/base/net_export.h"
20 #include "net/base/network_change_notifier.h"
21 
22 namespace base {
23 class SequencedTaskRunner;
24 }  // namespace base
25 
26 namespace net {
27 
28 // NetworkChangeNotifierWin uses a SequenceChecker, as all its internal
29 // notification code must be called on the sequence it is created and destroyed
30 // on.  All the NetworkChangeNotifier methods it implements are threadsafe.
31 class NET_EXPORT_PRIVATE NetworkChangeNotifierWin
32     : public NetworkChangeNotifier,
33       public base::win::ObjectWatcher::Delegate {
34  public:
35   NetworkChangeNotifierWin();
36   NetworkChangeNotifierWin(const NetworkChangeNotifierWin&) = delete;
37   NetworkChangeNotifierWin& operator=(const NetworkChangeNotifierWin&) = delete;
38   ~NetworkChangeNotifierWin() override;
39 
40   // Begins listening for a single subsequent address change.  If it fails to
41   // start watching, it retries on a timer.  Must be called only once, on the
42   // sequence |this| was created on.  This cannot be called in the constructor,
43   // as WatchForAddressChangeInternal is mocked out in unit tests.
44   // TODO(mmenke): Consider making this function a part of the
45   //               NetworkChangeNotifier interface, so other subclasses can be
46   //               unit tested in similar fashion, as needed.
47   void WatchForAddressChange();
48 
49  protected:
50   // For unit tests only.
is_watching()51   bool is_watching() const { return is_watching_; }
set_is_watching(bool is_watching)52   void set_is_watching(bool is_watching) { is_watching_ = is_watching; }
sequential_failures()53   int sequential_failures() const { return sequential_failures_; }
54 
55  private:
56   friend class NetworkChangeNotifierWinTest;
57   friend class TestNetworkChangeNotifierWin;
58 
59   // NetworkChangeNotifier methods:
60   ConnectionType GetCurrentConnectionType() const override;
61 
62   // ObjectWatcher::Delegate methods:
63   // Must only be called on the sequence |this| was created on.
64   void OnObjectSignaled(HANDLE object) override;
65 
66   // Does the actual work to determine the current connection type.
67   // It is not thread safe, see crbug.com/324913.
68   static ConnectionType RecomputeCurrentConnectionType();
69 
70   // Calls RecomputeCurrentConnectionTypeImpl on the DNS sequence and runs
71   // |reply_callback| with the type on the calling sequence.
72   virtual void RecomputeCurrentConnectionTypeOnBlockingSequence(
73       base::OnceCallback<void(ConnectionType)> reply_callback) const;
74 
75   void SetCurrentConnectionType(ConnectionType connection_type);
76 
77   // Notifies IP address change observers of a change immediately, and notifies
78   // network state change observers on a delay.  Must only be called on the
79   // sequence |this| was created on.
80   void NotifyObservers(ConnectionType connection_type);
81 
82   // Forwards connection type notifications to parent class.
83   void NotifyParentOfConnectionTypeChange();
84   void NotifyParentOfConnectionTypeChangeImpl(ConnectionType connection_type);
85 
86   // Tries to start listening for a single subsequent address change.  Returns
87   // false on failure.  The caller is responsible for updating |is_watching_|.
88   // Virtual for unit tests.  Must only be called on the sequence |this| was
89   // created on.
90   virtual bool WatchForAddressChangeInternal();
91 
92   static NetworkChangeCalculatorParams NetworkChangeCalculatorParamsWin();
93 
94   // All member variables may only be accessed on the sequence |this| was
95   // created on.
96 
97   // False when not currently watching for network change events.  This only
98   // happens on initialization and when WatchForAddressChangeInternal fails and
99   // there is a pending task to try again.  Needed for safe cleanup.
100   bool is_watching_ = false;
101 
102   base::win::ObjectWatcher addr_watcher_;
103   OVERLAPPED addr_overlapped_;
104 
105   base::OneShotTimer timer_;
106 
107   // Number of times WatchForAddressChange has failed in a row.
108   int sequential_failures_ = 0;
109 
110   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
111 
112   mutable base::Lock last_computed_connection_type_lock_;
113   ConnectionType last_computed_connection_type_;
114 
115   // Result of IsOffline() when NotifyObserversOfConnectionTypeChange()
116   // was last called.
117   bool last_announced_offline_;
118   // Number of times polled to check if still offline.
119   int offline_polls_;
120 
121   SEQUENCE_CHECKER(sequence_checker_);
122 
123   // Used for calling WatchForAddressChange again on failure.
124   base::WeakPtrFactory<NetworkChangeNotifierWin> weak_factory_{this};
125 };
126 
127 }  // namespace net
128 
129 #endif  // NET_BASE_NETWORK_CHANGE_NOTIFIER_WIN_H_
130