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