1/* 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "NetworkStateNotifier.h" 28 29#include <SystemConfiguration/SystemConfiguration.h> 30 31 32namespace WebCore { 33 34static const double StateChangeTimerInterval = 2.0; 35 36void NetworkStateNotifier::updateState() 37{ 38 // Assume that we're offline until proven otherwise. 39 m_isOnLine = false; 40 41 RetainPtr<CFStringRef> str = adoptCF(SCDynamicStoreKeyCreateNetworkInterface(0, kSCDynamicStoreDomainState)); 42 43 RetainPtr<CFPropertyListRef> propertyList = adoptCF(SCDynamicStoreCopyValue(m_store.get(), str.get())); 44 45 if (!propertyList) 46 return; 47 48 if (CFGetTypeID(propertyList.get()) != CFDictionaryGetTypeID()) 49 return; 50 51 CFArrayRef netInterfaces = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)propertyList.get(), kSCDynamicStorePropNetInterfaces); 52 if (CFGetTypeID(netInterfaces) != CFArrayGetTypeID()) 53 return; 54 55 for (CFIndex i = 0; i < CFArrayGetCount(netInterfaces); i++) { 56 CFStringRef interface = (CFStringRef)CFArrayGetValueAtIndex(netInterfaces, i); 57 if (CFGetTypeID(interface) != CFStringGetTypeID()) 58 continue; 59 60 // Ignore the loopback interface. 61 if (CFStringFind(interface, CFSTR("lo"), kCFCompareAnchored).location != kCFNotFound) 62 continue; 63 64 RetainPtr<CFStringRef> key = adoptCF(SCDynamicStoreKeyCreateNetworkInterfaceEntity(0, kSCDynamicStoreDomainState, interface, kSCEntNetIPv4)); 65 66 RetainPtr<CFArrayRef> keyList = adoptCF(SCDynamicStoreCopyKeyList(m_store.get(), key.get())); 67 68 if (keyList && CFArrayGetCount(keyList.get())) { 69 m_isOnLine = true; 70 break; 71 } 72 } 73} 74 75void NetworkStateNotifier::dynamicStoreCallback(SCDynamicStoreRef, CFArrayRef, void* info) 76{ 77 NetworkStateNotifier* notifier = static_cast<NetworkStateNotifier*>(info); 78 79 // Calling updateState() could be expensive so we schedule a timer that will do it 80 // when things have cooled down. 81 notifier->m_networkStateChangeTimer.startOneShot(StateChangeTimerInterval); 82} 83 84void NetworkStateNotifier::networkStateChangeTimerFired(Timer<NetworkStateNotifier>*) 85{ 86 bool oldOnLine = m_isOnLine; 87 88 updateState(); 89 90 if (m_isOnLine == oldOnLine) 91 return; 92 93 if (m_networkStateChangedFunction) 94 m_networkStateChangedFunction(); 95} 96 97NetworkStateNotifier::NetworkStateNotifier() 98 : m_isOnLine(false) 99 , m_networkStateChangedFunction(0) 100 , m_networkStateChangeTimer(this, &NetworkStateNotifier::networkStateChangeTimerFired) 101{ 102 SCDynamicStoreContext context = { 0, this, 0, 0, 0 }; 103 104 m_store = adoptCF(SCDynamicStoreCreate(0, CFSTR("com.apple.WebCore"), dynamicStoreCallback, &context)); 105 if (!m_store) 106 return; 107 108 RetainPtr<CFRunLoopSourceRef> configSource = adoptCF(SCDynamicStoreCreateRunLoopSource(0, m_store.get(), 0)); 109 if (!configSource) 110 return; 111 112 CFRunLoopAddSource(CFRunLoopGetMain(), configSource.get(), kCFRunLoopCommonModes); 113 114 RetainPtr<CFMutableArrayRef> keys = adoptCF(CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks)); 115 RetainPtr<CFMutableArrayRef> patterns = adoptCF(CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks)); 116 117 RetainPtr<CFStringRef> key; 118 RetainPtr<CFStringRef> pattern; 119 120 key = adoptCF(SCDynamicStoreKeyCreateNetworkGlobalEntity(0, kSCDynamicStoreDomainState, kSCEntNetIPv4)); 121 CFArrayAppendValue(keys.get(), key.get()); 122 123 pattern = adoptCF(SCDynamicStoreKeyCreateNetworkInterfaceEntity(0, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4)); 124 CFArrayAppendValue(patterns.get(), pattern.get()); 125 126 key = adoptCF(SCDynamicStoreKeyCreateNetworkGlobalEntity(0, kSCDynamicStoreDomainState, kSCEntNetDNS)); 127 CFArrayAppendValue(keys.get(), key.get()); 128 129 SCDynamicStoreSetNotificationKeys(m_store.get(), keys.get(), patterns.get()); 130 131 updateState(); 132} 133 134} 135