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