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