15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/network_change_notifier_mac.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netinet/in.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <resolv.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_config_service.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool CalculateReachability(SCNetworkConnectionFlags flags) { 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool reachable = flags & kSCNetworkFlagsReachable; 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool connection_required = flags & kSCNetworkFlagsConnectionRequired; 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return reachable && !connection_required; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkChangeNotifier::ConnectionType CalculateConnectionType( 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCNetworkConnectionFlags flags) { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool reachable = CalculateReachability(flags); 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (reachable) { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_IOS) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetworkChangeNotifier::CONNECTION_3G : 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetworkChangeNotifier::CONNECTION_WIFI; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(droger): Get something more detailed than CONNECTION_UNKNOWN. 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://crbug.com/112937 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NetworkChangeNotifier::CONNECTION_UNKNOWN; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(OS_IOS) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NetworkChangeNotifier::CONNECTION_NONE; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Thread on which we can run DnsConfigService, which requires a TYPE_IO 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// message loop. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NetworkChangeNotifierMac::DnsConfigServiceThread : public base::Thread { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DnsConfigServiceThread() : base::Thread("DnsConfigService") {} 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~DnsConfigServiceThread() { 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Stop(); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Init() OVERRIDE { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) service_ = DnsConfigService::CreateSystemService(); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) service_->WatchConfig(base::Bind(&NetworkChangeNotifier::SetDnsConfig)); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void CleanUp() OVERRIDE { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) service_.reset(); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DnsConfigService> service_; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DnsConfigServiceThread); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkChangeNotifierMac::NetworkChangeNotifierMac() 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : NetworkChangeNotifier(NetworkChangeCalculatorParamsMac()), 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) connection_type_(CONNECTION_UNKNOWN), 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) connection_type_initialized_(false), 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) initial_connection_type_cv_(&connection_type_lock_), 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) forwarder_(this), 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dns_config_service_thread_(new DnsConfigServiceThread()) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Must be initialized after the rest of this object, as it may call back into 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SetInitialConnectionType(). 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) config_watcher_.reset(new NetworkConfigWatcherMac(&forwarder_)); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dns_config_service_thread_->StartWithOptions( 7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkChangeNotifierMac::~NetworkChangeNotifierMac() { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Delete the ConfigWatcher to join the notifier thread, ensuring that 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // StartReachabilityNotifications() has an opportunity to run to completion. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) config_watcher_.reset(); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now that StartReachabilityNotifications() has either run to completion or 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // never run at all, unschedule reachability_ if it was previously scheduled. 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (reachability_.get() && run_loop_.get()) { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCNetworkReachabilityUnscheduleFromRunLoop(reachability_.get(), 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run_loop_.get(), 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCFRunLoopCommonModes); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NetworkChangeNotifier::NetworkChangeCalculatorParams 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NetworkChangeNotifierMac::NetworkChangeCalculatorParamsMac() { 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NetworkChangeCalculatorParams params; 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Delay values arrived at by simple experimentation and adjusted so as to 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // produce a single signal when switching between network connections. 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) params.ip_address_offline_delay_ = base::TimeDelta::FromMilliseconds(500); 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) params.ip_address_online_delay_ = base::TimeDelta::FromMilliseconds(500); 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) params.connection_type_offline_delay_ = 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TimeDelta::FromMilliseconds(1000); 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) params.connection_type_online_delay_ = base::TimeDelta::FromMilliseconds(500); 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return params; 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkChangeNotifier::ConnectionType 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkChangeNotifierMac::GetCurrentConnectionType() const { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock lock(connection_type_lock_); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure the initial connection type is set before returning. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (!connection_type_initialized_) { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) initial_connection_type_cv_.Wait(); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return connection_type_; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkChangeNotifierMac::Forwarder::Init() { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_config_watcher_->SetInitialConnectionType(); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkChangeNotifierMac::Forwarder::StartReachabilityNotifications() { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_config_watcher_->StartReachabilityNotifications(); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkChangeNotifierMac::Forwarder::SetDynamicStoreNotificationKeys( 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCDynamicStoreRef store) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_config_watcher_->SetDynamicStoreNotificationKeys(store); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkChangeNotifierMac::Forwarder::OnNetworkConfigChange( 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFArrayRef changed_keys) { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_config_watcher_->OnNetworkConfigChange(changed_keys); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkChangeNotifierMac::SetInitialConnectionType() { 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Called on notifier thread. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try to reach 0.0.0.0. This is the approach taken by Firefox: 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://mxr.mozilla.org/mozilla2.0/source/netwerk/system/mac/nsNetworkLinkService.mm 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // From my (adamk) testing on Snow Leopard, 0.0.0.0 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // seems to be reachable if any network connection is available. 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct sockaddr_in addr = {0}; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addr.sin_len = sizeof(addr); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addr.sin_family = AF_INET; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reachability_.reset(SCNetworkReachabilityCreateWithAddress( 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCFAllocatorDefault, reinterpret_cast<struct sockaddr*>(&addr))); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCNetworkConnectionFlags flags; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConnectionType connection_type = CONNECTION_UNKNOWN; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SCNetworkReachabilityGetFlags(reachability_, &flags)) { 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) connection_type = CalculateConnectionType(flags); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Could not get initial network connection type," 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "assuming online."; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock lock(connection_type_lock_); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) connection_type_ = connection_type; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) connection_type_initialized_ = true; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) initial_connection_type_cv_.Signal(); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkChangeNotifierMac::StartReachabilityNotifications() { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Called on notifier thread. 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run_loop_.reset(CFRunLoopGetCurrent()); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFRetain(run_loop_.get()); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(reachability_); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCNetworkReachabilityContext reachability_context = { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, // version 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, // user data 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, // retain 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, // release 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL // description 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!SCNetworkReachabilitySetCallback( 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reachability_, 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &NetworkChangeNotifierMac::ReachabilityCallback, 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &reachability_context)) { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(DFATAL) << "Could not set network reachability callback"; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reachability_.reset(); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!SCNetworkReachabilityScheduleWithRunLoop(reachability_, 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) run_loop_, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCFRunLoopCommonModes)) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(DFATAL) << "Could not schedule network reachability on run loop"; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reachability_.reset(); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkChangeNotifierMac::SetDynamicStoreNotificationKeys( 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCDynamicStoreRef store) { 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_IOS) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SCDynamicStore API does not exist on iOS. 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CFMutableArrayRef> notification_keys( 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); 201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CFStringRef> key( 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCDynamicStoreKeyCreateNetworkGlobalEntity( 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, kSCDynamicStoreDomainState, kSCEntNetInterface)); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFArrayAppendValue(notification_keys.get(), key.get()); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity( 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4)); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFArrayAppendValue(notification_keys.get(), key.get()); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity( 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6)); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFArrayAppendValue(notification_keys.get(), key.get()); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the notification keys. This starts us receiving notifications. 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ret = SCDynamicStoreSetNotificationKeys( 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store, notification_keys.get(), NULL); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(willchan): Figure out a proper way to handle this rather than crash. 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(ret); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(OS_IOS) 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkChangeNotifierMac::OnNetworkConfigChange(CFArrayRef changed_keys) { 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_IOS) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SCDynamicStore API does not exist on iOS. 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(run_loop_.get(), CFRunLoopGetCurrent()); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CFIndex i = 0; i < CFArrayGetCount(changed_keys); ++i) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFStringRef key = static_cast<CFStringRef>( 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFArrayGetValueAtIndex(changed_keys, i)); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CFStringHasSuffix(key, kSCEntNetIPv4) || 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFStringHasSuffix(key, kSCEntNetIPv6)) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NotifyObserversOfIPAddressChange(); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CFStringHasSuffix(key, kSCEntNetInterface)) { 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(willchan): Does not appear to be working. Look into this. 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Perhaps this isn't needed anyway. 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(OS_IOS) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkChangeNotifierMac::ReachabilityCallback( 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCNetworkReachabilityRef target, 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCNetworkConnectionFlags flags, 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* notifier) { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetworkChangeNotifierMac* notifier_mac = 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<NetworkChangeNotifierMac*>(notifier); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(notifier_mac->run_loop_.get(), CFRunLoopGetCurrent()); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConnectionType new_type = CalculateConnectionType(flags); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConnectionType old_type; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock lock(notifier_mac->connection_type_lock_); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_type = notifier_mac->connection_type_; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notifier_mac->connection_type_ = new_type; 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (old_type != new_type) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NotifyObserversOfConnectionTypeChange(); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_IOS) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On iOS, the SCDynamicStore API does not exist, and we use the reachability 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // API to detect IP address changes instead. 268c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch NotifyObserversOfIPAddressChange(); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(OS_IOS) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 273