Home | History | Annotate | Download | only in base
      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:
     57     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:
     73     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:
     87     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:
    124     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