• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_H_
6 #define NET_BASE_NETWORK_CHANGE_NOTIFIER_H_
7 
8 #include "base/basictypes.h"
9 #include "base/observer_list_threadsafe.h"
10 #include "base/time/time.h"
11 #include "net/base/net_export.h"
12 
13 class GURL;
14 
15 namespace net {
16 
17 struct DnsConfig;
18 class HistogramWatcher;
19 class NetworkChangeNotifierFactory;
20 class URLRequest;
21 
22 #if defined(OS_LINUX)
23 namespace internal {
24 class AddressTrackerLinux;
25 }
26 #endif
27 
28 // NetworkChangeNotifier monitors the system for network changes, and notifies
29 // registered observers of those events.  Observers may register on any thread,
30 // and will be called back on the thread from which they registered.
31 // NetworkChangeNotifiers are threadsafe, though they must be created and
32 // destroyed on the same thread.
33 class NET_EXPORT NetworkChangeNotifier {
34  public:
35   // This is a superset of the connection types in the NetInfo v3 specification:
36   // http://w3c.github.io/netinfo/.
37   enum ConnectionType {
38     CONNECTION_UNKNOWN = 0,  // A connection exists, but its type is unknown.
39                              // Also used as a default value.
40     CONNECTION_ETHERNET = 1,
41     CONNECTION_WIFI = 2,
42     CONNECTION_2G = 3,
43     CONNECTION_3G = 4,
44     CONNECTION_4G = 5,
45     CONNECTION_NONE = 6,     // No connection.
46     CONNECTION_BLUETOOTH = 7,
47     CONNECTION_LAST = CONNECTION_BLUETOOTH
48   };
49 
50   class NET_EXPORT IPAddressObserver {
51    public:
52     // Will be called when the IP address of the primary interface changes.
53     // This includes when the primary interface itself changes.
54     virtual void OnIPAddressChanged() = 0;
55 
56    protected:
IPAddressObserver()57     IPAddressObserver() {}
~IPAddressObserver()58     virtual ~IPAddressObserver() {}
59 
60    private:
61     DISALLOW_COPY_AND_ASSIGN(IPAddressObserver);
62   };
63 
64   class NET_EXPORT ConnectionTypeObserver {
65    public:
66     // Will be called when the connection type of the system has changed.
67     // See NetworkChangeNotifier::GetConnectionType() for important caveats
68     // about the unreliability of using this signal to infer the ability to
69     // reach remote sites.
70     virtual void OnConnectionTypeChanged(ConnectionType type) = 0;
71 
72    protected:
ConnectionTypeObserver()73     ConnectionTypeObserver() {}
~ConnectionTypeObserver()74     virtual ~ConnectionTypeObserver() {}
75 
76    private:
77     DISALLOW_COPY_AND_ASSIGN(ConnectionTypeObserver);
78   };
79 
80   class NET_EXPORT DNSObserver {
81    public:
82     // Will be called when the DNS settings of the system may have changed.
83     // Use GetDnsConfig to obtain the current settings.
84     virtual void OnDNSChanged() = 0;
85 
86    protected:
DNSObserver()87     DNSObserver() {}
~DNSObserver()88     virtual ~DNSObserver() {}
89 
90    private:
91     DISALLOW_COPY_AND_ASSIGN(DNSObserver);
92   };
93 
94   class NET_EXPORT NetworkChangeObserver {
95    public:
96     // OnNetworkChanged will be called when a change occurs to the host
97     // computer's hardware or software that affects the route network packets
98     // take to any network server. Some examples:
99     //   1. A network connection becoming available or going away. For example
100     //      plugging or unplugging an Ethernet cable, WiFi or cellular modem
101     //      connecting or disconnecting from a network, or a VPN tunnel being
102     //      established or taken down.
103     //   2. An active network connection's IP address changes.
104     //   3. A change to the local IP routing tables.
105     // The signal shall only be produced when the change is complete.  For
106     // example if a new network connection has become available, only give the
107     // signal once we think the O/S has finished establishing the connection
108     // (i.e. DHCP is done) to the point where the new connection is usable.
109     // The signal shall not be produced spuriously as it will be triggering some
110     // expensive operations, like socket pools closing all connections and
111     // sockets and then re-establishing them.
112     // |type| indicates the type of the active primary network connection after
113     // the change.  Observers performing "constructive" activities like trying
114     // to establish a connection to a server should only do so when
115     // |type != CONNECTION_NONE|.  Observers performing "destructive" activities
116     // like resetting already established server connections should only do so
117     // when |type == CONNECTION_NONE|.  OnNetworkChanged will always be called
118     // with CONNECTION_NONE immediately prior to being called with an online
119     // state; this is done to make sure that destructive actions take place
120     // prior to constructive actions.
121     virtual void OnNetworkChanged(ConnectionType type) = 0;
122 
123    protected:
NetworkChangeObserver()124     NetworkChangeObserver() {}
~NetworkChangeObserver()125     virtual ~NetworkChangeObserver() {}
126 
127    private:
128     DISALLOW_COPY_AND_ASSIGN(NetworkChangeObserver);
129   };
130 
131   virtual ~NetworkChangeNotifier();
132 
133   // See the description of NetworkChangeNotifier::GetConnectionType().
134   // Implementations must be thread-safe. Implementations must also be
135   // cheap as this could be called (repeatedly) from the network thread.
136   virtual ConnectionType GetCurrentConnectionType() const = 0;
137 
138   // Replaces the default class factory instance of NetworkChangeNotifier class.
139   // The method will take over the ownership of |factory| object.
140   static void SetFactory(NetworkChangeNotifierFactory* factory);
141 
142   // Creates the process-wide, platform-specific NetworkChangeNotifier.  The
143   // caller owns the returned pointer.  You may call this on any thread.  You
144   // may also avoid creating this entirely (in which case nothing will be
145   // monitored), but if you do create it, you must do so before any other
146   // threads try to access the API below, and it must outlive all other threads
147   // which might try to use it.
148   static NetworkChangeNotifier* Create();
149 
150   // Returns the connection type.
151   // A return value of |CONNECTION_NONE| is a pretty strong indicator that the
152   // user won't be able to connect to remote sites. However, another return
153   // value doesn't imply that the user will be able to connect to remote sites;
154   // even if some link is up, it is uncertain whether a particular connection
155   // attempt to a particular remote site will be successful.
156   // The returned value only describes the connection currently used by the
157   // device, and does not take into account other machines on the network. For
158   // example, if the device is connected using Wifi to a 3G gateway to access
159   // the internet, the connection type is CONNECTION_WIFI.
160   static ConnectionType GetConnectionType();
161 
162   // Retrieve the last read DnsConfig. This could be expensive if the system has
163   // a large HOSTS file.
164   static void GetDnsConfig(DnsConfig* config);
165 
166 #if defined(OS_LINUX)
167   // Returns the AddressTrackerLinux if present.
168   static const internal::AddressTrackerLinux* GetAddressTracker();
169 #endif
170 
171   // Convenience method to determine if the user is offline.
172   // Returns true if there is currently no internet connection.
173   //
174   // A return value of |true| is a pretty strong indicator that the user
175   // won't be able to connect to remote sites. However, a return value of
176   // |false| is inconclusive; even if some link is up, it is uncertain
177   // whether a particular connection attempt to a particular remote site
178   // will be successfully.
179   static bool IsOffline();
180 
181   // Returns true if |type| is a cellular connection.
182   // Returns false if |type| is CONNECTION_UNKNOWN, and thus, depending on the
183   // implementation of GetConnectionType(), it is possible that
184   // IsConnectionCellular(GetConnectionType()) returns false even if the
185   // current connection is cellular.
186   static bool IsConnectionCellular(ConnectionType type);
187 
188   // Like Create(), but for use in tests.  The mock object doesn't monitor any
189   // events, it merely rebroadcasts notifications when requested.
190   static NetworkChangeNotifier* CreateMock();
191 
192   // Registers |observer| to receive notifications of network changes.  The
193   // thread on which this is called is the thread on which |observer| will be
194   // called back with notifications.  This is safe to call if Create() has not
195   // been called (as long as it doesn't race the Create() call on another
196   // thread), in which case it will simply do nothing.
197   static void AddIPAddressObserver(IPAddressObserver* observer);
198   static void AddConnectionTypeObserver(ConnectionTypeObserver* observer);
199   static void AddDNSObserver(DNSObserver* observer);
200   static void AddNetworkChangeObserver(NetworkChangeObserver* observer);
201 
202   // Unregisters |observer| from receiving notifications.  This must be called
203   // on the same thread on which AddObserver() was called.  Like AddObserver(),
204   // this is safe to call if Create() has not been called (as long as it doesn't
205   // race the Create() call on another thread), in which case it will simply do
206   // nothing.  Technically, it's also safe to call after the notifier object has
207   // been destroyed, if the call doesn't race the notifier's destruction, but
208   // there's no reason to use the API in this risky way, so don't do it.
209   static void RemoveIPAddressObserver(IPAddressObserver* observer);
210   static void RemoveConnectionTypeObserver(ConnectionTypeObserver* observer);
211   static void RemoveDNSObserver(DNSObserver* observer);
212   static void RemoveNetworkChangeObserver(NetworkChangeObserver* observer);
213 
214   // Allow unit tests to trigger notifications.
215   static void NotifyObserversOfIPAddressChangeForTests();
216   static void NotifyObserversOfConnectionTypeChangeForTests(
217       ConnectionType type);
218   static void NotifyObserversOfNetworkChangeForTests(ConnectionType type);
219 
220   // Enable or disable notifications from the host. After setting to true, be
221   // sure to pump the RunLoop until idle to finish any preexisting
222   // notifications.
223   static void SetTestNotificationsOnly(bool test_only);
224 
225   // Return a string equivalent to |type|.
226   static const char* ConnectionTypeToString(ConnectionType type);
227 
228   // Let the NetworkChangeNotifier know we received some data.
229   // This is used for producing histogram data about the accuracy of
230   // the NetworkChangenotifier's online detection and rough network
231   // connection measurements.
232   static void NotifyDataReceived(const URLRequest& request, int bytes_read);
233 
234   // Register the Observer callbacks for producing histogram data.  This
235   // should be called from the network thread to avoid race conditions.
236   // ShutdownHistogramWatcher() must be called prior to NetworkChangeNotifier
237   // destruction.
238   static void InitHistogramWatcher();
239 
240   // Unregister the Observer callbacks for producing histogram data.  This
241   // should be called from the network thread to avoid race conditions.
242   static void ShutdownHistogramWatcher();
243 
244   // Log the |NCN.NetworkOperatorMCCMNC| histogram.
245   static void LogOperatorCodeHistogram(ConnectionType type);
246 
247   // Allows a second NetworkChangeNotifier to be created for unit testing, so
248   // the test suite can create a MockNetworkChangeNotifier, but platform
249   // specific NetworkChangeNotifiers can also be created for testing.  To use,
250   // create an DisableForTest object, and then create the new
251   // NetworkChangeNotifier object.  The NetworkChangeNotifier must be
252   // destroyed before the DisableForTest object, as its destruction will restore
253   // the original NetworkChangeNotifier.
254   class NET_EXPORT DisableForTest {
255    public:
256     DisableForTest();
257     ~DisableForTest();
258 
259    private:
260     // The original NetworkChangeNotifier to be restored on destruction.
261     NetworkChangeNotifier* network_change_notifier_;
262   };
263 
264  protected:
265   // NetworkChanged signal is calculated from the IPAddressChanged and
266   // ConnectionTypeChanged signals. Delay parameters control how long to delay
267   // producing NetworkChanged signal after particular input signals so as to
268   // combine duplicates.  In other words if an input signal is repeated within
269   // the corresponding delay period, only one resulting NetworkChange signal is
270   // produced.
271   struct NET_EXPORT NetworkChangeCalculatorParams {
272     NetworkChangeCalculatorParams();
273     // Controls delay after OnIPAddressChanged when transitioning from an
274     // offline state.
275     base::TimeDelta ip_address_offline_delay_;
276     // Controls delay after OnIPAddressChanged when transitioning from an
277     // online state.
278     base::TimeDelta ip_address_online_delay_;
279     // Controls delay after OnConnectionTypeChanged when transitioning from an
280     // offline state.
281     base::TimeDelta connection_type_offline_delay_;
282     // Controls delay after OnConnectionTypeChanged when transitioning from an
283     // online state.
284     base::TimeDelta connection_type_online_delay_;
285   };
286 
287   explicit NetworkChangeNotifier(
288       const NetworkChangeCalculatorParams& params =
289           NetworkChangeCalculatorParams());
290 
291 #if defined(OS_LINUX)
292   // Returns the AddressTrackerLinux if present.
293   // TODO(szym): Retrieve AddressMap from NetworkState. http://crbug.com/144212
294   virtual const internal::AddressTrackerLinux*
295       GetAddressTrackerInternal() const;
296 #endif
297 
298   // Broadcasts a notification to all registered observers.  Note that this
299   // happens asynchronously, even for observers on the current thread, even in
300   // tests.
301   static void NotifyObserversOfIPAddressChange();
302   static void NotifyObserversOfConnectionTypeChange();
303   static void NotifyObserversOfDNSChange();
304   static void NotifyObserversOfNetworkChange(ConnectionType type);
305 
306   // Stores |config| in NetworkState and notifies observers.
307   static void SetDnsConfig(const DnsConfig& config);
308 
309  private:
310   friend class HostResolverImplDnsTest;
311   friend class NetworkChangeNotifierAndroidTest;
312   friend class NetworkChangeNotifierLinuxTest;
313   friend class NetworkChangeNotifierWinTest;
314 
315   class NetworkState;
316   class NetworkChangeCalculator;
317 
318   void NotifyObserversOfIPAddressChangeImpl();
319   void NotifyObserversOfConnectionTypeChangeImpl(ConnectionType type);
320   void NotifyObserversOfDNSChangeImpl();
321   void NotifyObserversOfNetworkChangeImpl(ConnectionType type);
322 
323   const scoped_refptr<ObserverListThreadSafe<IPAddressObserver> >
324       ip_address_observer_list_;
325   const scoped_refptr<ObserverListThreadSafe<ConnectionTypeObserver> >
326       connection_type_observer_list_;
327   const scoped_refptr<ObserverListThreadSafe<DNSObserver> >
328       resolver_state_observer_list_;
329   const scoped_refptr<ObserverListThreadSafe<NetworkChangeObserver> >
330       network_change_observer_list_;
331 
332   // The current network state. Hosts DnsConfig, exposed via GetDnsConfig.
333   scoped_ptr<NetworkState> network_state_;
334 
335   // A little-piggy-back observer that simply logs UMA histogram data.
336   scoped_ptr<HistogramWatcher> histogram_watcher_;
337 
338   // Computes NetworkChange signal from IPAddress and ConnectionType signals.
339   scoped_ptr<NetworkChangeCalculator> network_change_calculator_;
340 
341   // Set true to disable non-test notifications (to prevent flakes in tests).
342   bool test_notifications_only_;
343 
344   DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifier);
345 };
346 
347 }  // namespace net
348 
349 #endif  // NET_BASE_NETWORK_CHANGE_NOTIFIER_H_
350